CONTENU

OPTIMISATION MAPS HALF-LIFE 2

Ce cours porte sur "comment optimiser sa map sous le moteur Source (Half-Life 2)"
Cette page dispose d'une feuille de style pour l'impression (afin de supprimer la mise en page du site).
Dernière mise à jour le 24/08/2013.

Ce cours a été entièrement écrit par moi, c'est à dire NykO18.
Pour me contacter, plusieurs moyens :

Si la page ne s'affiche pas correctement chez vous (résolution inférieure ou égale à 1024x768) cliquez ici.
Pardonnez-moi pour la lourdeur excessive de la page (4 MB !), mais les idées sont venues au fur et à mesure, et rien ne prédestinait ce tutorial à devenir aussi gros au départ. Laissez simplement la page se charger avant de commencer à lire.

Creative Commons License Cette création est mise à disposition
sous un contrat Creative Commons.

Plan


Introduction

Ce tutorial s'adresse à tous les gens qui vont se retrouver parmis les citations suivantes, toutes trouvées dans les forums de mapping-area :

RoBoT a dit :
Je fais acutellement une map sous hl2dm et lorsque je veux compiler ma map (BSP : en mode normal - VIS : en mode normal - RAD: en mode normal) la compilation plante... Je me souviens juste de quelques phrases:
Memory leak: mempool blocks left in memory: 48
Memory leak: mempool blocks left in memory: 11
Et cela plante sous Portal Flow: 0...1

brusnt a dit :
Bah voila, en fait je suis en train de faire ma map, et le temps de compilation (run map) était plutôt raisonable, moins d'une minute, mais là comme ça d'un coup, alors que je n'ai pas ajouté spécialement de polys, ni de jeux de lumière, c'est une demi-heure de calculs !

CN_Mapoleon1er a dit :
Je créé ma map sur Hammer et lorsque je veux la compiler (F9) le programme met un temps fou sur l'étape "Portal Flow" (il y a des petits chiffres qui s'affichent, séparés par des points, de cette manière : 1...2...3...) et l'affichage de chaque point/chiffre prend parfois plusieurs dizaines de secondes et donc la compilation ne se termine pas et freeze mon PC, ou alors parfois elle arrive au bout mais après 15 min !)

Nargzul a dit :
Voila, je viens de finir ma map, et je n'arrive jamais au bout de la compilation, a cause de quoi ça peut etre ? j'ai plus ou moins réussi à le réafficher en masquant toutes les autres fenêtres et il bloqué sur un traitement, un ...8.. dans le "vvis.exe" plus précisément au "portal flow"... j'ai redémarré steam, redémarré le pc, rien y fait...

mind a dit :
Voila j'ai un petit problème avec le vis, quand je joue dans ma map avec le "mat_wireframe 1" je peux voir qu'il calcul absolument tout en même temps et ça fais ramer vraiment énormément donc j'aurais voulu savoir si quelqu'un connait le problème sachant que je n'ai pas mis de hint ni d'occluder donc voila merci d'avance.

Neernitt a dit :
Voila j'ai un petit ennui avec ma map, le moteur calcule toute la map en permanance ce qui fait que ça rame vachement, et je voulais savoir si il y a un moyen pour que, par exemple, à une distance de 2000 pixels le niveau de détail diminue progressivement.

tuni a dit :
Bonjour a tout les mappeurs, j'aurais besoin d'aide pour optimiser ma map, elle se passe en extérieure avec une piscine au centre. Mon problème c'est une baisse des r_speed, alors y a-t-il des mappeurs de folie pour m'aider à arranger ça car j'ai entendu parler de hint, areaportal mais je ne sais pa m'en servir.

J'aurais pu en prendre encore beaucoup comme ça, mais après on va me dire que j'essaie de combler ce tutorial avec du n'importe quoi. (je précise que j'ai corrigé les fautes d'orthographe des posts ci-dessus :D)
Le but de ce tutorial est donc de vous expliquer les rudiments de l'optimisation sous Half-Life 2. Il est possible que certaines techniques fonctionnent sous Half-Life premier du nom, mais ce n'est pas l'objet de ce tutorial. Nous allons tout au long du tutorial commencer par la ou les sources du problème pour finalement en arriver à sa solution.. si tant est qu'elle existe bien entendu :D

Je met à votre disposition la map que j'ai créée pour ce tutorial. Elle contient quelque uns des exemples que j'expose ici ainsi que les techniques pour les hints, areaportals, areaportalwindows, occluders, func_detail et autres.. Si au moins cela peut servir à quelque chose... faites en bon usage.


I. La compilation

90% des gens qui se plaignent d'une compilation beaucoup trop longue à leur goût on des problèmes avec VIS. (les autres ont une mauvaise idée de ce qu'est une heure de compilation à part un temps normal) Seulement voilà, dans ces 90% de plaignants, seulement 10 ou 20% savent réellement à quoi sert chaque étape de la compilation d'une map. Je vais donc tenter de vous expliquer cela rudimentairement (attention ce n'est pas non plus un cours sur la compilation, je fais avec mes connaissances et elles sont sommaires).

I.1. BSP

Un cube sous Half-Life 2

Lors de la compilation, BSP possède le rôle le plus primitif. En effet, avant que n'importe lequel des autres outils puisse être utilisé, il faut au préalable "construire" la map. C'est le rôle de BSP. Il ignore d'abord toutes les entités MÊME les func_detail et créé les blocs qui formeront l'architecture basique de la map à l'aide de polygones. Dans le cas de Half-Life 2, tout objet est construit à partir de triangles, il faut donc 12 triangles pour faire un bloc rectangulaire. (2 par face rectangulaire)
BSP ignore les func_detail pour la seule et bonne raison que ce sont des brushes comme les autres mais qu'ils sont traités différemment lors de la compilation. Nous y reviendrons plus tard.

Son rôle est donc en premier lieu de découper la map en triangles. Half-Life 2 ne gêre pas les polygones de plus de 3 sommets, comme la majorité des moteurs 3D. Il est donc obligé de convertir un polygone de 4 ou 5 faces sous Hammer en 2 ou 3 triangles sous Half-Life 2, et ce même si Hammer semble persuadé qu'une forme à quatre côté puisse exister. Si elles sont représentées ainsi dans Hammer, c'est simplement pour que cela soit plus clair, plus intuitif et surtout plus simple pour s'y retrouver.

BSP n'ignore pas réellement les entités, sinon il n'y en aurait tout simplement pas dans la map. Il faut bien différencier la "disposition des blocs" qui est le partitionnage de l'espace (découpage de la map et création de "pièces" ou "salles", ou Binary Space Partitioning [BSP]) de l'enregistrement de la position des entités. Les entités sont par la suite dynamiquement chargées par le moteur, à l'emplacement noté par BSP.

Un exemple de leak

Le partitionnage de l'espace consiste à déterminer la surface jouable et à traiter les endroits creux.. Hammer determine où sont les endroits où le joueur est susceptible de pouvoir se trouver.. Logiquement, il s'arrête aux "murs" qui bordent la map (le ciel par exemple). Tout ce qui se trouve en dehors de la map, ce vide étrange qu'aucun mappeur ne devrait laisser apparant, n'existe pas. Quand je dis "Logiquement" c'est parce que si votre map possède malgré tout un moyen d'accès vers le vide de l'extérieur (un trou en fait, et peu importe sa taille) et bien BSP ne va plus être capable de determiner où commence et où s'arrête votre map.. Il va, au bout d'un moment, se retrouver dans le vide et planter car il a "du vide" à calculer à l'infini... C'est ce qu'on appelle courramment un leak (littéralement "une fuite" en anglais).

Une map qui possède un leak est impossible à optimiser, aussi veillez à ce que vos maps ne contiennent jamais de leaks. Les leaks se repèrent lors de la compilation de la map.. soyez attentifs aux messages de ce genre, qui indiquent un leak dans votre map :
**** leaked ****
Entity info_player_start (0.00 0.00 64.00) leaked!

Pour vous en débarrasser, après la compilation faites Map > Load Pointfile. Ceci va dessiner un trait rouge sur votre map qui va a un moment donné passer par le trou à reboucher.. vous n'aurez qu'à le suivre et faire le nécessaire

Pour en savoir plus sur BSP :
* Utilisez cet outil créé par moi-même pour trouver vos erreurs de compilation.
* Lisez ce tutorial de Gectou4.
* Lisez cette page du Wiki de Valve.

I.2. VIS

C'est le deuxième outil à se lancer durant la compilation et c'est également celui qui a le plus d'importance au niveau de l'optimisation de votre carte. Explications :
Lorsque BSP a terminé de construire votre carte avec ses triangles et de découper l'espace jouable, c'est au tour de VIS d'intervenir. Avez-vous déjà testé votre map sans compiler avec le VIS ? Normalement, vous allez avoir moins de FPS qu'avec (même si vous n'avez pas optimisé) et pourquoi ? C'est tout simple : VIS constitue tout simplement les yeux du joueur, il va calculer la visibilité de chaque objet selon toutes les positions possibles. Certes, il ne calcule pas vraiment la visibilité de chaque objet, sinon nous en aurions pour la nuit, mais il va habilement (en théorie) découper chaque partie de votre map en "salles" depuis lesquelles le joueur pourra ou non voir les autres salles. Accrochez vous, c'est pas simple à comprendre, mais une fois que ça sera rentré ça ira beaucoup mieux.

Découpage selon VIS

Prenons l'exemple ci-contre. Nous avons un couloir (numéro 5) reliant 4 salles (numéros 1, 2, 3 et 4) entre elles (vus de haut). Disons que l'on se trouve dans la salle 1. A votre avis, est-il nécessaire de calculer ce qui se trouve dans la salle 3 ? Je pense que non personnellement, et c'est exactement ce que le VIS va se dire. Dès qu'il n'y aura aucun moyen quel qu'il soit de voir le moindre pixel d'une autre salle, elle ne sera pas affichée, tout simplement.
En se trouvant dans le couloir, on a bien sûr une visibilité totale sur chaque salle et le couloir.. tout est donc calculé.
Depuis notre salle 1, nous pouvons bien sûr voir la salle d'en face (la 2) par l'ouverture, mais on peut également voir ce qui se passe dans la salle 4 si l'on se décale un peu et que l'on regarde vers la droite. Certes, on n'y verra pas grand chose, quelques centimètres tout au plus, mais c'est suffisant pour le VIS.

Je reviendrai un peu plus tard sur plusieurs moyen de ne pas calculer cette salle dont on ne voit "presque rien" mais aussi sur d'autres cas de figure plus ou moins complexes.
Il faut simplement à partir de maintenant que vous gardiez en tête que VIS ne prend pas compte l'endroit exact où vous vous trouvez dans le jeu mais uniquement la "salle" dans laquelle vous vous trouvez.. A partir du moment où vous vous trouvez dans une "salle" il considère que vous pouvez vous trouver à n'importe quel endroit à l'intérieur (aussi bien "horizontalement" que "verticalement"). VIS considère le jeu comme une sorte de succession de blocs creux (les fameuses "salles") dans lesquels le joueur peut éventuellement se trouver, mais on ne sait pas exactement où à l'intérieur de ces salles. Vous pouvez donc vous trouver au plafond en haut à gauche ou dans le coin en bas à droite de la salle 2 (par exemple), peu importe pour lui. Je suis conscient que selon si l'on se trouve sur le point jaune ou le point bleu sur le plan ci-contre, on a pas forcément une vue dégagée de la salle 4.. mais il va falloir apprendre à penser comme VIS. Lui pense que vous êtes sur les deux en même temps, ainsi que partout ailleurs dans la salle.

Note: Compiler sa map en VIS FAST ne donne absolument pas un ordre de grandeur des FPS dans la map. Compiler en FAST c'est un peu comme ne rien faire du tout.. et c'est totalement déconseillé pour une compilation finale. Compiler en FAST c'est uniquement pour faire des tests sans altérer la qualité visuelle.. (à part RAD FAST qui altère les ombres)
Note: VIS s'occupe également du rendu de l'eau une fois dans le jeu.. en fait il ne s'occupe pas vraiment du rendu, mais il y participe. Pour voir l'eau dans votre map, vous devrez donc compiler au moins en VIS FAST.
Note: VIS calcule la visibilité à deux vis-leafs de distance, c'est très important à retenir pour la suite, on en reparlera.

ch4ndl3r a dit :
Le souci avec VIS, c'est qu'il faut voir les vis-leafs comme des volumes (horizontaux et verticaux) bornés par des brushes. (ndlr: des blocs) [...] Une fois que VIS a terminé son boulot, on obtient une table, le PVS qui indique pour tel ou tel vis-leaf quels sont les autres visibles. Cette table est ensuite interpretée directement ingame.

Définition : le PVS
Ceci est une notion qu'il n'est pas obligatoire de connaître, je la met juste ici pour votre culture générale. Cet acronyme est soumis à diverses interprétations : aussi bien "Potential Visibility Set", que "Potentially Visible Set", ou "Potentially Viewable Set". Le PVS contrôle ce qui est censé être affiché ou non par le moteur directement dans le jeu. Ces calculs sont basés sur la compilation de VIS qui a normalement déterminé ce qui est visible et de où est-ce que c'est visible. A la place de tous le temps afficher la totalité de la map, le moteur se contente alors d'afficher ce qui est visible contribuant à un gain de performances élevé.

Voici 4 images qui vous aideront probablement à encore mieux comprendre ce qu'est un visleaf. Un visleaf est une "salle imaginaire" qui est représentée par les traits rouges sur les images ci-dessous.

mat_leafvis 0 mat_leafvis 1
mat_leafvis 0 mat_leafvis 1

I.3. RAD

Le dernier outil qui se lance lors d'une compilation normale de Hammer c'est RAD. L'ami RAD a pour rôle de générer les ombres/lumières et de finaliser la map. Je ne sais pas grand chose sur lui, mais par contre, je sais qu'il n'intervient pas énormément pour optimiser une carte. Je vous expliquerai néanmoins quelques petits trucs qui font qu'il peut être utile tout de même.

Comme vous avez pu le constater j'espère, VIS constitue une part très importante dans l'optimisation d'une map. Néanmoins, on va voir ensemble que BSP et RAD ont aussi leur rôle à jouer dans l'histoire. Des rôles secondaires certes, mais souvent, les rôles secondaires sont très important également.

I.4. Temps de compilation

J'entend beaucoup de personnes (et j'ai été des leurs) dire qu'une map bien optimisée ne devrait pas se compiler en plus d'une heure, ou encore que c'est RAD qui prend le plus de temps, ou même qu'une map moche ne doit pas mettre longtemps à compiler. Tout ceci est absolument faux. Le temps de compilation d'une map est quelque chose de très variable. Cela dépend de facteurs tels que :

  • La puissance de votre ordinateur : Plus votre ordinateur est puissant, plus la compilation est rapide. Un processeur multi-core améliore également grandement les temps de compilation.
  • La complexité de la carte : Plus vous avez des salles avec des formes complexes, des enchevêtrements de couloirs arrondis ou de salles en cercle, plus VIS va mettre de temps à compiler.. Votre map aura beau être bien optimisée, il ne faut pas non plus rêver.
  • La complexité des éclairages : Plus vous avez des jeux de lumière complexes et des lightmap petites, plus RAD va mettre de temps à compiler... RAD peut parfois être très très long à mettre en lumière une carte et il demande également énormément de mémoire. Bien souvent son processus utilise plus de 200 MB de mémoire à lui seul.
  • Les options avec lesquelles vous compilez : Sur certains compilateurs, il est possible de régler plein d'options différentes qui allongent ou réduisent la durée de la compilation en fonction des effets ajoutés ou supprimés.
  • Si vous utilisez ou non votre ordinateur pendant une compilation : Plus vous utilisez de programmes en même temps que vous compilez et plus le compilateur doit partager ses ressources. Et plus le compilateur partage ses ressources, plus il est lent.

Il est également faux de penser que RAD est le plus long ou que c'est VIS le plus long.. Plus votre map aura d'effets de lumière complexes, plus RAD mettra de temps à compiler. Plus votre map sera complexe au niveau architectural et plus VIS mettra de temps à compiler. Il n'existe pas non plus de temps de référence pour chaque type de map.. tout dépend des facteurs énoncés plus haut. dm_tropic met environ 30min à se compiler avec le HDR, dm_mine met environ 2 ou 3h tandis que dm_escape met 10h. Il n'y a pas de règle de calcul pour cela !


II. Les Techniques

Passons tout de suite au vif du sujet. L'optimisation sous Half-Life 2.
On ne dirait pas comme ça en voyant Half-Life 2 tourner, mais le moteur de rendu est beaucoup plus restrictif qu'il n'y parait. Lorsque la plupart d'entre nous, moi le premier, ont commencé leur première carte sous Half-Life 2, ils se sont dit "Oulala, ça va me changer de Half-Life 1, plus de limites, plus de ralentissements !". A tord. J'ai cru à tout ça tout au long de ma première map dm_autoroute. Aujourd'hui, cette map pourri dans un coin du dossier sourcesdk_content et pour cause.. elle est tout bonnement injouable. Je me disais : "Hammer 4 c'est du gateau, couplé à Half-Life 2 ça va faire des étincelles, la puissance incarnée !" J'étais très loin du compte.

Certes, il parait beaucoup plus facile de faire des cartes sous Hammer que tout autre soft orienté modélisation 3D, et c'est vrai ! Le logiciel est très simple d'utilisation, ce sont malheureusement les méthodes qui sont très complexes. Autant il est facile de mapper pour Half-Life 2, autant il est difficile de BIEN mapper pour Half-Life 2.

II.1. Le découpage de la map

Ce qui suit est la règle d'or du mapping sous n'importe quel moteur utilisant le système BSP/VIS.
Toute map doit être constituée de "salles" plus moins grandes, toutes hermétiquement fermées. Bien sûr, le mot "hermétique" est une image, car si l'on ferme réellement toutes ces salles hermétiquement, on va avoir du mal à passer de l'une à l'autre. Non, ce que j'entend par "hermétiquement" c'est "disposées d'une façon qui fait penser à des salles". On va les fermer imaginairement par la suite à l'aide d'entités spéciales. Il faut voir les maps comme des successions de blocs creux (des salles) reliés par des couloirs (c'est une vision bien sûr très restrictive). C'est assez complexe à expliquer, prenons un exemple.

II.1.A. Utilisation de VIS uniquement

Imaginons que tout à coup vous ayiez envie de créer trois salles, en angle droit, à ciel ouvert et raccordées par des couloirs. Pourquoi pas après tout ? Je vais vous montrer ce qu'il ne faut absolument pas faire sous aucune forme que ce soit ! Et pourtant, Dieu sait qu'on en voit souvent des maps comme ça !

A ne surtout pas faire !

Qu'est-ce qui ne va pas vont me dire certains.. "Non mais trois claques dans ta tête, quoi !"
Rien ne va ! Tout est agencé dans le contraire de l'esprit Half-Life 2 ! Je vous explique :

Le plus gros problème, même énorme, qui se pose ici, c'est le ciel (lees blocs bleu-ciel). Beaucoup d'entre nous ne peuvent imaginer le ciel autrement que comme "la plus grande chose qui nous entoure" et font donc un bloc tout autour de leur map pour le représenter. Il faut arrêter de penser comme cela ! Dans la réalité, c'est peut-être ainsi, mais pas dans Half-Life 2. Dans Half-Life 2, le ciel c'est simplement un bloc avec une texture spéciale qui donne une illusion de profondeur. Il n'y a donc aucun besoin de faire un bloc réellement profond !
Vous allez me dire que c'est pareil, et que vous ne voyez pas le problème.. "T'en veux une autre ?".
Je viens d'expliquer le fonctionnement de VIS, 20 lignes plus tôt, mais on va reprendre. Je vais me mettre à la place de VIS qui découvre cette horreur et doit la découper en "salles hermétiques". (pour mon bien personnel, je vais m'abstenir de faire toutes les vues, mais juste celle du haut, c'est plus parlant. De plus, je ne m'appelle pas VIS et donc le découpage n'est peut-être pas exact, c'est pour donner une idée. J'ai coloré les différentes zones perçues par VIS pour mieux les distinguer)

Le résultat

Et voilà le travail ! Vous n'avez rien à redire sur VIS, il a fait son travail en suivant les directives de votre map, il a découpé en suivant le contour de vos blocs et on se retrouve avec un beau merdier sans nom composé de plusieurs dizaines de vis-leafs. (a prononcer "vicelifce", j'appellerai désormais comme ça les "salles hermétiques" dont je parle) Et où sont ces vis-leafs ? A des endroits vides qu'on ne peut de toute façon même pas atteindre, c'est-à-dire hors des trois salles du départ ! Voyez vous l'intêret ? Moi non.

Pourquoi VIS a-t-il découpé de cette façon ? Mais tout simplement parce que nos trois salles n'ont pas de "plafond". VIS n'est pas censé savoir que nous ne pourrons pas passer par dessus les murs et, par conséquent, il fait son boulot partout.. même là où nous n'irons pas. C'est pourquoi cette technique dite du "Skybox Géant" est à proscrire immédiatement. Les blocs avec la texture tools/toolsskybox doivent être considérés comme des murs normaux. C'est juste leur apparence qui va changer.

En conlusion, il n'est pas nécessaire de faire un skybox géant autour de sa map, il suffit de "boucher" les endroits où l'on voit le ciel avec des blocs portant la texture tools/toolsskybox. Comme ceci :

Ce qu'il faut faire !

Le résultat est le même, sauf que l'on ne peut pas passer par dessus les murs. Mais de toute façon, on en a jamais eu envie.
VIS comprend alors beaucoup beaucoup mieux votre map et découpe ainsi :

Le résultat

On se retrouve avec 5 vis-leafs au lieu d'une bonne vingtaine ! Vous comprenez maintenant pourquoi je dis qu'il faut fermer "fermétiquement" ces "salles" ? Un autre exemple serait une banale fenêtre par laquelle on aurait jamais l'occasion de passer, mais qui donnerait sur l'extérieur.. pas besoin de faire toute une salle dehors, il suffit de boucher le trou de la fenêtre :

Ce qu'il faut faire !

II.1.B. Utilisation de VIS et des Hints

II.1.B.a. Exemple 1

C'est bien joli tout ça, mais du coup j'en entend déjà dire : "Si j'ai envie de passer par au dessus des murs pour aller d'une pièce à l'autre , ça me regarde." Et j'allais bien sûr y venir, car tout n'est pas toujours aussi rose dans la vie d'un mappeur :D Il est vrai que l'on a le droit de vouloir laisser au joueur la possibilité de passer au dessus des murs. Dans le cas de figure précédent, il se retrouve coincé contre le bloc du ciel. Heureusement il y a un moyen de faire la même chose autrement. Explications :

Prenons une autre disposition, je me suis servi de celle fournie dans le SDK : sdk_hints.vmf
Deux salles séparées par un épais mur sur lequel, si on y arrive, on peut très bien monter pour rejoindre l'autre salle. Le ciel doit donc être assez haut, du moins pas collé aux murs pour que le joueur puisse marcher librement sur le mur mitoyen. Voici le découpage de VIS vu de côté lorsque l'on dispose le tout comme ceci :

La mauvaise utilisation

Les blocs colorés en rouge, vert et bleu sont les vis-leafs que VIS va découper. Le problème est le suivant : lorsque l'on se trouve dans la salle 1, on ne peut logiquement pas voir ce qui se trouve dans la salle 2 car il y a un épais mur qui sépare les deux salles. On peut apercevoir ce qui peut se trouver SUR le mur, mais pas après le mur. Or, avec ce découpage de VIS, on a un problème. Regardez bien, n'importe où que l'on se trouve dans la salle 1, que ce soit au ras du sol (point bleu) ou au ras du ciel (point jaune), on se trouve dans le même vis-leaf coloré en vert. Du coup, VIS pense que c'est possible d'être collé au ciel et, par conséquent, de voir ce qui se trouve dans la salle 2 en regardant vers le bas.

C'est ici qu'interviennent les Hints. Les hints, c'est assez obscur et peu de gens arrivent à les comprendre, mais je vais tenter de vous expliquer. C'est un bloc normal qui va servir à découper les vis-leafs. En gros, on va demander à VIS d'en créer plus que la normale (ici VIS a créé 3 vis-leafs spontanément, mais vous êtes d'accord que ça ne suffit pas puisqu'il y a un problème de visibilité). Bien utilisés, les hints ajoutent des vis-leafs mais font moins ramer le jeu, tandis que mal utilisés ils en rajoutent, font encore plus ramer le jeu et allongent le temps de compilation en prime.
Ce qu'il faut comprendre avec les hints, c'est que l'on a, dans 99% des cas, uniquement besoin d'une seule des 6 faces du bloc. Cette face va être considérée par VIS comme une découpe/une limite dans le vis-leaf courrant. Cette face qui sert de "frontière" doit porter la texture HINT (tools/toolshint) et toutes les autres faces du bloc la texture SKIP (tools/toolsskip).

Dans notre cas à nous, ce que lon veut, c'est découper les vis-leafs des salles 1 et 2 en deux parties. Celle ou l'on va toujours se trouver (près du sol) et celle où l'on ne va jamais aller (vers le ciel). Voyez l'exemple :

Le bloc vu du dessus (skip) :
Hint vu du dessus

Le bloc vu du dessous (hint) :
Hint vu du dessous

Le bloc vu de côté :
Hint vu de côté

Le résultat sur la découpe de VIS sera alors tout simple, il va fractionner les vis-leafs 1 et 2 en deux vis-leafs distincts dans le sens de la hauteur. Du coup, depuis le vis-leaf vert, on ne pourra voir que ce qui se passe dans le rouge (qui est vide, donc peu importe) mais plus dans le bleu, celui qui nous intéresse ! Comme ceci :

La mauvaise utilisation

Les Hints sont assez tordus, et il faut beaucoup de logique et des facilités à visualiser dans l'espace pour savoir où les placer efficacement. Mais une fois que l'on y est arrivés, cela peut drastiquement améliorer les performances d'une map.
Il faut bien se dire que, bien qu'un hint soit représenté par un bloc, seul la ou les faces portant la texture tools/toolshint vont réellement servir. Il est possible de les placer à l'horizontale, à la verticale, et aussi penchés à 45° dans n'importe quel sens je crois. La vraie restriction est de ne pas mettre un hint dont les 4 côtés de la face portant la texture Hint ne toucheraient pas tous un mur. Il y aurait alors un trou entre le mur et le Hint résultant en une erreur de compilation. J'ai récemment découvert qu'un hint pouvait très bien ne faire qu'une unité de long et qu'il n'était pas important qu'il touche des murs à chacun de ses côtés.. Si un hint ne touche pas de blocs, lors de la compilation VIS va automatiquement prolonger les bords du bloc hint jusqu'à rencontrer un mur ou un autre vis-leaf.. Plutôt pratique si vous avez un endroit avec énormément de hints. Néanmoins, il est beaucoup moins évident de voir où passent les hints dans votre map si vous ne pouvez plus les voir qu'en imaginant le prolongement des blocs..
Bien sûr, il faut également que la face texturée en Hint soit rectangulaire, cela va sans dire :)

Extrait d'une conversation MSN avec MoroeS :

MoroeS dit :
Pour ton tuto, explique peut-être précisément comment mettre les HINT dans une map à ciel ouvert où par exemple c'est une grande plaine.
NykO18 dit :
Ben en fait tu peux pas vraiment en mettre..
MoroeS dit :
Donc en gros dans un grand espace il faut bien optimiser.
NykO18 dit :
Oui, il faut se servir d'autres entités comme la distance maximale de visibilité, la distance de disparition des props, les occluders, etc..
MoroeS dit :
Tu peux pas faire des "pièces" avec les HINT ?
NykO18 dit :
Non, les hints font certes des pièces, mais si ces pièces ne sont pas fermées par des blocs à un moment ou un autre ça ne sert à rien car elles ne sont réellement jamais fermées..
NykO18 dit :
Les hints c'est juste une aide pour VIS, ça ne fait aucun miracle, il ne faut pas voir les hints comme des entités qui cachent la visibilité car ce n'est absolument pas le but des hints. Ils servent seulement à aider VIS à découper la map lorsqu'il ne comprend pas certains endroits (comme mon exemple du ciel atteignable un peu plus haut)
MoroeS dit :
Ok
NykO18 dit :
Tout ce que tu peux faire dans un grand espace c'est limiter la propagation des découpes occasionnées par des blocs plus ou moins isolés.. imagine tu as un mur diforme au milieu d'une plaine, si tu ne l'entoures pas de hints, les découpes occasionnées par ses bords vont se propager à tout l'espace disponible et ainsi mettre rapidement en charpie l'organisation de la plaine..

Howto hints

NDLR: Je précise que dans cet exemple, les blocs auraient juste eu besoin d'être transformés en func_detail et on n'en parle plus (car les func_detail ne découpent pas l'espace, c'est justement leur plus grand interêt). Mais c'est pour l'exemple que je les laisse en blocs normaux. Il faut voir le bloc carré comme un batiment (une maison) et le cylindre comme une cuve par exemple :D

Pour en savoir plus sur les hints :
* Ouvrez la map sdk_hints.vmf fournie avec le SDK.
* Voyez cette page du Wiki de Valve.
* Voyez ce tutorial uniquement ciblé sur l'utilisation des hints par moi-même.
* Voyez ce tutorial par Alucard_DH.
* Voyez ce tutorial par 00940. * Voyez ce tutorial par NinjaGrinch. * Voyez cette page du Wiki de VALVe.

II.1.B.b. Exemple 2

Partons maintenant sur un autre exemple pour comprendre les hints.. Il est un peu hors-sujet dans le contexte actuel de nos salles mais il vaut toujours mieux s'assurer d'avoir compris avec un deuxième exemple. Ce coup-ci, je vais prendre le cas classique du couloir courbé reliant deux salles entre elles. Pourquoi classique ? Parce que c'est l'exemple qui est toujours utilisé dans les cours sur les hints !
Voici le plan vu de haut de la map d'exemple :

Plan de la map d'exemple

Bon, jusque là j'espère que vous aurez deviné que les deux gros carrés sont deux salles et que le petit truc qui les relie est un couloir. J'espère aussi que vous avez compris que de la salle du "haut", il est relativement inutile de savoir ce qui se passe dans la salle du "bas". Si BSP fait correctement son travail de découpe, il devrait créer quelque chose dans ce genre là, 4 vis-leafs représentant les 4 parties principales de la map.

Plan des vis-leafs

Seulement voilà, quel est le problème sur la découpe du dessus ? Il est assez simple a appréhender, VIS détermine la visibilité en se basant sur le fait qu'un vis-leaf est visible ou non depuis celui dans lequel on se trouve. Actuellement, on se trouve dans le vis-leaf numéro 1 sur le schéma ci-dessus. On a donc bien sûr une vue dégagée sur le numéro 2 ET une vue partielle sur le numéro 3. Concrètement qu'est-ce que ça signifie ? Ca signifie que peu importe l'endroit où l'on se trouve dans le vis-leaf numéro 1, tout ce qui se trouve dans les vis-leafs numéro 1, 2 et 3 sera calculé. Et ce, même si vous vous trouvez au niveau du chiffre 1 sur le schéma et que vous n'avez aucune visibilité sur le vis-leaf numéro 3. C'est un premier problème.. oui un premier car ce n'est que le premier.

Souvenez de ce que j'ai expliqué quand j'ai présenté VIS au début de ce tutorial, il calcule la visibilité à 2 vis-leafs de distance. Concrètement cela signifie que les vis-leafs calculés sont non seulement ceux que vous voyez, mais également ceux que vous pourriez voir si vous vous situiez dans ceux que vous pouvez voir depuis l'endroit où vous êtes actuellement. Ouais c'est un peu confu, mais avec l'exemple vous allez comprendre. Toujours sur le schéma ci-dessus, depuis le vis-leaf numéro 1 on voit donc ce qui se passe dans le 2 et 3. Le problème c'est donc que VIS décide qu'il faut calculer également les vis-leafs qu'il est possible de voir si vous vous trouviez dans le 2 ou le 3. En conclusion, comme le vis-leaf numéro 4 est visible du vis-leaf numéro 3, il sera également calculé ! Résultat, depuis la salle du "haut" le moteur calcule absolument toute la map et donc la salle du "bas" avec (même si on ne la voit pas).

Visiblité trop importante

Il va donc falloir trouver un moyen de dire à VIS qu'il arrête son délire et qu'il ne calcule plus cette salle d'aussi loin. Et pour cela, il va falloir modifier la façon dont BSP a découpé ces maudits vis-leafs pendant la compilation. Il va falloir faire en sorte qu'il y ai plus de 2 vis-leafs de distance entre la salle du "haut" et celle du "bas". Ce genre de chose se fait au moyen de hints. La seule façon de placer le hint dans cette situation c'est de le mettre en biais dans le couloir de façon à ce que l'on ne voie même plus le deuxième morceau du couloir. Et il n'y a que cette position qui convient (en jaune sur le schéma) :

Position du hint

De cette façon, un 5ème vis-leaf est créé. La visibilité étant toujours calculée à deux vis-leafs de distance et le vis-leaf numéro 5 pouvant voir le numéro 3, le couloir sera bien sûr toujours calculé entièrement, mais le calcul s'arrêtera là. La salle du "bas" est maintenant à 3 vis-leafs de distance et VIS la considère désormais invisible depuis l'emplacement actuel. Voici en grande partie à quoi servent les hints.

II.1.B.c. Exemple 3

On vient de voir un exemple avec de belles découpes de BSP sur deux salles et un couloir, où tout est rose et fleuri dans le monde de BSP et de VIS. Maintenant, il est également probable que dès le départ BSP ne comprenne rien à rien à la situation et décide d'interpréter tout ça à l'arrache comme il peut. Imaginons que BSP ai décidé de découper l'espace de la façon suivante (et ne riez pas trop, c'est exactement la façon dont il découpe sur cette map de test chez moi, comme quoi...) :

Découpage anarchique

Il a tout simplement considéré les salles comme faisant partie intégrante du couloir.. juste une excroissance un peu plus large. Il a donc donné la priorité au couloir au lieu de la donner aux salles. Résultat, de n'importe où dans la map tout le reste est calculé. Le vis-leaf 1 voit le 3 qui voit le 4, le 3 voit le 4 qui voit le 5 et le 6, et ainsi de suite. La seule façon de calmer les choses dans ce cas de figure c'est de se prendre pour BSP et d'imaginer la "meilleur découpe qu'il aurait dû faire". Avec des hints il est ainsi possible de rétablir l'équilibre et de réparer les ignominies de BSP. Les hints seraient à placer de cette façon (en jaune sur le schéma) :

Découpage 'sauvons les meubles'

Effectivement, cela fait de plus en plus de vis-leafs pour rien.. et c'est vrai que c'est gonflant ; mais BSP est concu comme cela et on n'y peut absolument rien. Avec cette nouvelle découpe, le vis-leaf 1, 2 et 3 voient le 4 qui voit le 5, le 4 voit le 5 qui voit le 6, 7 et 8. La salle du "bas" n'est plus non plus calculée depuis la salle du "haut" et tout le monde est content.. Il y a beaucoup plus de vis-leafs, mais au moins ca fonctionne.

Évidemment, tous ces exemples paraîssent un peu dérisoire vu la taille des salles et le faible niveau de complexité utilisé. Mais imaginez que ces salles soient <>10 fois plus grandes et détaillées et on obtient de l'optimisation en bonne et dûe forme !

II.1.C. Utilisation de VIS et de murs invisibles (displacements)

Si basiquement, vous n'avez pas envie de vous prendre la tête avec toutes ces histoires de hints, il reste malgré tout une solution qui marche très bien. Les murs invisibles, couverts de la texture tools/toolnodraw, ils sont invisibles, et pourtant ils bloquent la visibilité, si c'est pas magnifique ça ! Prenons une fois de plus un exemple.
Disons que l'on a une salle, traversée par un mur naturel en roche (créé à partir de displacements). Ce qu'il faut savoir avec les displacements, c'est qu'ils ne sont pas considérés comme des murs par BSP. C'est comme si on pouvait voir à travers.. ça peut paraître bizarre, mais imaginez la découpe faite par BSP le long de murs de forme totalement irrégulière telle qu'un mur comme celui-ci.. ce ne serait pas beau à voir et on comprend tout de suite pourquoi BSP ne les traite pas.

La scène

Le problème ici, c'est bien sûr que malgré le fait que l'on ne verra jamais ce qui se trouve de l'autre côté de ce mur (il est trop haut), tout y sera quand même calculé pour la raison au dessus.. (VIS voit à travers les displacements) L'astuce est donc de remodéliser ce mur avec un autre bloc qui sera lui traité par BSP mais qui sera invisible (et solide). La texture tools/toolnodraw est donc tout à fait adaptée ! Faites un bloc de cette manière en plein milieu de ce fichu mur de roche :

Le mur nodraw

De cette façon, la salle sera coupée en deux salles distinctes et BSP pourra faire son travail tout en ignorant toujours notre mur de roche. Lorsqu'il se heurtera au mur en nodraw, il considèrera que les limites de la salle se situent ici, et ignorera donc tout ce qui se trouve de l'autre côté ! Je veux bien vous accorder le fait que cela va empêcher vos grenades de passer de l'autre côté, mais on ne peut pas tout avoir en optimisation quand on utilise les méthodes du pauvre. :D

Si maintenant vous vous décidez finalement à utiliser les hints, alors je vais vous montrer comment faire tout en gardant l'utilisation du bloc nodraw. Disons que, finalement, ça vous plairait bien que les grenades passent au dessus du mur. En gardant en mémoire que VIS voit à travers les displacements, il nous faut donc quelque chose à substituer à ce mur invisible pour empêcher tout ce qui est de l'autre côté d'apparaître. On va donc laisser le mur en nodraw, mais à l'intérieur du bloc displacé uniquement, comme ceci :

Le mur nodraw dedans

On se met alors dans la peau de BSP, et on décoche dans les visgroups (sur le côté droit de Hammer) le groupe "Displacements" afin de voir uniquement ce que BSP voit. :

Le mur nodraw uniquement

On se retrouve alors tout "bêtement" dans le cas exposé au II.1.B (deux salles séparées par un mur mitoyen) et il nous suffit de disposer un hint sur le haut de ce mur et couvrant toute la salle, pour empêcher d'afficher ce qui se trouve de l'autre côté du mur. On obtient finalement le résultat suivant et notre optimisation est terminée :

Le mur nodraw et le hint

Pour en savoir plus sur la façon de construire sa map :
* Ouvrez les maps deathmatch et solo fournies avec le SDK.
* Voyez cette page du Wiki de Valve.

II.1.D. Voir avec les yeux du compilateur

Dans le paragraphe précédent, j'ai rapidement abordé le fait que BSP et VIS ne voyaient pas le map de la même façon que nous, mais je ne me suis pas plus étendu sur le sujet que cela.. or, il me semble que c'est une chose très importante, et encore plus importante depuis que Hammer a été mis à jour afin de créer automatiquement des visgroups assez performants. J'ai donc décidé de m'attarder un peu plus là-dessus car c'est tout de même une "technique" que j'utilise relativement souvent lorsque je créé des maps.
Vous ne savez pas ce que sont les autovisgroups ? Les voici :

Les visgroups

Les autovisgroups c'est simplement une façon de mieux s'y retrouver dans sa map quand cela commence à devenir un peu fouilli.. Lorsque vous construisez votre map, vous avez la possibilité de créer des groupes en selectionnant plusieurs objets et en les groupant. Et bien sachez qu'à côté de cela, Hammer créé lui même automatiquement des groupes très utiles au mappeur. Il rassemble lui même tout ce qui se ressemble afin de pouvoir les cacher/montrer à volonté. Il créé un groupe pour les props, un groupe pour les displacements, un groupe pour les func_detail, et ainsi de suite... Tout se retrouve bien organisé et cela va nous permettre de voir la map de la même façon que le compilateur.

Prenons pour l'exemple un morceau d'une de mes maps, un petit village paisible. Voici comment vous voyez la map dans Hammer :

Un village

Waaah, c'est joli (:D) mais par contre ce n'est absolument pas comme ça que le compilateur voit la map.. Faisons une petite liste de ce que le compilateur (BSP+VIS) ne voit pas. BSP et VIS ne voient pas :

  • Les props
  • Les func_detail
  • Les displacements
  • Et toutes les entités en général
  • Par contre VIS voit les hints..

On va donc tout simplement aller dans le petit menu des autovisgroups et décocher tout ce qui nous intéresse pas, en premier lieu tous les props, puis les func_detail, puis les displacements, et toutes les entités :

Un village sans props Un village sans props ni displacements Un village sans props ni displacements ni displacements Un village sans props ni displacements ni displacements ni entités

Il ne reste qu'à rajouter les hints et nous avons enfin une vision à peu près correcte de ce que voit vraiment le compilateur lorsqu'il traite la map.

Un village sans props ni displacements ni displacements ni entités, mais avec hints

De là, il vous est beaucoup plus facile de voir où il risque d'y avoir des découpes, quels objets feraient mieux d'être mis en func_detail, quels autres ont besoin de hints, et ainsi de suite.. C'est une "technique" que j'utilise très souvent pour voir ce qui risque ou non de poser problème au compilateur. Sachez également que lorsque vous compilez en expert, une option -glview peut être ajoutée à BSP afin qu'il génère automatiquement une représentation de la map telle qu'il la voit, sous forme d'un petit fichier d'informations 3D lisibles avec glview.exe (fourni avec le SDK dans ..\sourcesdk\bin)

Pour en savoir plus sur glview :
* Voyez ce tutorial de Gectou4.
* Voyez cette page du Wiki de Valve.


II.2. L'économie de faces

Dans cette partie, nous allons parler d'optimisations uniquement liées à BSP. Il faut savoir quelques trucs avant de commencer, notamment que BSP effectue plusieurs tâches lors de la compilation, vous pouvez d'ailleurs les voir passer lors de sa compilation qui ne dure que quelques secondes grâce au fait que sa fonction est très primitive, transformer toute l'architecture Hammer en ensemble de triangles MAIS avec quelques options. Je vais vous expliquer quelques optimisations possibles par BSP.

II.2.A. Les cylindres & arches

Je vous rassure, je ne vais pas faire de roman sur les cylindres et les arches dans Half-Life 2, mais il y a néanmoins quelques petites choses à savoir notamment au niveau du nombre de faces ! (n'est-ce pas moroes :D)
Y'a pas mal de monde qui se dit qu'un cylindre c'est du tout cuit maintenant pour le moteur d'Half-Life 2. D'accord, il n'a aucun problème pour l'afficher, mais autour ? Vous ne pensez pas qu'il risque d'y avoir un petit bémol ? Et bien si, et il est simple. BSP va repasser par dessus par la suite, et ça va pas être beau à voir du tout !

Faites donc un pilier dans une salle et compilez le tout.. Voilà la découpe de BSP pour former les vis-leaf.

Les cylindres

C'est exactement la même chose qu'en creusant avec un cylindre, quel merdier, un vis-leaf par face.. et évidemment, plus il y a de faces, et non seulement plus il y a de calculs à faire pour les afficher, mais en plus il y a également des calculs en plus pour VIS par la suite. Les cylindres ont la vie dure.

Le problème est le même pour les arches, on a tendance, en vue de faire quelque chose le plus rond et beau possible, d'abuser sur le nombre de faces. Une arche à plus de 16 faces m'est personnellement inconnue, et je fais rarement d'arches/cylindres à plus de 10 ou 12 faces. Prenons l'exemple ci-dessous :

Le test des arches

Evidemment, l'arche la plus parfaite visuellement est celle le plus à gauche, mais est-ce vraiment voyant à ce point ? L'arche de droite me semble personnellement tout à fait acceptable non ? On compare une arche à 10 faces, avec une 8 faces, et une 6 faces. Il est tout à fait possible d'utiliser l'arche du milieu, mais 8 faces pour cela me semble déjà beaucoup. (pour une map multijoueurs tout du moins) Alors ne parlons pas d'une 10 faces !

Il faut savoir être avare en faces, et ne pas toujours privilégier la qualité visuelle aux performances. Vous pouvez également jouer avec les textures, une texture arrondie "lissera" l'arche par exemple. Et si par hasard l'arche est dans la pénombre, cela se verra moins. Pourquoi ne pas opter pour des arches/cylindres à moins de faces lorsqu'il fait sombre et à plus de faces lorsqu'il fait clair ? Cela serait déjà un bon commencement :)

II.2.B. La fonction Carve et Hollow

II.2.B.a. Carve

Directement tiré de mon tutorial sur ce même sujet...
Je vois tellement de gens qui disent "CARVE CEY MAL" et d'autres qui disent "MAY POURQUOI CARVE CEY MAL ?" que j'ai décidé de faire une petite démonstration du pourquoi du comment. Premièrement, un exemple simple, vous voulez faire un trou rectangulaire dans un mur. Pour mettre une porte par exemple. Voici ce que vous obtenez en utilisant l'outil Carve :

Avec Carve :

Comme vous pouvez le voir, j'espère, il y a un bloc de trop.. un des deux sités au dessus des portes.. C'est là qu'intervient l'outil "Clip" : Au lieu d'utiliser "Carve", utilisez "Clip" comme ceci :

1. Selectionnez le bloc à découper

2. Activez l'outil "Clip"

3. Dessinez une ligne sur le bloc selectionné, elle represente la ligne selon laquelle le bloc va être découpé. (on ne peut découper que sur 2 dimensions, donc selon un plan sur l'axe des x, des y ou des z)

4. En recliquant sur l'outil, vous activez plusieurs modes. Le premier mode découpe le bloc et supprime le deuxième morceau, le 2ème mode découpe le bloc et supprime le premier morceau et le 3ème bloc découpe uniquement. C'est ce mode qui nous intéresse.

5. Lorsque vous aurez la découpe voulue, appuyez sur Entrée, et le bloc est découpé.

6. Répêtez l'action autant de fois que nécessaire pour former le trou voulu.


7. Votre découpe est terminée ! Il ne vous reste plus qu'à supprimer le bloc bouchant ce trou pour qu'il soit opérationnel.

Dans notre cas du début, on obtient facilement ceci :

Il y a donc un bloc de moins, et il est beaucoup plus facile de retoucher ce mur après la découpe.
Un autre exemple plus parlant et beaucoup plus évident, est le cas ou l'on veut faire un trou circulaire dans un mur !

Voyez le résultat avec l'outil Carve (à gauche) et avec l'outil Clip (à droite) :

Et imaginez ensuite qu'on veuille faire deux trous circulaires l'un a côté de l'autre.

Voyez le résultat avec l'outil Carve :

Voyez le résultat avec l'outil Clip:

Il devient donc évident que l'outil Carve est une horreur dans la plupart des cas, voire tous les cas, et son utilisation est à bannir pour toute map qui se veut optimisée. Essayez donc un peu de changer la taille du mur creusé avec des cylindres.. Avec ma méthode il vous suffit d'agrandir les 4 blocs autour pour agrandir le mur sans toucher au trou. Vous pouvez même déplacer librement le trou lui-même si ça vous chante...
Contrairement aux idées reçues, ma méthode ne génére pas plus de faces. Certes dans Hammer oui, mais une fois la map compilée, elle en génère au maximum le même nombre, sinon moins car tous les triangles visibles sur les images ci-dessus sont fusionnés aux blocs qui forment les bords carrés du trou.
Et si tout ceci ne vous suffit pas :

ganondorf150 a dit :
Bon alors voilà, suite à un petit abus de la fonction carve, un mur que je n'avais pas demandé s'est créé. Ce mur est comme de l'eau, on peut passer à travers et il est transparent. Je n'arrive pas à l'enlever donc si quelqu'un aurait une idée ce serait chouette.

II.2.B.b. Hollow

Selon certaines personnes, l'utilisation de la fonction Hollow serait déconseillée. Je ne sais pas vraiment pourquoi, mais il est vrai que pour des blocs autres que des blocs rectangulaires, c'est absolument proscrit ! Cela fait un bordel inimaginable de faces et de blocs irréguliers.. Regardez le résultat d'un Hollow sur un cône :

Hollow sur Spike

Zorg045 a dit :
Le hollow créé lui aussi certains problèmes, defois pouvant même faire planter la compilation, alors le mieux à faire reste encore d'utiliser ses 10 petits doigts (9 voir 8 ou moins pour certains) et de faire ça à la main, au moins on est sûr du résultat

miliciste a dit :
[...] ce skybox je vais le dégrouper pour faire 6 brush au lieu d'un seul hollowé... il parait que c'est mieux.

Il n'y a pas énormément de choses à dire sur la fonction Hollow, je conseille à tout le monde de plutôt construire ses salles bloc par bloc et ses canalisations, puits, galeries et autres endroits creux également. De même, n'essayez pas de "Hollower" des cylindres, il vous suffit de faire une arche de la même taille et de boucher chaque extrémité avec un bloc..

II.2.C. Les func_detail

Un autre fondement de l'optimisation des maps est l'entité func_detail ! Et encore, si ce n'était qu'un fondement.. c'est la base même de l'optimisation sour le moteur d'Half-Life 2. C'est la technique la plus puissante, la plus utilisée et par chance, la plus facile à mettre en oeuvre.
Cette méthode dit que tous les morceaux d'architecture complexes ou pas, que vous considérez comme des détails DOIVENT être tranformés en func_detail.

  • Les colonnes (intérieures et extérieures)
  • Les fenêtres (les rebords, les barreaux)
  • Les cloisons (si elles n'ont pas besoin de cacher la visiblité, comme dans un bureau à l'américaine par exemple)
  • Les poutres de bois
  • Les arrondis en général
  • Les passerelles suspendues
  • Les corniches sur les bords des étages d'immeubles
  • Les bords des toits où le toit est prolongé dans le vide
  • Les planches
  • Les meubles (comptoirs, caisses)
  • et plus généralement tout ce qui est un détail et/ou qui ressort d'un mur ou du sol et risque de causer des problèmes à BSP et VIS doit être transformé en func_detail.

Prenons une petite carte et mettons y quelques détails (poutres, piliers, cloisons, étagères, ...) pour voir ce qu'il se passe lorsque l'on arrive dans le jeu.

Voici ce que cela donne dans Hammer :
On décompte 24 faces pour les deux colonnes
20 faces pour l'étagère du fond
7 faces pour la cloison de gauche
6 pour les murs, le sol et le plafond..
Soit un total de 57 faces fois 2 = 114 triangles/polygones pour la totalité de la salle. (je multiplie par 2 le nombre de faces car toutes les faces sont rectangulaires et sont donc transformées en 2 triangles chacune)

Sans func_detail

Mais voilà ce que ça donne dans le jeu une fois la map compilée :
Je ne m'amuserai pas à compter les faces, mais on peut facilement imaginer qu'il y en a plus du double..

Sans func_detail

Comme vous pouvez le constater, il y a énormément de faces créées automatiquement autour des formes complexes qui constituent les détails. Je ne vous exliquerai pas pourquoi (ça prendrait un certain temps, sachez juste que BSP, pendant la compilation, fusionne les blocs qui se touchent). Il faut savoir que n'importe quel volume qui touche une surface génère un nombre de faces supplémentaires égal au nombre de côtés du volume qui touchent la surface. Le cylindre est donc le pire des cas car un cylindre de 12 faces touchant un plafond et un sol va générer 24 faces inutiles, 12 sur chacun des deux blocs. Et pour peu qu'il y ai plusieurs de ces cylindres, cela devient vite cataclysmique car les faces s'entre-découpent..
Voyez cette image pour voir comment les cylindres ont découpé le plafond.
Voyez cette image pour voir comment l'étagère à découpé le sol et le mur.
Voyez cette image pour voir comment la cloison à découpé le sol, le plafond et le mur.

Pour éviter ce genre de désagréments, transformez un par un tout les blocs qui forment les détails en func_detail et voici le résultat obtenu dans le jeu :
Nous sommes très loin des 200 et quelques faces de tout à l'heure.. Il me semble que j'ai compté les faces et qu'il y en avait quelque chose comme 66.

Avec func_detail

Alors certes, sur une petite map peu détaillée comme ça, les FPS ne changent pas.. mais imaginez sur une vraie map.. Imaginez bien que l'on vient d'économiser les deux tiers des faces sur cet exemple. Economiser deux tiers de polygones à afficher n'est en général pas de refus... Pour plus de commodité avec les func_detail, je vous conseille de régler, dans les options de Hammer, l'entité bloc par défaut sur func_detail. (Tools > Options > Default SolidEntity Class) Ainsi vous n'aurez qu'a faire CTRL+T ou "Tie To Entity" en selectionnant vos objets pour les tranformer en func_detail (cela va ainsi beaucoup plus vite).

Vous vous demandez peut-être comment j'ai fait pour avoir cette vue avec des traits verts pour délimiter les polygones.. C'est très simple, pour repérer ces endroits anormaux où trop de faces apparaissent, activez la console de Half-Life 2 et tapez y "mat_wireframe 3". Pour cela, je pense que le mode développeur (developer 1) ou le mode de triche (sv_cheats 1) devront être activés.

Alucard_DH a dit :

Une autre précision, il y a 4 modes d'affichage pour le mode Wireframe (commande mat_wireframe x)
* mat_wireframe 0 : Jeu normal sans fil de fer
* mat_wireframe 1 : affiche la découpe des tous les objets en polygones triangulaires (cela affiche également les blocs cachés mais quand même calculés par transparence, ce qui est bien pour voir ce que le vis calcule).
* mat_wireframe 2 : Même que le 1 mais sans la transparence.
* mat_wireframe 3 : Affiche la découpe des objets en mode BSP (là est le piège, ce n'est pas cette découpe là qu'il faut prendre en compte pour le calcul des polygones, le jeu pouvant afficher des polygones carré).

Gardez en mémoire également qu'il ne faut pas trop abuser des func_detail, l'optimisation a ses limites et un abus de func_detail peut entraîner une détérioration drastique des performances. Regardez les cartes fournies avec le SDK pour savoir à peu près combien et où en utiliser. Néanmoins, je n'ai jamais eu de problème en transformant à peu près tout ce qui dépasse des murs et du sol sur mes maps. Usez-donc en et même abusez-donc en.

Pour en savoir plus :
* Ouvrez la map sdk_func_detail.vmf fournie avec le SDK.
* Voyez cette page du Wiki de Valve

II.2.D. La texture Nodraw

Le premier conseil que je tiendrais à donner à n'importe qui faisant des cartes est le plus simple : Toujours utiliser la texture tools/toolsnodraw lors de la création d'un objet. Toujours, toujours ! Cette texture spéciale permet de ne pas tenir compte lors de la compilation des faces sur lesquelles elle est appliquée, tout en considérant tout de même le bloc porteur comme solide.

Pourquoi faire ? Simplement parce que lorsque vous créez une salle par exemple la plupart des faces n'ont absolument pas besoin d'être affichées et calculées. Prenons un exemple simple, une salle cubique avec 4 colonnes. Commençons par faire une salle, un pavé sur lequel on va appliquer l'outil Hollow. (c'est un pavé, hollow n'est donc pas un problème pour moi)
Voici ce que l'on obtient :

Mode wireframe

Comme vous pouvez le voir, il y a un problème. (ah bon, vous ne le voyez pas ?) Si jamais vous n'utilisez pas la texture tool/toolnodraw il va y avoir des faces dessinées pour rien. Regardez, vous allez voir que toutes les faces colorées en rouge/orange n'ont aucun besoin d'être dessinées :

Mode flat

Elles n'ont pas besoin d'être calculées soit parce qu'elles sont cachées darrière un autre bloc comme le plafond pour les faces du dessus ou un autre mur pour celles sur les tranches, mais aussi parce qu'on ne pourra pas voir cette salle de l'extérieur, donc pas besoin de dessiner les faces sur l'extérieur.
Voici ce qui est beaucoup plus correct :

Mode texturé

Ca ne semble pas grand chose, mais l'on économise tout de même beaucoup de faces par cette méthode. Au lieu de 36 faces, le moteur n'en calcule plus que 6, les 6 que le joueur voit, les 4 murs, le sol et le plafond. Toujours pas convaincu(e) ? Alors regardez ce qui se passe lorsque je selectionne toutes les faces ayant la texture nodraw sur une de mes cartes :

7581 faces marked.

Ca vous parrait toujours aussi peu ? Sachant qu'il y a 18346 faces au total sur cette carte, on économise au moteur du jeu le calcul de 41% de ces faces, ce qui est énorme ! Il y a comme ça beaucoup de faces qu'il n'est pas nécessaire de calculer, voyez cette dernière image :

Vue du dessus texturée

Le dessus et le dessous des murs et des colonnes étant collés au sol et au plafond, il n'est pas nécessaire non plus de les faire calculer par le moteur. Voici ce que je pouvais dire sur la texture tools/toolnodraw, très très importante dans le mapping Source.
Je tient à dire que l'exemple ci-dessus, n'est pas forcément très représentatif de l'utilisation de la texture nodraw car les faces situées à l'extérieur de la salle et entre les blocs ne sont de toute façon pas calculées lors de la compilation.. néanmoins, en règle générale, il vaut mieux prévenir que guérir. Sachez de toute façon que nodraw est la texture à mettre sur toute face qui n'est pas censée être visible par le joueur. Exemple ci-dessous, où les faces du dessus sont mises en nodraw car le joueur n'est pas censé voler..

Vue du dessus texturée
Extrait de dm_castle par *MoroeS*

Le plus simple à faire pour ne pas trop vous embêter avec le nodraw c'est de créer tous vos nouveaux blocs avec cette texture puis ne texturer que les faces que le joueur pourra voir. Lorsque vous copiez un bloc déjà existant, retexturez-le en nodraw avant de changer ses textures afin d'être sûr de ne pas générer de faces inutiles.

II.2.E. Le texturage en général

Il y a quelque chose de très logique dans le texturage, et dont presque personne ne se rend compte : l'alignement des textures c'est super super important. Imaginez que vous ayez construit un mur à partir de 4 blocs collés les uns aux autres. Ne me demandez pas où est l'intérêt, c'est juste pour vous expliquer. Voici notre mur, à chaque trait blanc correspond le bord d'un des blocs. Pour bien vous montrer, j'ai selectionné l'un d'entre eux :

Mur composé de 4 blocs

Maintenant, démolissons le bel alignement des textures que j'ai réalisé. C'est exactement ce qui se passe par exemple lorsque vous déplacez des blocs avec l'option Texture Lock > Icone Texture Lock désactivée ! J'ai fait en sorte que les 4 textures ne soient plus du tout alignées les unes aux autres :

Mur composé de 4 blocs différents

Evidemment, ce qui était prévisible se produit, nous avons un mur composé de 4 blocs distincts. 8 triangles en facade.

Mur composé de 4 blocs différents

Mais imaginons maintenant que notre but était justement l'inverse. Un mur qui serait composé de 4 blocs mais qui, à première vue, ressemblerait à un seul bloc. Alors pourquoi avoir 4 faces différentes en facade alors qu'au fond le bloc ne ressemble qu'a une seule ? C'est exactement ce que j'essaie de vous faire comprendre. Aligner les textures TOUT LE TEMPS permet d'éviter ces désagréments, car afficher une texture alignée a côté d'une texture non alignée, c'est comme afficher une texture à côté d'une autre différente, et donc afficher une face à côté d'une autre. Tandis que si la texture est la même et qu'elle est alignée sur toutes les faces qui sont côte à côte, BSP va considérer toutes les faces comme "fusionnables" et va donc les rassembler pour n'en faire plus qu'une seule.

Ci-dessous exactement le même mur composé de 4 blocs mais dont les 4 faces ont été fusionnées car la texture est alignée :

Mur composé de 4 blocs identiques

Gain de faces, gain de calcul, gain de FPS. C'est tout simple, il faut absolument aligner vos textures.

Le conseil du fûté :

Evidemment, aligner toutes ses textures une par une c'est vite lassant.. Pour éviter cela, il existe une petite astuce très pratique et beaucoup plus rapide à mettre en oeuvre. A chaque fois que vous terminez une partie de votre map et que vous décidez de la compiler ou alors une fois votre map terminée suivez les étapes suivantes :

* Ouvrez l'outil Toogle Texture Application (Shift+A) puis cliquez sur Browse pour ouvrir le navigateur de textures.
* Cochez la case Only Used Textures en bas à gauche. Vous n'aurez plus que les textures que vous avez utilisées.
* Dans ces textures, il y en a certaines qui se répêtent et d'autres pas. J'entend pas là, il y a des textures qu'il n'est absolument pas nécessaire d'aligner puisqu'elles se répêtent en mosaïque sans problème (c'est souvent le cas des textures de sable, d'herbe, de brique, d'eau ou autre).
* Selectionnez la première de ces textures mosaïques et cliquez sur le bouton Mark en bas à droite. Ceci va sélectionner toutes vos faces ayant cette texture.
* Une fois revenu dans l'outil Toggle Texture Application vous n'aurez plus qu'à remettre les valeurs de "Texture Shift" à X = 0 et Y = 0 et, tant qu'à faire, les valeurs de Texture scale au même nombre. Ceci aura pour effet de réaligner toutes vos textures les unes aux autres.
* Désselectionnez toutes les faces et recommencez avec la texture mosaïque suivante jusqu'à ce qu'il n'en reste plus.

Une fois ceci fait, vous aurez la plupart de vos textures alignées les unes aux autres sans grand effort et votre map gagnera en FPS.
Dans la pratique, si vous sélectionnez toutes vos faces ayant une certaine texture mosaïque et que vous obtenez ça cela veut dire que vous devez remettre les valeurs comme ceci.

Autre petit détail vis-à-vis des textures c'est qu'à chaque fois qu'une texture "se repête" une nouvelle face est créée.. Je m'explique : si vous avez un mur de 1024 unités de long et 256 unités de haut et que vous apposez dessus une texture de 256x256 pixels, le mur sera découpé en 4 faces distinctes. Simplement parce qu'à chaque fois qu'on arrive au moment ou la texture se repête une nouvelle fois sur la même face, il faut une découpe..
Ce genre de petit détail peut générer des découpes ressemblant à celles-ci :
(c'est particulièrement vrai sur les grandes structures et sur les grandes surfaces)
Néanmoins cela reste à vérifier car il semble que cela ne le fasse pas dans tous les cas...

Découpes normales des textures

II.2.F. La grille de Hammer

Je vais juste vous faire un petit speech sur la grille de Hammer. Juste pour vous dire que s'il y a une grille dans Hammer, ce n'est pas pour rien :D Je vois plein de mappeurs qui mappent sans la grille et je peux vous dire que ce n'est pas du tout du tout une bonne idée. Premièrement, il est tout à fait conseillé de garder cette grille pour aligner PARFAITEMENT chaque bloc avec chaque autre bloc. J'ai déjà vu plein de maps où tous les blocs étaient décalés d'une ou deux unités, enchevetrés les uns dans les autres, laissant des espaces entre chaque... l'anarchie pour une map Half-Life 2. Voici un exemple de décalage de moins d'un dixième d'unité qui suffit amplement à fausser les calculs de VIS :

Exemple de décalage de moins d'un dixième d'unité

Sachez bien que lors de la compilation, VIS se contre-fout de savoir si, oui ou non, vous vouliez vraiment mettre des espaces entre vos blocs et s'il en trouve, il considèrera que votre salle se poursuit dans cet espace de quelques pixels, et adieu l'optimisation. Le pire ennemi du mappeur c'est le manque de précision.. le manque de rigueur dans la disposition des blocs.. l'envie de tout faire "comme ça vient" sans réfléchir à un "plan de construction" quelconque..

Autre chose, sachez que, quoi qu'il arrive, BSP va découper tous vos blocs toutes les 1024 unités. Peu importe si c'est au beau milieu d'un truc super détaillé, tout sera sauvagement découpé en suivant les lignes vertes (et les deux lignes bleues) de la grille de Hammer. C'est également pour cela qu'il est important d'afficher la grille, car construire un morceau d'architecture fort détaillé sur une telle ligne risque de doubler le nombre de faces.. et ça, c'est pas vraiment compatible avec l'optimisation. Regardez le travail :

Coupure des 1024

Coupure des 1024

Faites donc bien attention à ces petits détails qui gachent la vie.


II.3. Limiter la visibilité

Plutôt que directement simplifier la géométrie, il est également possible de tout simplement la cacher, quand on le désire. Evidemment, ça n'est pas toujours possible habilement, c'est pour cela qu'il vaut mieux appliquer un peu toutes les différentes méthodes. De mon côté, les méthodes suivantes fonctionnent plutôt bien. Nous allons parler de func_occluder, qui cache les props ; de func_areaportal et de func_areaportalwindow, qui cachent les props et les brushes.. etc..

II.3.A. Les func_occluders

Directement en relation avec la visibilité des props (prop_static, prop_physics, etc... aussi appelés models), voici venir les func_occluder. Les occluders sont des blocs qui permettent de contrôler la visibilité derrière eux. Ils ne jouent que sur l'apparition et la disparition des Props ne peuvent pas se situer en dehors du monde mais ont l'avantage de pouvoir être activés/désactivés durant une partie.

Les func_occluder sont créés avec un brush de type block. Il doivent avoir la texture tools/toolsoccluder uniquement sur les faces qui doivent cacher les props et la texture tools/toolsnodraw sur celles qui n'ont aucun effet. Si des blocs possèdent cette texture sans être des func_occluder, cela dégradera les performances.

Note: Trop d'occluders tue les occluders. Chaque func_occluder doit être placé de façon à cacher suffisemment de models. S'il s'avèrait qu'ils empêchent un grand nombre de props d'être affichés, alors ils amélioreraient les performances. Sinon, ils pourraient s'avérer plus gourmants en ressources que d'afficher tout simplement les props. Pour savoir si vos occluders sont utiles, affichez les FPS depuis la console (cl_showfps 2) et comparez la vitesse d'affichage avant et après avoir tapé r_occlusion 0 dans la console. Ceci désactive les occluders. (tapez "r_occlusion 1" pour les réactiver)

Exemple d'occluders

Sur cette image, l'occluder permet de cacher tout le mobilier de la salle située derrière les deux portes. Lorsque les portes s'ouvrent, l'occluder est désactivé (par un output de la porte OnOpen > mon_occluder > Disable) et réactivé lorsque la porte se referme. (OnFullyClosed > mon_occluder > Enable).

Un autre exemple, prenons la map dod_campazzo (magnifique map réalisée par MoroeS) dont je me suis chargé de l'optimisation (comme j'ai pu). La structure de la map fait qu'il est très compliqué d'utiliser les techniques conventionnelles (hints et découpage propre des leafs). J'ai alors allégé l'affichage de la map grâce à des func_occluder placés dans des endroits "stratégiques" de la map. Des endroits où il n'est pas vraiment possible de cacher la visibilité efficacement et où des dizaines de prop_static étaient affichés alors que non-visibles. C'est le cas des maisons qui bordent les rues. Il est très difficile de forcer VIS à ne pas calculer ce qui se trouve dans la rue suivant le coin d'un bâtiment, surtout quand les bâtiments en question sont de forme diverses et variées. J'ai alors "rusé" en plaçant des func_occluder à l'intérieur des bâtiments qu'il n'est pas possible de visiter. De cette façon, tout les models qui se trouvent derrière le bâtiment ne sont plus affichés.
Voici comment est placé l'un des func_occluder :

Occluder sur dod_campazzo dans hammer

Et voici quel est le gain une fois dans le jeu. Tous les props dont le contour est affiché en vert ont été cachés par l'occluder.. ce qui en fait un certain nombre, comme vous pouvez le constater sur l'image suivante (le gain de performance est d'environ 10 FPS à cet endroit) :

Occluder sur dod_campazzo ingame

En règle générale, les occluders sont très utiles couplés à un mur en displacement, un mur partiellement détruit, ou à tout autre obstacle qui bloque partiellement la visibilité. Notez également qu'ils peuvent être également placés dans un sol ou/et un plafond d'un bâtiment de plusieurs étages pour cacher les models situés à l'étage du dessous/dessus, s'il s'averait que VIS ne s'en charge pas tout seul.

Pour en savoir plus sur les occluders :
* Ouvrez la map sdk_occluder.vmf fournie avec le SDK.
* Voyez cette page du Wiki de Valve

II.3.B. Les func_areaportal

Lorsque vous construisez votre map, comme nous l'avons vu un peu plus avant, VIS découpe tout en vis-leafs pour calculer quelle pièce est visible d'un endroit à un autre. Le problème c'est que vous n'êtes pas sans savoir que tout ceci est très approximatif et que, par exemple, une toute petite ouverture donnant sur un extérieur giganstesque aura pour effet de faire calculer au moteur tout l'extérieur visible depuis la pièce courante.. autant dire, tout. Vous n'êtes pas non plus sans savoir que les portes par exemples ne sont pas considérées comme des solides par VIS mais comme des entités (logique me direz-vous). Ce qui fait qu'en vous trouvant devant une porte fermée, tout ce qui se trouve derrière est calculé quand même.. quel malheur.

II.3.B.a Avec l'aide d'une porte

Et bien, dites "Hourra" pour les func_areaportal car non seulement il vont résoudre le premier problème, mais également le second dans la foulée. Vous allez voir, en plus c'est super simple à mettre en oeuvre. J'ai repris notre jolie map du début, avec ces fameuses trois salles qui se suivent en "L" avec notre super ciel en guise de plafond. J'ai rajouté une porte pour séparer une salle d'une autre et j'ai fourré plein de models dans la deuxième salle pour tester. Lorsque le jeu s'est lancé, VIS a considéré que la porte n'existait pas, et donc, tout ce qui se trouvait derrière la porte fermée était calculé. Et c'est là que les func_areaportal sont super astucieux.

En gros, un func_areaportal peut être utilisé de deux façons différentes. Avec la première, il doit toujours être couplé à une porte, doit faire la même taille qu'elle (conseillé) et avoir dans ses propriétés le champ Name of Linked Door contenant le nom de la porte. En fait, c'est une sorte de trigger qui va permettre deux choses très puissantes :

  • Lorsque la porte est fermée, il va oublier tout ce qui se trouve derrière, en totalité. C'est à dire toute la pièce. (seulement s'il n'y a aucun autre moyen que la porte de voir cette salle)
  • Lorsque la porte est ouverte, il ne va pas comme on aurait pu le penser, dessiner toute la pièce qui se trouve derrière, mais uniquement ce qui est visible par l'ouverture de la porte ! Ce qui est franchement énorme vous l'avouerez :D

Je sais très bien que vu comme ça, ça n'est pas très parlant, alors je n'ai pas bien sûr pas oublié les petits screenshots qui vont avec :

La porte et son func_areaportal de la même taille
La porte et l'areaportal

Le résultat quand la porte est fermée
la porte fermée

Et quand la porte est ouverte
La porte ouverte

Et enfin quand on regarde seulement par un bout de l'ouverture
La porte de côté

II.3.B.b Sans l'aide d'une porte

La deuxième méthode, figurez-vous que c'est exactement la même, mais sans la porte. Comment ça ? Ben facile, mettez le même func_areaportal, ne mettez rien dans Name of Linked Door et positionnez Initial State sur Open, et la magie opère. Cela fait le même effet que s'il y avait une porte, mais tout le temps ouverte. Exactement la même chose que sur le quatrième screen ci-dessus. C'est très utile à placer par exemple au bout d'un couloir qui donne sur un grand espace. Sur l'image qui suit, on voit très bien comment cela fonctionne. Les deux traits blancs montrent le champ de vision du joueur (en bleu) à travers l'areaportal. Tout ce qui se situe dans le triangle bleu sera calculé car directement visible à travers l'ouverture tandis que tout le reste sera ignoré car hors de l'areaportal et situé derrière un mur..

Schéma angle de vision

II.3.B.c areaportal brush doesn't touch two areas

Il existe évidemment des restictions à l'utilisation des func_areaportal, notamment le fait qu'ils doivent impérativement séparer 2 endroits clos. Pas 1, ni 3, ni 4, mais 2. De plus, ils ne sont pas transparents comme les hints qui sont traités une fois pendant la compilation et basta. Ils nécessitent des calculs de visibilité constants une fois dans le jeu. Heureusement, bien utilisés, ils sont beaucoup plus bénéfiques que le temps nécessaire à les calculer. Si par malheur vous n'aviez pas placé correctement vos func_areaportal, vous auriez un message d'erreur à la compilation ressemblant à quelque chose comme :
* Brush X: areaportal brush doesn't touch two areas
Malheureusement, cette erreur est assez dure à situer, heureusement que la même méthode que pour les leaks peut être utilisée, à savoir charger le pointfile (Map > Load Pointfile). Je vais tenter de vous expliquer pourquoi vous avez cette erreur.

Avec les func_areaportal, le truc c'est de faire en sorte que chaque côté de l'areaportal scelle des espaces clos.. hermétiques.. Explication avec des petits schémas. Sur le schéma suivant, on peut voir qu'il est possible de passer plusieurs fois par l'areaportal, dans le même sens.. Donc, chaque côté de l'areaportal n'est en fait composé que d'un seul espace clos. C'est contraire à l'esprit "areaportal".

Espaces pas clos

Sur ce deuxième schéma, nous sommes exactement dans le même cas de figure, sauf que nous avons désormais deux areaportal (areaportaux ?) distincts. Ces func_areaportal étant considérés comme solides, nous nous retrouvons avec deux espaces clos de chaque côté. Désormais, il n'y a plus aucun problème, chaque areaportal ne peut être traversé dans le même sens qu'une fois à la suite. (seulement si tout est fermé hermétiquement, et que les areaportal touchent les murs et le plafond/sol hermétiquement)

Espaces clos

Espaces clos

Evidemment, sur ce dernier schéma, tout est clos dès le départ et nous n'avons donc aucun problème. Retenez juste que, si votre niveau décrit une boucle, vous devrez forcément utiliser au moins 2 func_areaportal pour créer 2 espaces clos. Si jamais vous obtenez l'erreur * Brush X: areaportal brush doesn't touch two areas, il vous suffira de charger le Pointfile (Map > Load Pointfile) et de regarder la boucle décrite par un trait rouge. Elle va vous montrer pourquoi votre func_areaportal foire, c'est à dire qu'elle va vous décrire par quel chemin il est possible de passer plusieurs fois dans votre areaportal dans le même sens..

Enfin, il existe une dernière solution à ce problème : vous avez mis un func_areaportal dans l'eau.. Oui je sais, c'est débile, mais on ne peut pas mettre d'areaportal qui traverse la surface d'un plan d'eau. Il faut alors le découper en deux areaportal distincts.. La partie au dessus de l'eau, et la partie au dessous de l'eau.. Sans ça, vous aurez des reflets très.. étranges.. à la surface de votre eau.

II.3.B.d Mise en garde

Tiré du site www.planetquake.com :

"En utilisant les techniques d'optimisation dites "normales" de VIS, tout ce qui est dessiné à un moment et à un endroit précis est déjà connu par avance par le moteur. C'est une gestion statique. Avec les areaportals, le moteur doit calculer en temps réel quoi dessiner depuis chaque position du joueur à chaque fois qu'il croise la vue d'un func_areaportal. Quand vous avez plusieurs de ces areaportals, le moteur doit calculer encore plus dur pour afficher ce qu'il faut. Pour ceux qui sont assez logiques, le nombre de modes d'affichage différent est 2N où N est le nombre d'areaportals en vue. Donc, si une pièce possède 2 areaportals, cela fait 4 options différentes, et avec 4 areaportals cela fait 16... Comme vous pouvez le voir, cela devient vite très goumand en calculs pour le moteur dès qu'il commence à y avoir beaucoup d'areaportals.

Dans nos tests, nous avons remarqué une augmentation notable de la charge du processeur du serveur sur les maps utilisant des func_areaportal. Nous avons également remarqué une perte de fluidité qui semble devenir de pire en pire avec plus de joueurs et avec la durée durant laquelle la carte est jouée. En imaginant ce que le serveur a à gérer, c'est tout à fait compréhensible.." [imaginez 16 joueurs dans une salle avec 4 areaportals.. ça fait 16x24 champs de visions à calculer.. soit 256 !]

Autrement dit, lorsque vous êtes sur votre map solo avec vos 15 areaportals dans la même pièce (un à chaque fenêtre de maison, comme dans les maps "coast") c'est votre ordinateur qui supporte les calculs.. bien sûr pour lui il n'y a rien de plus simple.. et encore, parfois il a déjà du mal à s'en sortir. Alors maintenant, imaginez que votre PC doive gérer 8 fois Half-Life 2 en même temps ! Je ne pense pas qu'il aimerait trop, et bien c'est exactement la même chose pour le serveur qui hebergera votre map si elle est multijoueurs.

Tidjey à dit :
Bravo, ton tuto, est très bien fait mais j'ai une remarque a propos des areaportals.
En regardant les maps officielles de Day of Defeat Source, on peut voir qu'ils en ont mis partout, meme dans les grands couloirs. Sur dod_flash (petite carte) il y en a 42 au total et à certains endroits, on peut voir à travers 4 areaportals qui se suivent.
Donc pour ta mise en garde (qui est également sur le wiki de Valve) comme quoi en abuser serait trop lourd pour le serveur, peut-on la prendre à la légère ?

NDLR: Je n'ai pas encore d'explications à apporter à ceci.. je n'en sais pas plus sur les areaportals, il faudrait procéder à des tests grandeur nature pour se faire une idée concrète..

II.3.B.e Quelques commandes

Pour tester vos areaportal il y a plusieurs commandes console qui peuvent s'avérer très utiles (surtout en conjonction avec la commande mat_wireframe sinon ça n'a aucun interêt)

  • r_DrawPortals : Dessine les portails, ce qu'ils cachent et ce qu'ils laissent passer.
  • r_PortalsOpenAll : Force l'ouverture de tous les areaportal.
  • r_PortalsCloseAll : Force la fermeture de tous les areaportal, utile pour voir lesquels fonctionnent ou pas.

Pour en savoir plus sur les areaportal :
* Voyez cette page du Wiki de Valve.

II.3.C. Les func_areaportalwindow

Dans le même esprit que les func_areaportal voici les func_areaportalwindow. Le nom semble le même, mais l'utilisation est tout autre ! Voici l'idée. Imaginez que vous avez une salle avec des fenêtres donnant sur l'extérieur. Cet extérieur est assez lumineux vis-à-vis de l'intérieur de votre salle. Ce qui semblerait donc logique serait que ces fenêtres vous éblouissent.. facile a faire avec des env_lightglow.. mais tant qu'à faire, pourquoi ne pas faire également que, puisque vous êtes ébloui, ce qui est dehors ne soit pas dessiné ? Voilà un des intérêts de nos func_areaportalwindow.

Tout comme les func_areaportal, ces derniers ont besoin d'un autre bloc pour fonctionner. Ce coup-ci, c'est d'un func_brush, bloc qui va servir de mur séparatoire. Le principe, c'est de faire apparaître/disparaître progressivement un mur selon la distance à laquelle le joueur se trouve. dans notre cas, nous avons tout intérêt à faire apparaître un mur blanc, blanc comme la lumière éblouissante. Evidemment, si dehors il fait nuit, on ne va pas faire apparaître un mur blanc.. mais un mur noir.. Nous allons donc créer un bloc de la taille de l'ouverture avec la texture qui nous intéresse puis le transformer en func_brush. Appliquez ensuite les options suivantes :

  • Name : window
  • Start Disabled : No
  • Solidity : Never Solid
  • Solid BSP : No

La deuxième étape, c'est de créer le bloc de la même taille qui va correspondre à notre func_areaportalwindow, faites donc déjà cela et mettre lui les propriétés suivantes :

  • Rendered Window : window
  • Fade Start Distance : Mettez la distance à partir de laquelle le mur va commencer à apparaître. A cette valeur, le mur sera transparent selon la valeur entrée dans le champ Translucency Limit
  • End Start Distance : Mettez la distance à partir de laquelle le mur aura apparu et sera devenu solide. (il cachera alors tout ce qui est derrière lui)
  • Translucency Limit : Le niveau de la transparence du mur quand on aura atteint la distance spécifiée dans Fade Start Distance. Une valeur de 0.0 à 1.0 où 0.0 représente la transparence totale et 1.0 aucun changement dans l'opacité.

Et voilà, vous aurez une fenêtre où, de loin, on verra un carré blanc éclatant et rien ne sera dessiné derrière, et plus vous vous en approcherez, plus le bloc blanc deviendra transparent et ce qui est derrière apparaîtra au fur et à mesure. Vous savez, c'est le même effet que dans Half-Life 2 sur la côte avec le buggy, dans on entre et sort des tunnels. Voilà comment optimiser un peu plus vos maps. Quelques images pour vous expliquer tout cela ?

L'ouverture vue de loin. Un mur et rien de dessiné derrière
De loin

Vue de plus près. Un mur translucide ou tout réapparaît derrière
De plus près

Vue de tout pret, l'ouverture est transparente
De très près


II.4. D'autres techniques

Impossibles à classer dans une catégorie précise, il existe de nombreuses autres petites techniques qui peuvent ajouter de petites touches d'optimisation à vos maps. Certes, elles ne feront pas tout, mais un petit plus est toujours le bienvenu dans la course aux FPS ! Voici donc quelques unes des techniques que je connais :

II.4.A. Les func_lod

Dans la même lignée de les func_detail, il y a également les func_lod. D'une certaine manière, c'est la même chose mais en version entité (donc ignoré par BSP) et dôté d'un système de disparition au bout d'une certaine distance. Ceci peut être à appliqué à n'importe quel bloc d'architecture de Hammer.

Un comptoir, une torche, une grille ou autre petit objet créé à partir de brushes est un bon candidat pour devenir un func_lod. J'ai par exemple décidé de faire disparaitre les torches à l'intérieur d'un bâtiment ainsi que les bordures de fenêtres lorsque l'on est plutôt loin de celui-ci. Pensez-y, cela peut-être très salvateur.

Gardez en mémoire également que, tout comme les func_detail, il ne faut pas trop abuser des func_lod. L'optimisation a ses limites et un abus de func_lod peut entraîner une détérioration drastique des performances. Regardez les cartes fournies avec le SDK pour savoir à peu près combien et où en utiliser. D'une manière générale, retenez que ce n'est pas conseillé pour l'architecture d'une map, mais plus pour de petits objets sans grande importance.

II.4.B. Les Props

Depuis Half-Life 1, les petits objets comme les plus gros qui sont considérés comme plus détaillés que la normale ne sont plus composés de brushes (blocs dans Hammer : cubes, cylindres, etc.) Ce sont maintenant des modèles 3D créés depuis un autre logiciel tel que XSI, 3DSMax ou encore Maya.. Comme indiqué sur le Wiki de Valve, les Props devraient être utilisés pour les objets suivants :

  • Les petits objets du monde (cannettes, meubles, ordinateurs, portes, etc.).
  • Les gros objets qui demandent un haut niveau de détail [...].
  • Tout ce qui nécessite d'être déplacé et/ou soumis aux lois de la physique. (ramassé, lancé, poussé, cassé, etc).
  • Tout ce qui est "verdure" (herbe, plantes, etc.).
  • Les objets qui vont apparaître de nombreuses fois dans le niveau.

Bien que tous ces objets nécessitent beaucoup moins de ressources que le reste des objets en brushes, il faut tout de même faire attention à ne pas dépasser certaines limites. On peut trouver sur les pages du VERC Collective de Valve les limites suivantes à respecter pour garder de bonnes performances :

  • prop_detail : Des dizaines de milliers
  • prop_static : Des milliers
  • prop_dynamic : Des centaines
  • prop_physics : Des dizaines à des centaines
  • prop_ragdoll : Moins de 10

Néanmoins, il y a des moyens d'augmenter ces limites, ou, tout du moins, d'en mettre plus que la normale sans faire pour autant ramer plus. Prenons pour cette partie une de mes cartes. Elle se déroule dans un bâtiment, mon IUT, et est composée de couloirs et de salles. Prenons pour exemple une des salles de classe et plus particulièrement, les néons au plafond :

Salle de classe

Ces néons au plafond sont fixes, ils ne peuvent pas tomber ni sortir de cette salle. Lorsque vous vous trouvez dans la salle d'à côté ou dans le couloir, il n'est absolument pas nécessaire de les afficher. Or, à cause de la largesse de VIS lors de son calcul de la découpe pour la visibilité, cela peut très bien arriver..
C'est pour cela qu'il existe d'autres méthodes dont la suivante :

la salle mesure environ 280x280 et est entourée de murs et de portes donnant sur un couloir. Or, du couloir on a absolument pas besoin de voir les néons qui se trouvent dans cette salle, à part en se trouvant devant les portes. La distance maximale à laquelle on peut voir les néons du fond (fléchés) c'est le bord du couloir (fléché aussi). La distance séparant ces deux points est 340. On va alors régler plusieurs choses dans les propriétés des prop_static.

  • Premièrement, si vous vous fichez qu'en tirant sur ces néons ça fasse un bruit de verre, mettez collision sur Not Solid, ça sera ça de moins à gérer pour le moteur physique.
  • Deuxièmement, mettez Disable Shadows sur Yes parce qu'il n'est pas nécessaire de faire apparaître des ombres sur une lumière..
  • Ensuite, on va régler Start Fade Dist/Pixels sur la distance maximale à laquelle on peut le voir, donc 340. Ce qui signifie qu'a partir de 340 unités, le néon va commencer à disparaître.
  • Obligatoirement, il faudra ensuite entrer une autre valeur dans End Fade Dist/Pixels, une valeur plus élevée. Elle correspondra à la distance à partir de laquel le néon aura totalement disparu. Entre les deux distances, le néon disparaîtra au fur et à mesure. J'ai par habitude de le régler sur environ 256 de plus que le Start Fade Dist/Pixels pour que la disparition ne soit pas trop violente AU CAS OU l'on arrive à voir le model quand même. Donc au final, environ 600.
  • Puis, si vous êtes absolument maniaque, vous pouvez également régler les options Minimum DX Level et Maximum DX Level. Ces deux options définissent la version minimum et/ou maximum de DirectX requise pour afficher ce prop. Utile si vous avez pitié des cartes graphiques d'ancienne génération.

Cette méthode est assez efficace mais il en existe d'autres. Retenez juste que tout prop ne pouvant pas être atteint devrait être Non-Solide et tout prop ne se déplaçant pas devrait disparaître quand on ne le voit plus. Dans le même genre, les petits objets comme les papiers, canettes, bouteilles, etc.. devraient disparaître assez rapidement, comme à 512 unités et il n'est pas souvent nécessaire de leur faire projetter des ombres. Vous pouvez également utiliser le flag nommé Debris - don't collide with the player or other debris si c'est un petit prop_physics. Non seulement ça va éviter des calculs de collisions complexes entre ces petits objets, mais cela va également faire en sorte que le joueur passe à travers d'eux. Ce qui est plutôt pratique lorsque vous disposez des petits objets par terre, cela évite des blocages du joueur par une canette ou autres désagréments.

Pour en savoir plus sur les props :
* Ouvrez les maps solo et deathmatch fournies avec le SDK.
* Voyez cette page du Wiki de Valve

II.4.C. La lightmap

Tiré directement du site officiel :

Le moteur Source utilise des données de lightmap pour simuler la lumière et les ombres sur les brushes. L'augmentation de cette lightmap procure des ombres plus fines, mais demande plus de mémoire. La densité et la qualité de la lightmap peuvent être altérées pour améliorer les performances.

Ces réglages se font depuis l'outil Texture Application. La taille de la lightmap est mesurée en luxels par unités. Les valeurs plus faibles équivalent à des résolutions plus élevées. L'échelle par défaut est de 16 luxels par unité. Une plus grande résolution de la lightmap augmente le temps que RAD prend pour compiler le niveau. Vous pouvez diminuer ce temps en diminuant la demande en mémoire de la lumière. Il suffit de diminuer la résolution de la lightmap sur les faces qui n'ont pas besoin d'un grand niveau de détail au niveau des ombres. Les bons candidats à des grandes échelles de la lightmap sont les surfaces complètement dans l'ombre, complètement illuminées ou loin de tout endroit où le joueur peut se rendre. [de même, les bons candidats à une petite échelle de la lightmap sont les zones où vous voulez que les ombres soient très belles et bien fines]

Lightmap

Pour avoir un aperçu de la lightmap de votre carte, réglez le type de vue 3D sur 3D Lightmap Grid.

Pour en savoir plus sur la lightmap :
* Ouvrez la map sdk_lightmaps.vmf fournie avec le SDK.
* Voyez cette page du Wiki de Valve.

II.4.D. Les displacements

Je ne suis pas ici pour vous expliquer ce qu'est un displacement, néanmoins, je vous rapellerai certaines petites choses qu'il est bon de savoir sur eux.

  • Premièrement, ils ne sont pas considérés commes des brushes et par conséquent VIS les ignore lors de la compilation.
  • Deuxièmement ils sont logiquement beaucoup moins gourmant que des brushes normaux et un grand nombre d'entre eux peuvent être utilisés au sein d'une même map. Personnellement j'en utilise jusqu'à une bonne centaine sur ma map dm_mine et les FPS sont largement au dessus de 100.
  • Troisièmement, ils ne peuvent en AUCUN CAS être convertis en entités et encore moins en func_detail, oubliez donc cela.
  • Quatrièment, lorsque vous créez un displacement, veillez bien à ne selectionner que les faces qui vous intéressent ! En l'occurence, c'est souvent la face du dessus pour un terrain et une des faces des côtés pour un mur. Il est très rare, voire impossible que vous ayez besoin des 6 faces d'un bloc en même temps !

Gectou4 a dit :

Les brushes displacés sont très utiles mais ont de nombreux défaut. Notamment à grande échelle. Il faut aussi savoir qu'outre le fait qu'il ne puissent être mis dans une entité ou transformés en entité il laissent toutefois passer la lumière. Veiller donc à placer un brush avec la texture tools/toolblocklight qui stoppera toute lumière. Dans le cadre d'un displacement complexe n'hésitez pas à placer un brush avec la texture tools/toolblack derrière les jonction des displacements qui laisseraient quelque problème de leaf (petite étincelles blanches sur les pourtours qui peuvent être supprimés par un sew quand cela est possible).
Un displacement étendu se doit d'être découpé. Découpé au minimum en 512. Vous aurez ainsi des régions de displacements qui sont généralement plus contrôlables et peuvent être affinées. De plus, cette méthode de découpe évite que toute l'étendue displacée ne soit calculé en même temps.

Tiré de ce tuto par Gectou4

Pour en savoir plus sur les displacements :
* Voyez cette page du Wiki de Valve

II.4.E. Les prop_detail

De mon côté, je n'ai jamais vraiment réussi à insérer de prop_detail sur ma map, et je ne comprends pas vraiment en quoi ça consiste. Les seuls props_detail que je connaisse, sont ceux générés automatiquement par certaines textures pour former de l'herbe par exemple. Et c'est justement de ça que je comptais parler. Cette herbe, aussi sympa soit-elle, est parfois bien lourde à gérer pour le moteur. Et ce malgré le fait que ce ne soient que de vulgaires sprites dans la plupart des cas. Par exemple, la texture nature/benddirtdirt001a apposée sur un bloc qui n'est pas un displacement va générer énormément d'herbe au mètre carré. Voyez plutôt l'impact sur les FPS... (c'est compilé sans le VIS et le RAD je vous rassure)

Herbe

Alors certes, cela fait plutôt réaliste, mais en attendant, voyez les performances si je supprime cette herbe... (nous verrons comment la supprimer avec une commande console plus tard dans le tutorial)

Sans herbe

Comme vous pouvez le constater, il y a tout de même un bonne différence entre les deux screens. Certes, le premier est plus joli, mais le deuxième culmine à 18 FPS de plus tout de même.. Il faut donc apprendre à ne pas être trop gourmant avec l'herbe.. surtout sur de grandes étendues. Arrangez-vous pour en faire de petites taches par-ci par-là, le tout habillement maquillé derrière un peu de relief :)

Herbe clairsemée

II.4.F. Les light_dynamic

Je n'ai pas spécialement grand chose à dire sur les light_dynamic. Ce qu'il faut savoir, c'est que se sont des sources de lumières pour lesquelles les ombres seront calculées en temps réel, c'est à dire dans le jeu.. Ce qui signifie que cela sera particulièrement lourd à gérer pour le moteur, surtout au bout d'un certain nombre de lumières dynamiques.. J'ai d'ailleurs fait un petit test ci-dessous.. Une salle carrée, un displacement et 4 light_dynamic qui éclairent 4 NPCs (Eli, Alyx, Barney et Breen). Avec si peu de détail dans ma salle, je me retrouve a si peu de FPS :

Light_dynamic, adieu FPS

Et maintenant si j'éteint ces lumières dynamiques :

Light_dynamic OFF

Oui, 64 FPS pour afficher si peu de choses, c'est très peu. On voit bien que les light_dynamic c'est pas si terrible.. si au bout de 4 le moteur commence à flancher et perdre une quarantaine de FPS, c'est pas très recommandé niveau optimisation.

Une autre chose à savoir également, et qui peut causer des ralentissements parfois incompris, c'est que les point_lightspot sont également des lumières dynamiques ! La seule chose qui diffère c'est le fait qu'avec cette entité-ci, un halo de lumière du plus bel effet est automatiquement ajouté à votre spot. Vous allez me dire, c'est dommage qu'ils n'aient pas prévu ça pour le light_spot tout bêtement.. et effectivement, c'est très idiot je trouve. Néanmoins, vous pouvez toujours coupler un point_lightspot et un light_spot puis, dans les flags du point_lightspot, cocher la case No Dynamic Light. Vous aurez ainsi uniquement ce joli halo de lumière et la lumière non dynamique du light_spot. (n'oubliez pas de régler les angles du point_lightspot similairement à ceux du light_spot :D)

J'ai également remarqué que faire clignoter des light ou light_spot basiques à des endroits assez complexes générait des pics d'utilisation du moteur et par conséquent, des saccades assez marquées et des chutes de FPS à chaque clignotement de la lumière. Certes, l'endroit était assez complexe, mais il n'y avait qu'une seule light aussi..

II.4.G. La texture blocklight

Exactement comme son nom l'indique, la texture tools/toolblocklight permet d'absorber toute lumière la touchant et l'empêche d'aller plus loin. Elle est très utile dans des situations où vous souhaitez jouer sur la lumière pour créer des effets que vous n'arrivez pas à faire naturellement. Mais elle est également très utile pour bloquer la lumière partout où elle n'est pas nécessaire. Cela évite à RAD de calculer de l'éclairage pour rien à des endroits où cela ne sert à rien.. Par exemple, vous voulez créer un trou très sombre, mettez donc un bloc texturé avec la texture tools/toolblocklight en plein milieu et la lumière n'ira jamais plus loin que ce bloc. Petit exemple du fonctionnement, placez tout simplement un bloc avec la texture blocklight dans un endroit lumineux, et voilà le résultat :

Dans Hammer

Dans Half-Life

Les displacements sont les meilleurs candidats pour ce type de traitement, du fait de leur propriété à laisser passer la lumière. C'est très con, mais c'est comme ça.. Pensez-y.

II.4.H. L'overlap : à éviter

L'overlap est tout simplement le nom anglais pour la superposition de blocs et leur inter-pénétration (ce mot vous fait rire ?). En théorie, il ne faut JAMAIS que deux blocs se retrouvent l'un dans l'autre ou que leurs faces soient superposées (quand cela arrive, on voit leur textures changer sans arrêt). L'overlap entraîne non seulement l'affiche de polygones supplémentaires et inutiles, mais peut également occasionnellement causer des problèmes dit de "Z-fighting" sur plusieurs faces dont le moteur a du mal à determiner laquelle montrer et laquelle cacher..

Ce n'est pas bien méchant à la base, mais en combinant ce problème mineur avec d'autres problèmes mineurs, on en vient à ralentir le travail de moteur du jeu, et par conséquent à perdre de précieux FPS. Voici l'aspect des overlaps dans Hammer :

Overlaps

II.4.I. L'eau : un gouffre à FPS

Ce n'est un secret pour personne, l'eau sous le moteur d'Half-Life 2 est un gouffre à FPS. Non seulement elle prend énormément de temps à être affichée en temps qu'eau, mais elle prend également du temps pour dessiner ses shaders, pour dessiner ses reflets et en plus pour adapter le reste du monde à ses contours.. Autrement dit, moins il y en a, mieux c'est.
Dans les maps multijoueurs en particulier, il ne faut surtout pas en abuser, car cela entraine beaucoup de lag. Voici quelques techniques pour réduire le nombre de FPS perdus :

  • Si vous perdez vraiment beaucoup de FPS, changez la texture de l'eau pour une texture ayant "cheap" ou "dx70" dans le nom. C'est certes moins beau, mais c'est également beaucoup plus économique.
  • Utilisez l'entité water_lod_control. Selon l'aide intégrée à Hammer, cette entité sert à "contrôler la caractéristique "basse résolution" de n'importe quelle eau sur la map. Si vous avez de l'eau sur votre map, alors cette entité est requise." La valeur Start Transition to Cheap Water determine la distance à partir de laquelle l'eau devient moins belle, et la valeur End Transition to Cheap Water la distance à partir de laquelle l'eau est définitivement en basse résolution.
    Je vous avouerai que, personnellement, je mets cette entité avec une valeur souvent de 512-1024 mais je ne vois vraiment aucune différence. (ce qui est peut-être dû à la puissance de l'ordinateur sur lequel la map est executée) Dans un sens c'est peut-être bien, car l'eau est peut-être moins complexe à gérer mais pas moins belle, mais dans un autre sens, ça fonctionne peut-être tout simplement pas :D Dans le doute, il vaut mieux en mettre !
  • Réduisez la taille de vos blocs d'eau. Il faut toujours faire ses blocs d'eau aussi petit que possible.
  • Ne laissez JAMAIS de l'eau se superposer ou passer à l'intérieur d'autres blocs sous pretexte que vous avez une grande surface à couvrir. Même à l'intérieur et derrière les blocs et les displacements, l'eau sera TOUJOURS calculée mais jamais visible..
  • Laissez aussi peu de model possible toucher l'eau. Tout model qui touchera l'eau sera calculé avec des options spéciales qui le rendra beaucoup plus lourd à gérer. En général, ils sont calculés deux fois. Utilisez la commande mat_showwatertextures 0/1 dans la console pour afficher les entités dans ce cas de figure.

II.4.J. Start/End Fade Pixels

Une technique que je n'ai remarquée qu'il y a peu en farfouillant un peu Hammer. Lorsque vous ouvrez une map et que vous allez dans Map > Map properties, vous avez deux options très pratiques dans la liste qui apparait : Start Fade Pixels et End Fade Pixels. Ces deux options servent à gérer la distance de disparition des models sur toute la map en même temps. Mais leur système diffère de celui intégré dans chaque prop de la map.

En fait, ces deux options permettent de définir à partir de quelle taille un model va commencer à disparaître de l'écran. Si vous spécifiez 50 dans Start Fade Pixels et 20 dans End Fade Pixels, tous les objets de la map commenceront à disparaître à partir du moment où il feront moins de 50 pixels de diamètre à l'écran jusqu'à complètement disparaître lorsqu'ils auront atteint la taille de 20 pixels. Cela permet de faire disparaître très facilement les petits objets assez vite et les objets moyens un peu plus loin. C'est une méthode très simple pour donner un petit coup de pouce à une map qui craque un peu sous le poids des props.

II.4.K. Quand tout le reste a échoué : l'env_fog_controller

Quand tout le reste de vos tests à échoué, il reste pourtant une solution. L'env_fog_controller est un entité qui permet de faire du brouillard, et qui dit brouillard dit distance de vision réduite. ça parait "dommage" d'en arriver là, mais on a parfois pas le choix.
Pour ajouter du brouillard dans une map, reglez l'env_fog_controller comme ceci :

Fog Enable : Yes
Primary Fog Color : la couleur du brouillard (ex: 128 128 128)
Fog Start : la distance à laquelle le brouillard commence
Fog End : la distance à laquelle le brouillard se termine (totalement opaque)

Un exemple de brouillard :

Du brouillard

Toutefois, sur la capture d'écran ci-dessus, cela n'optimise en fait rien du tout, car après le brouillard, votre map ne disparait pas pour autant. Elle est simplement dans le brouillard, et même si vous ne distinguez plus les détails, ils sont quand même affichés dans le brouillard. Vous devez donc vous servir de l'option Far Z Clip Plane de cette même entité pour faire tout simplement disparaître la map à partir d'une certaine distance. En général, on l'utilise soit en intérieur, quand les espaces sont très réduits, soit en combinaison avec du brouillard visible. Toutefois, utiliser le Far Z Clip Plane sans le mettre en combinaison avec un brouillard quel qu'il soit rend assez moche car la map disparaît tout simplement après une certaine distance. Lorsque vous utilisez le Far Z Clip Plane, réglez-le sur la même distance que le "Fog End" de l'env_fog_controller.

Un exemple de Far Z Clip Plane en n'utilisant pas de brouillard pour le masquer :

Far Z Clip Plane

Voici quelques commandes console permettant de manipuler le brouillard directement dans le jeu, cela permet de faire des tests facilement et sans avoir à recompiler à chaque fois votre map pour avoir le bon éclairage et le bon brouillard :

  • fog_override 1 : Supprime le brouillard déjà présent dans la map pour pouvoir faire des tests avec les commandes qui suivent.
  • fog_color R V B : Change la couleur du brouillard dans la map.
  • fog_enable 0/1 : Active/désactive le brouillard sur la map.
  • fog_start X : Change la distance à laquelle commence le brouillard sur la map.
  • fog_end X : Change la distance à laquelle se termine le brouillard sur la map.
  • fog_colorskybox R V B : Change la couleur du brouillard dans la skybox 3D.
  • fog_enableskybox 0/1 : Active/désactive le brouillard dans la skybox 3D.
  • fog_startskybox X : Change la distance à laquelle commence le brouillard dans la skybox 3D.
  • fog_endskybox X : Change la distance à laquelle se termine le brouillard dans la skybox 3D.
  • r_farz X : Change la distance à laquelle la map n'est plus affichée (Far Z Clip Plane).

III. Comprendre une fois dans le jeu

La chose la plus utile dans ce tutorial probablement.. comment savoir, une fois dans le jeu, que vos optimisations sont utiles et même à la limite, si elles fonctionnent tout court. Voici donc tous les outils fournis par VALVe avec le moteur Source pour débugguer et développer sous Half-Life 2.

III.1. Le +showbudget

Showbudget est un outil intégré au moteur Source qui permet de voir combien de temps Source passe sur chacune de ses tâches. C'est principalement un outil de détection des élements qui ralentissent trop le jeu. Ce passage traite de son usage à des fins d'optimisation.

III.1.A. Accès

Showbudget est accessible depuis la console. Il n'est pas nécessaire d'activer le mode de triche pour l'utiliser. Ouvre la console et tapez : +showbudget Fermez ensuite la console. Il devrait normalement être apparu une fenêtre un peu intimidante sur votre écran, c'est le budget. Vous pouvez également taper -showbudget pour le faire disparaître.

Le showbudget

III.1.B. Signification

Dans le coin en haut à droite, vous pouvez voir du texte traitant de "fps" et de "ms". Le premier nombre vous dit combien d'images par secondes sont actuellement dessinées. 60 et plus sont généralement considérés comme bon. Le second nombre est, lui, un meilleur indicateur en vous montrant combien de millisecondes (millièmes de secondes) cela prend au moteur pour dessiner une fois l'écran. Plus c'est bas, mieux c'est. Le texte apparaît en rouge lorsque Source pense que ce temps est mauvais, en jaune lorsque cela devient limite et plus trop adapté à plusieurs joueurs et en vert lorsque tout va bien.

Ensuite, vous pourrez remarquer plusieurs barres de couleur dans la partie principale du graphique. Chaque barre représente combien de temps met Source pour effectuer chaque tâche. Quand ces barres sont petites (à gauche), votre ordinateur gère les choses plutôt bien. Si vous remarquez quelques barres flirtant avec la droite, c'est qu'il y a des endroits à retravailler dans votre map. Voici un résumé de ce que chaque barre signifie :

  • Unaccounted :
    Tout le temps passé par le moteur à faire autre chose qu'à s'occuper du jeu.. les autres processus tournant sur l'ordinateur peuvent par exemple ralentir le moteur. Fermez tous les programmes non-essentiels qui tournent en fond. La commande fps_max peut également être responsable d'une augmentation de cette barre, mais dans ce cas, c'est sans importance car c'est plus ou moins l'effet recherché.

  • World Rendering :
    Concerne les brushes (blocs). Si c'est trop haut, réduisez la complexité de vos blocs ou leur nombre visible en même temps avec les techniques d'optimisation que nous avons eu vues un peu plus haut.

  • Displacement Rendering :
    Concerne les displacements. Si c'est trop haut, vous aurez surement besoin de simplifier vos displacement. En utilisant un "power" moins élevé par exemple ou en découpant vos displacements en plusieurs plus petits afin qu'ils ne soient pas calculés de trop loin.

  • Game :
    Autant que je sache, il n'y a rien à tirer de celle ci à part que si c'est trop élevé, c'est que vous avez trop d'entités qui déclenchent trop d'actions (système d'input/output de Hammer).

  • NPCs :
    Concerne tous les personnes non-joueurs et donc l'intelligence artificielle. Si c'est trop haut, vous avez surement trop de NPCs sur votre carte ou trop de bots en multijoueurs.

  • Server Animation :
    Temps passé par le serveur (en multijoueurs) pour animer les models.

  • Client Animation :
    Temps passé par le client (en multijoueurs) pour animer les models.

  • Physics :
    Temps nécessaire pour effectuer les simulations physiques. Si c'est trop haut, utilisez moins d'objets soumis à la physique ou des moins compliqués, réduisez également le nombre ou la complexité des contraintes que vous avez mises en place (entités phys_). Utilisez tant que possible des prop_physics_multiplayer a la place des prop_physics en multijoueurs.

    Vous pouvez utiliser les commandes physics_budget ou physics_report_active pour afficher combien d'objets sont actifs en même temps. Si vous en avez plus de 20 ou 30, alors vous devrez réduire ce nombre. Réduire le nombre de colision entre eux est également un bon moyen d'optimiser. En faisant plus d'objets avec l'option "debris" cochée par exemple.

  • Static Prop Rendering :
    Temps nécessaire pour dessiner les prop_static. Si c'est trop haut, c'est qu'il y en a trop. (recommandé entre des centaines à des milliers)

  • Other Model Rendering :
    Temps nécessaire au dessin des prop_dynamic, prop_physics et leur variantes ainsi que des armes et des NPCs. Si c'est trop haut, vous utilisez surement trop de models déplaçables et/ou soumis à la physique et/ou de monstres ou de personnes.

  • Light Cache :
    Concerne les ombres. C'est le temps passé à calculer les ombres de tous les objets qui bougent.. prop_physics, prop_dynamic, NPCs, etc... Si c'est trop haut, vous pouvez désactiver leurs ombres.

  • Brush Model Rendering :
    Temps passé par le moteur à dessiner toutes les entités à base de brushes. Comme les func_door, les func_brush, les func_tracktrain, etc... Utilisez les mêmes méthodes que pour World Geometry pour réduire ce nombre.

  • Shadow Rendering :
    C'est le temps passé à afficher les ombres calculées par le Light Cache. Ajouter une entité shadow_control avec un nombre plus bas que la normale pour la distance d'affichage maximum des ombres en haute-résolution peut aider à réduire le temps passé à afficher les ombres.

  • Detail Prop Rendering :
    Temps nécessaire au dessin des prop_detail, c'est-à-dire en majorité de l'herbe et autres models automatiquement ajoutés par certaines textures.

  • Particle/Effect Rendering :
    Temps nécessaire au dessin de tout ce qui utilise des particules. Fumée, nuages, étincelles, lasers et tout le reste. Si ce temps reste elevé en permanence, c'est que c'est probablement la faute d'un env_fire, env_steam, env_smokestack ou autre effet de fumée.

  • Ropes :
    Concerne les cordes/cables. Si c'est trop haut, vous avez probablement trop de cordes/cables ou bien ils sont trop complexes (réduisez leur nombre de segments/subdivisions)

  • Dynamic Light Rendering : Temps nécessaire au dessin des éclairages dynamiques. Si c'est trop haut, vous avez trop d'éclairage dynamique (souvent lorsque vous oubliez de cocher le flag "No Dynamic Light" en mettant un point_spotlight)

  • Networking :
    Temps nécessaire pour effectuer tout ce qui est en rapport avec le réseau. Ce n'est pas la même chose que le lag. Si c'est trop haut, il faudra que vous pensiez à envoyer moins de données par le réseau, et donc à simplifier la carte ou réduire le nombre de joueurs.

  • Sound :
    Temps nécessaire au traitement des sons. Les sons sont causés par les ambient_generic, plusieurs types de func_, les env_soundscape, etc.. Si c'est trop haut, vous avez surement trop de son au même endroit ou trop de son de haute qualité.

  • VGUI :
    Temps nécessaire au dessin de tous les menus (HUD, menu principal, le showbudget en lui même, etc..)

  • FileSystem :
    Cela signifie que vous utilisez des fichiers depuis le disque et non la mémoire.

  • Prediction :
    Temps nécessaire à la prédiction des mouvements des autres joueurs en réseau. Vous ne pouvez pas faire grand chose contre cela...

  • Interpolation :
    Animation/interpolation des entités côté client. Vous ne pouvez pas faire grand chose contre cela...

  • Swap Buffers :
    Concerne les shaders des textures et possiblement d'autres choses. Renseignez vous sur les shaders pour plus d'informations. (certains dont moi, ont un problème avec le Swap Buffer à cause de l'eau quelque part dans leur map)

    Neernitt a dit :
    Swap Buffer; je me permet de signaler que ça peut etre un probléme qui n'a rien a voir avec la map, moi j'avait la barre au max, sur ma map et j'ai donc testé sur les maps officieles = pareil. J'ai reboot le pc et sur ma map la barre était devenue toute petite comme sur les officieles. Voila c'est tout :)

  • AINet :
    Totalement inutile.

  • Occlusion :
    Temps nécessaire au traitement des func_occluder et probablement des areaportals.

  • Overlays :
    Lié aux info_overlay. Si c'est trop haut, vous avez surement trop d'info_overlay ou d'info_decal, ou bien ils sont de trop grande taille.

  • CLagCompensationManager :
    Pas certain, mais semble lié à la gestion du réseau du côté client, notamment à la gestion du lag. Il n'y a de toute façon pas grand chose que vous pouvez faire contre ça.

  • CViewRender::Render :
    Temps passé à dessiner l'image qui va être affichée par votre carte graphique... Ce qui augmente ce temps c'est le nombre de fois que l'image est obligée d'être calculée à cause des objets transparents ou translucides qu'il faut afficher devant ou derrière d'autres objets. L'eau, les sprites, les vitres, et toutes ces choses augmentent ce nombre.

  • 3D Skybox :
    Temps nécessaire au traitement et au dessin du Skybox 3D. Si c'est trop haut, vous devrez probablement simplifier votre Skybox 3D. Il n'y a pas d'autre solution car il est affiché en permanance.

III.1.C. Assigner à une touche

Si vous avez prévu de beaucoup utiliser +showbudget, inserez ces lignes dans votre fichier config.cfg. Cela aura pour effet de réassigner la touche "J" pour afficher/cacher le budget. Vous devrez redémarrer le jeu pour que les changements prennent effet.

alias showbudget_on "+showbudget; bind j showbudget_off"
alias showbudget_off "-showbudget; bind j showbudget_on"
bind "j" "showbudget_on"

Vous pouvez également taper tout simplement bind j "+showbudget" dans la console pour assigner le budget à la touche "j" et faire en sorte qu'il s'affiche quand vous appuyez et disparaisse quand vous cessez d'appuyer sur la touche.

III.1.D. Mise en garde

J'ajouterais aussi qu'il faut vous méfier du showbudget et notamment des FPS qu'il affiche..
Premièrement, il arrive que le budget soit totalement faussé par quelque chose et qu'il affiche des valeurs bien plus élevées que la normale qui pourraient vous faire penser que votre map est optimisée.. dans ce cas, utilisez la commande net_graph 1 ou cl_showfps 1.. et faites la comparaison avec les deux valeurs.
Deuxièmement, sachez que le showbudget en lui même prend pas mal de ressources ! Il m'est arrivé de voir des endroits de ma map à 40 FPS, puis à 50 FPS sans le showbudget affiché, puis à 55 FPS sans le mode mat_wireframe 1, et enfin 57-58 sans le net_graph.. Prudence donc.

De plus, il est dit que le showbudget n'affiche réellement les bonnes valeurs que lorsque le jeu est lancé en mode plein écran et avec le moins possible d'applications tournant en arrière plan (désactivez les antivirus, antispywares, firewalls et autres bouffeurs de puissance).

III.2. Les commandes console

A côté du showbudget, il y a également pléthore de commandes console également très très utiles pour l'optimisation. En voici une liste, peut-être pas exhaustive, mais qui aura le mérite de vous présenter les plus utiles.

Commandes génériques :

  • developer 0/1 : Active/désactive le mode développeur.
  • sv_cheats 0/1 : Active/désactive le mode de triche, parfois utile pour utiliser certaines des commandes suivantes.
  • cl_showfps 0/1 : Cache/affiche les FPS, surement la commande la plus utile pour optimiser. Tentez de rester au dessus de 40 ou 50 FPS.
  • ent_messages_draw 0/1 : Active/désactive le mode debug qui affiche toutes les liaisons entre chaque entités et tous les évenements input/output.
  • find X : Commande très utile. Elle cherche parmis toutes les commandes console celles qui contiennent le mot "X". Salvateur pour retrouver une commande oubliée.
  • listmodels : Affiche une liste de tous les models chargés en mémoire.
  • mat_wireframe 0/1 : Active/désactive l'affichage en mode fil de fer.

    Alucard_DH a dit :

    Une autre précision, il y a 4 modes d'affichage pour le mode Wireframe (commande mat_wireframe x)
    * mat_wireframe 0 : Jeu normal sans fil de fer
    * mat_wireframe 1 : affiche la découpe des tous les objets en polygones triangulaires (cela affiche également les blocs cachés mais quand même calculés par transparence, ce qui est bien pour voir ce que le vis calcule).
    * mat_wireframe 2 : Même que le 1 mais sans la transparence.
    * mat_wireframe 3 : Affiche la découpe des objets en mode BSP (là est le piège, ce n'est pas cette découpe là qu'il faut prendre en compte pour le calcul des polygones, le jeu pouvant afficher des polygones carré).

Commandes pour contrôler l'affichage :

  • mat_drawwater 0/1 : Cache/affiche l'eau sur la map.
  • r_draw3dsky 0/1 : Cache/affiche le skybox 3D (utile pour voir s'il fait ramer).
  • r_dispwalkable 0/1 : Cache/affiche en couleur les faces des displacements où le joueur peut marcher (utile pour faire un chemin escarpé par exemple).
  • r_drawdecals 0/1 : Cache/affiche les decals.
  • r_drawdetailprops 0/1 : Cache/affiche les prop_detail (utile pour voir si votre herbe fait ramer).
  • r_drawdisp 0/1 : Cache/affiche les displacements.
  • r_drawstaticprop 0/1 : Cache/affiche les prop_static.
  • mat_bumpmap 0/1 : Active/désactive le bumpmapping.
  • mat_show_texture_memory_usage 0/1 : Affiche/cache la mémoire utilisée par toutes les textures actuellement affichées.
  • mat_texture_limit X : Défini une limite en Ko pour les textures mises en mémoire. Ne pas mettre de petite taille car sinon l'interface risque aussi de disparaître.
  • mat_surfacemat 0/1 : Affiche/cache les textures utilisées sur chaque face.
  • vcollide_wireframe 0/1 : Affiche/cache le modèle de collision des props.
  • mat_specular 0/1 : Active/désactive les reflets.
  • mat_dxlevel X : Change le mode d'affichage DirectX actuellement utilisé (valeurs conseillées : 60, 70, 80, 81, 90). Pratique pour voir à quoi ressemble votre map chez ceux qui ont une configuration plus légère. Cependant, prenez gare. Faire tourner votre carte graphique à un niveau de DirectX pour laquelle elle n'est pas "prévue" peut engendrer des problèmes plus ou moins graves. Cela peut aller des ralentissements à la coupure pure et simple de l'affichage (le reboot est alors la seule solution).
  • mat_fullbright 0/1 : Active/désactive la mise en lumière totale de la map. (compilation sans RAD)
  • mat_luxels 0/1 : Cache/affiche la lightmap en pleine partie.

Commandes pour contrôler la visibilité :

  • mat_leafvis 0/1 : Active/désactive l'affichage des vis-leafs sur la map (leurs contours sont dessinés en rouge).
  • r_lockpvs 0/1 : Bloque le PVS de façon à ce que seul le vis-leaf où vous vous trouvez reste affiché. Vous pouvez ainsi vous balader dans la map et voir ce qui est dessiné si vous vous trouviez encore dans le vis-leaf bloqué.
  • r_novis 0/1 : Active/désactive l'usage de VIS dans le jeu.
  • r_occlusion 0/1 : Active/désactive les func_occluder (cela permet de voir si vos occluders ont un impact sur vos FPS).
  • r_visocclusion 0/1 : Active/désactive le débuggage des func_occluders (les entités en vert sont cachées par un occluder, celles en rouge non).


Conclusion

J'ai vraiment pas envie de faire de conclusion après avoir écrit tout ça.. mais alors, vraiment pas.
Si après ça, vous êtes toujours aussi nul(le) en optimisation, je ne peux plus rien pour vous désolé.
Sur ce, j'espère que vous aurez compris comment facilement optimiser vos maps. Je vous rappelle au passage qu'il n'est pas forcément obligatoire d'utiliser TOUTES les techniques de ce tuto en même temps ! Votre map ne ressemblerait probablement plus à rien. A vous de voir ce que vous souhaitez utiliser et à quel endroit, mais gardez en mémoire que certaines techniques sont très utiles et puissantes, et d'autres moins, voire beaucoup moins.

Gardez également en mémoire que l'optimisation d'une map ne commence pas une fois que vous l'avez terminée, mais au contraire avant même de la commencer. Si la totalité de votre map peut être vue depuis un seul endroit, il n'y aura pas beaucoup d'optimisation possible... Essayez d'éviter les endroits très grands et très larges puisqu'il est pratiquement impossible de les optimiser. A la place, tentez de bloquer la distance de visibilité avec des immeubles, des murs, des arbres, je sais pas, peu importe.. Essayez également de construire votre map assez "labyrinthiquement" avec des angles, des couloirs qui tournent et des salles non-alignées avec les couloirs..

Un autre petite chose que je tiens à rappeler puisque vous êtes arrivés jusqu'ici. A aucun moment dans ce tuto je ne me vante de connaître tout sur l'optimisation. Au contraire, je ne connais certainement pas encore bon nombre de techniques. Celles dont j'ai la connaissance ne sont pas également forcément expliquées de la manière la plus efficace possible et il est également possible que certains d'entre vous aient une idée tout autre de telle ou telle entité. Sachez que j'ai testé plusieurs fois toutes les techniques présentes dans ce tuto, et je vous assure qu'elles fonctionnent toutes si vous faites tout dans les règles. Ne venez, s'il vous plait, pas vous plaindre parce que quelque chose ne fonctionne pas. L'erreur viendra forcément de vous. Vous pouvez néanmoins passer sur les forums de mapping-area.com et poser votre question en précisant que vous avez déjà lu ce cours.

Et, une dernière chose.. il est évident que je me décharge de toute responsabilité si vous foutez en l'air votre map avec ce tuto :D C'est absolument pas mon problème. Quand vous comptez faire une grosse modification d'une map, gardez toujours une copie de sauvegarde sous la main. On est jamais assez loin d'une erreur.

Si vous cherchez de plus amples imformations sur l'optimisation, voici quelques adresses :

Francais http://www.mapping-area.com/forum/forum16.php
Francais http://www.siteduzero.com/tuto-3-2-0-une-map-avec-hammer.html#part_16
Francais http://alphasis.free.fr/?G4=02000000000000
Anglais http://developer.valvesoftware.com/wiki/Optimization
Anglais http://developer.valvesoftware.com/wiki/Optimization_%28Geometry%29
Anglais http://www.student.ru.nl/rvanhoorn/optimization.php
Anglais http://developer.valvesoftware.com/wiki/Leaks_Explained
Anglais http://developer.valvesoftware.com/wiki/Hammer_Editor_Documentation
Anglais http://developer.valvesoftware.com/wiki/BSP_Map_Optimization
Anglais http://www.hl2world.com/wiki/index.php/Area_Portals

En attendant, bon mapping et bonne optimisation !

Par NykO18
Le 07/04/2005

v1.0 (07/04/2005)
- Première édition

v1.0.1 (09/04/2005)
- Ajout de liens vers des tutoriaux

v1.0.2 (12/04/2005)
- Ajout d'une mise en garde sur le +showbudget

v1.0.5 (14/04/2005)
- Découpage de la section areaportal en 4 parties
- Ajout d'explications sur l'erreur areaportal brush doesn't touch two areas
- Ajout de screenshots sur la section blocklight

v1.1.0 (30/04/2005)
- Ajout de précisions sur BSP
- Ajout de précisions sur VIS
- Correction d'une erreur sur la fusion des faces co-planaires
- Ajout d'une mise en garde sur les areaportals
- Correction de fautes d'orthographe

v1.3.0 (31/12/2005)
- Corrections d'énormités sur BSP et VIS
- Ajout de précisions sur BSP et les leaks
- Ajout de précisions sur VIS
- Ajout d'un paragraphe sur l'overlap
- Ajout d'un paragraphe sur l'eau
- Ajout d'un paragraphe sur l'env_fog_controller
- Ajout de bon nombre de liens vers d'autres tutoriaux
- Reformulation de l'article sur Carve et changement des screenshots
- Reformulation de l'article sur les func_detail
- Reformulation et ajout de précisions sur le texturage
- Réécriture de la partie sur le showbudget
- Ajout d'autres commandes consoles utiles
- Reformulation de la conclusion
- Reformulation de beaucoup de phrases
- Reprise de quelques screenshots assez mauvais
- Correction de fautes d'orthographe

v1.4.0 (09/03/2006)
- Ajout de précisions sur le PVS
- Modification des images pour apporter un peu de clarté aux propos
- Ajout d'un exemple supplémentaire pour le skybox
- Ajout d'explications sur les hints
- Amélioration de l'exemple sur le mur nodraw
- Légère reformulation du paragraphe sur les func_detail
- Correction de plusieurs erreurs de syntaxe, d'orthographe et d'affirmations fausses
- Ajout d'un paragraphe à la mise en garde sur les areaportals
- Ajout de toute une partie sur "Voir avec les yeux du compilateur"
- Ajout et correction de liens vers des tutoriaux externes

v1.5.0 (30/08/2006)
- Ajout de contenu pour aider à la compréhension des vis-leafs
- Ajout d'une section "Temps de compilation"
- Reformulation de la section sur l'env_fog_controller
- Ajout d'un mode d'affichage pour imprimer la page
- Ajout d'un 2ème exemple classique sur les hints
- Ajout d'un 3ème exemple sur les hints
- Correction des précisions sur la commande mat_wireframe
- Ajout d'une section sur le Start/End Fade Pixels
- Ajout de précisions sur les func_occluder
- Ajout de commandes console pour manipuler le brouillard dans le jeu
- Ajout de commandes console pour aider à l'optimisation
- Correction de multiples fautes

PS: Clin d'oeil à Asibasth qui a insisté pour apparaître en bas de cette page :
"J'exige être cité, du genre 'merci à Asibasth pour ses précieux conseils'"
Je précise qu'Asibasth n'a en rien participé à ce cours (ahaha)


Cette création est mise à disposition selon le Contrat Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique 2.0 France disponible en ligne http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ ou par courrier postal à Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.