Sur les traces de mes petit camarades (Eternal coding) (David Rousset’s Blog), je profite de l’opportunité de la //Build/ pour vous raconter la fabuleuse histoire de la création de contenus 3D du point de vue de l’artiste. Comme vous le savez peut-être, avant de travailler chez Microsoft, j’ai été profondément impliqué dans le développement d’un moteur 3D assez unique en son genre, NOVA. Mon travail principal était alors de faire tourner les développements de manière à prendre en compte le point de vue de son utilisateur et de récolter ses feedbacks. Est-ce que l’artiste utilisera cette fonctionnalité? Ets-ce que cette action est compréhensible? Comment faire ceci sans code ? Alors que Microsoft annonce ces jours-ci le support de la norme WebGL sous la dernière version d’Internet Explorer (AKA IE 11), faisons ensemble un tour des concepts de base de ce monde fabuleux de la 3D.

Donc, on commence souple sur ses appuis, avec parfois de gros raccourcis. Cet article se veut didactique plutôt que complet. On affinera par la suite.

 

La performance avant tout.

Dans mon boulot, je parle souvent avec de vieilles barbes qui n’ont de cesse de répéter que la performance est la clef des applications. Et c’est parti pour des heures de comparaison de technos, de monologues sur les spécificités du C++, sur la surpuissance de l’assembleur et du code natif. Il est vrai que de nos jours, avec nos machines rutilantes, bourrées d’haswell, de 16 Go de mémoire et de GPU digne de l’Etoile Noire, on aurait tendance à délaisser l’optimisation au profit d’une visualisation proche du parfait.

Mais une telle approche est une erreur. Ok, on peut afficher plus de triangles. Ok, on peut encore ajouter plus de particules. Super, j’ai géré la conception pour un écran HD pleine résolution 4K. Super. Mais pour en ajouter toujours plus, on doit optimiser. La bonne question est : Dur ! J’ai un super moteur 3D à ma disposition, qui exploite les dernières technos, basé sur une plateforme robuste, mais comment font donc les gars qui bossent sur des productions AAA pour obtenir de tels graphismes? Vous voyez cette fonction spécifique? C’est certainement un tueur de performances, ça ! Alors comment tout ceci tient ensemble ?

La question est tapie sous l’infâme vérité ! OP-TI-MI-SA-TION. Et pas seulement dans le code, se serait trop simple. Non, la performance d’une scène 3D vient souvent aussi des assets. En fait, les performances sont aussi une qualité des artistes 3D. Pensons aux optimisations  comme à une autoroute où toutes les voitures doivent rouler au dessus d’une vitesse limite de 30 images par seconde. Sous cette vitesse, l’affichage devient pénible et irritant. Donc chaque voiture doit maintenir sa vitesse au-dessus de ce minimum. Si vous avez peu de voitures, celles-ci vont arriver assez vite à destination. Par contre, leur nombre augmentant, elles vont ralentir afin de permettre à chacun d’atteindre leur destination dans de bonnes conditions. Mais on ne souhaite toujours pas descendre sous la vitesse minimale. Et si cela se produit tout de même, il faudra prendre des décisions drastiques. Devrais-je supprimer des voitures ? Ou vais-je être finalement obligé de descendre ma vitesse minimum…?

D’un autre côté, si vous êtes un professionnel ambitieux, avec toujours l’optimisation en ligne de mire, toute vos voitures vont super vite et prennent toutes l’autoroute des vacances à 3000 images par seconde. Mais alors, vous ratez votre but. En effet, le but de votre vie, en tant qu’artiste est de montrer des choses belles, pas rapides. Et le paysage que vous dépeignez est votre valeur ajoutée, pas les voitures… Si vos perfs sont trop bonnes, cela ne veut pas forcément dire que vous optimisez bien. Cela veut dire que vous optimisez trop. Et que vous ne tirez pas assez profit du moteur pour décrire votre monde 3D. Pas assez de framerate et votre monde devient pénible à suivre. Fais ton choix, Nicolas.

Et,bien sûr, vous êtes malgré tout dépendant de la plateforme matérielle et logicielle sur laquelle va tourner votre petit univers.

 

Un jeu très attendu : Ubisoft The Division. Un état de l’Art momentané de l’optimisation.
Un jeu très attendu : Ubisoft The Division. Un état de l’Art momentané de l’optimisation.

Un dernier mot sur ceci : Lorsque vous recherchez la performance, ne vous concentrer pas trop sur le nombre de triangles par seconde, ou sur combien de polygones votre scène comporte. Ce sont de bonnes données statistiques, mais un objet à forte densité peut être deux fois plus rapide à afficher en fonction des optimisations (taille des textures, économie d’effets ou de déformation de maillage,…).

 

Do you speak 3D ?

Les artistes 3D de par le monde forment une communauté et parle souvent un dialecte ésotérique comportant des mots qui leur sont propres. N’en soyez pas effrayés. Les concepts qui sont en dessous ce verbiage sont simples. C’est vraiment pas compliqué. Imaginez, vous vous trouvez dans un théâtre dont vous êtes le seul spectateur (plutôt un réalisateur, d’ailleurs). Disons que vous définissez le point de vue (la caméra). Devant vous se trouve la scène. C’est là que la pièce se joue et que les acteurs font leur boulot. Appelons-les des objets. Ils ont tous un but spécifique à jouer (fixe, animé, déclencheur, collision,…), mais ils ne peuvent briller sans lumière, ni sans costumes (un shader). En tant que caméraman, vous pouvez même ajouter des filtres à la volée pour encore embellir votre mise en scène (Post effect shaders). Et l’espace entourant la scène restant dans l’ombre le temps de la représentation, nous ignorerons purement et simplement ce qui est hors champ (Principe de Frustrum ou pyramide de vision).

Voilà, ce n’est pas plus compliqué que ceci.

 

Frustrum
Le principe du Frustrum. Tout ce qui n’est pas dans le champ de vision n’est pas pris en compte.

 

Bon, en fait si. C’est un peu plus compliqué, tout de même. Tous ces acteurs, tous ces items, quel bazar… Pour faire fonctionner tout ceci, vous devrez organiser un peu l’affaire. Par exemple, les acteurs ne doivent pas tous être en scène en même temps, ou déclamer leur prose au même moment. La règle est assez simple: Les performances sont la règles. Mais, en tant qu’artiste, vous voulez que chacun soit entendu et vu pour ses qualités intrinsèques. Pour cela, il va falloir suivre le scénarion et tirer parti du rôle de chacun.

Petits veinards, vous avez à votre disposition du personnel qualifié. Un régisseur, par exemple (votre CPU), qui fais bien attention à ce qui se trouve sur la scène. C’est lui qui est chargé des entrées/sorties de la scène. Trop de monde sur la scène, et votre CPU est perdu et ralenti le spectacle. Pas assez d’items et il passe son temps à attendre les autres. ha oui, pensez toujours à tout ce process à un événement image par image. En effet tout ce qui est décrit ici se reproduit au minimum 30 fois par seconde. Notamment, 30 fois par seconde, le CPU réorganise tout, reparti la charge et prépare l’image suivante. Dernière chose : Votre CPU, même si vous avez la chance et la monnaie pour posséder la dernière génération des puces tendances, votre CPU n’est pas Dieu. Il dispose de dons bien plus modestes. Par exemple, notre univers va des lointaines galaxies (si lointaines) au proton qui compose nos atomes. Les CPU actuels ne sont pas si précis et doivent traiter de données calibrées pour leur usage.

     

Une fois l’organisation faite, une fois les acteurs sur scène, jouant leur rôle, vous devez broadcaster ce qui se passe. C’est ici que les choses se compliquent un peu. Imaginez un monde 3D, transformé en 2D (votre écran, au final)…. Toute la complexité de cette tâche revient à notre GPU (la carte graphique). Pour afficher tout notre petit monde, nous héritons du travail de notre ami le CPU. Seulement, le GPU à sa propre logique, assez particulière. Par exemple, il va commencer par “rendre” la scène en partant des objets les plus éloignés, puis en rendant progressivement les objets plus proches de la caméra. Ceci est appelé le Z-buffer. On rend les objets en fonction de leur distance à la caméra, en partant des plus éloignés. Le GPU est beaucoup plus précis, également, puisque là où le CPU va traiter avec les objets, notre cartes graphiques va traiter avec ses composants (les faces, les sommets, les arêtes,…). Cela devient vraiment complexe lorsque vous jouez avec la transparence des objets, puisque le CPU n’a pas connaissance de cette info, le GPU la voit, mais à un niveau très bas. Comment dès lors connaître la transparence d’une face donnée d’un objet donné ?

Alors, résumons-nous un peu : Le CPU organise le boulot et arrange la scène. Le GPU prend alors la relève et construit les géométries (la tesselation). Ensuite, il illumine les faces de l’objet, en adoucissant les arêtes entre les polygones. Mais l’objet est toujours nu comme un ver, jusqu’à là. Le prochain processus consiste donc à donner un costume à notre acteur, si l’on veut bien filer encore un peu la métaphore. Mais nous reviendrons là-dessus un peu plus tard.

Au final, le résultat est traité comme un pixel à afficher et envoyé à l’écran. Cela revient à traduire des données abstraites en données concrètes (de la 3D à la 2D, comme des maths aux pixels).

Toute ces contraintes mènent immanquablement à une réflexion : On n’obtient de bonnes performances qu’en combinant finement la puissance du CPU avec les capacités du GPU. Si votre scène est trop optimisée, votre CPU va passer son temps à attendre que la scène se dessine. Si votre scène à beaucoup d’items à traiter, mais que le rendu est assez simple, votre CPU va beaucoup ralentir le GPU. C’est ce genre de souci qui à retarder la montée en puissance de la PS3, à cause de sa géométrie spécifique à 8 cœurs

 

Vous en reprendrez bien un peu ?

Un gros CPU est parfait pour traiter rapidement les entités de la scène et pour d’autres calculs annexes (notamment statistiques, ce qui peut se révéler utile…), tandis que le GPU est adapté au rendu final et pour certains trucs additionnels (comme la physique). N’oubliez pas pour autant qu’un bon jeu ou qu’une bonne simulation, c’est souvent bien plus que ceci et qu’il vous faudra faire de la place pour le son, l’intelligence artificielle, le réseau,  etc…

Tant que je tiens le GPU, gardez toujours à l’esprit qu’une image ne vient jamais non plus d’un bloc. Plutôt sous forme de passes multiples et successives que l’on nomme des Draw Calls. Le moins de Draw Calls vous rencontrez, le plus de FPS vous obtenez.

Chaque fois que vous ajoutez une fonctionnalité à votre rendu, vous ajoutez probablement un Draw call dans la pile. Pour mieux visualiser ceci, voyons maintenant ce qui définit l’aspect des objets de ma scène. Comme nous l’avons vu précédemment, un objet est généralement dessiné comme ceci par la carte graphique : D’abord les sommets, puis les arêtes, ensuite on remplit les triangles, on applique les lumières et enfin, on texture tout ceci. Les textures sont des ressources de la scène sous forme d’images bitmap ou procédurales et elles conforment l’aspect de l’objet à votre volonté artistique de manière additive, soustractive ou encore multiplicative. Une texture peut être appliquée dans un canal spécifique : le canal diffus définit l’aspect primaire de l’objet (un mur de briques, par exemple). Le canal ambiant est utile pour les ombrages, le canal d’opacité permet de créer des objets transparents, ou semi-transparents, le canal de spéculaire est pour la brillance du matériau concerné, le canal de réflexion pour refléter l’environnement, etc… le résultat de l’empilage de tous ces canaux est ce que l’on appelle un Shader.  Dépendant du moteur 3D et de la bravure de votre développeur, vous pourrez avoir accès à des shaders très complexes, comme des rendus de textures Fresnel, la gestion des textures cubiques, ou encore du spéculaire au pixel.

ha oui. J’allais oublier de vous parler de deux grandes nuances. Vous pouvez rendre vos shaders de deux manières. La première, et sans doute la plus rapide et de prendre en compte les sommets des objets comme support du shader. Rapide mais pas très précis, puisque l’éclairage et le spéculaire est calculé au sommet. Et, généralement, en temps réel, vous avez tendance à économiser sur les sommets. D’autre part, vous avez le rendu au pixel, ou chaque pixel de l’écran se voit assigner une couleur, basée sur tous les paramètres vus précédemment. Même si ce processus s’est vu allègrement accéléré ces derniers temps, ce type de rendu est néanmoins dépendant du nombre de pixels à afficher  et la complexité augmente avec la résolution visée. Plus vous aurez de pixels à afficher, plus vous consommerez de mémoire et plus votre rendu sera lent.

 

 

Shaded Diffus Ambiant  

Eclairé

Avec une texture de diffus

Diffus+ambiant

 
Specular   Reflec Shader

Diffus+Ambiant+Speculaire

 

Et un peu de réflection

Enfin, un shader Per pixel contenant du bump, du spéculaire et de la réflexion cubique.

 

Les outils

Ok, cela conclut cet article sur la 3D du point de vue de l’artiste. Le prochain article entrera dans le détail des outils pour produire des assets pour vos mondes 3D, spécialement Blender 3D. Restez connectés !

    
Labo

Une superbe démo WebGL réalisée par les gars de DPE France !