Il y a des jours où l’on se dit que la vie à un sens de l’humour certain dans sa manière de vous faire comprendre les choses. Sans tomber dans le cynisme, il faut accepter que les idées, c’est un peu comme un jeu de dés. Parfois vous n’arrivez à sortir que des 1, et lorsque vous vous y attendez le moins, hop, on tire le double six. Je vais vous expliquer ceci avec notre dernière scène pour BabylonJS, Sponza !
Pas vraiment le bon moment
Vous le savez, dans tout projet, le principal challenge est de conserver tout le monde concentré et motivé. En ce qui me concerne, après la démo Mansion (http://www.babylonjs.com/Demos/MANSION/), je me posais quelques questions : Devais-je refaire une autre démo avec la team babylonJS, ou devais-je consacrer mon peu de temps libre pour approfondir d’autres technologies, comme Unity3D ou le moteur Unreal ? En tant que créatif, j’ai tendance à papillonner, et l’envie d’une grosse scène AAA, avec un fort aspect gaming et des défis techniques importants (des ombres temps réel, par exemple). Par ailleurs, la charge de travail au boulot était assez forte et le peu de temps qu’il me restait le soir et la nuit devait être optimisé. De son côté, la BabylonJS dream team avait beaucoup d’ambitions et toujours beaucoup de passion. Des décisions devaient être prises. Il était peut-être temps de faire rouler les dés.
La stratégie “tu peux m’aider avec ça ? »
Je filais un coup de main à Julien Moreau Mathis (@luaacro) pour le polish et le test de l’éditeur d’actions de BabylonJS (un moyen innovant de créer des interactions sans aucune ligne de code). Pour avancer je me faisais une scène basée sur des interrupteurs afin de tester les différents workflows d’interactions ((http://www.babylonjs.com/Demos/ActionBuilder/). On fait un point d’avancement avec Julien, et, au détours de la conversation, celui-ci me demande de lui expliquer comment on éclaire une scène. Comme le lighting n’est pas une affaire simple (cela fait appel à la sensibilité, à des connaissances en photo, un peu de physique et beaucoup d’observations et de pratique), je lui propose de travailler sur un exemple. C’est là que la scène Sponza de Crytek entre en scène. Julien la télécharge (http://www.crytek.com/cryengine/cryengine3/downloads/), me la propose et depuis, j’ai beaucoup pensé à elle. C’était le point de départ d’une nouvelle aventure. Vous entendez le bruit de dés ?
La scène initiale
Cette scène…Bon, autant le dire tout de suite, elle n’est pas taillée pour s’exécuter sur un moteur JavaScript…Son propos, à la base, était de démontrer les capacités du Crytek engine (calibré AAA) en ce qui concerne des capacités spécifiques haut de gamme, telles que la radiosité et l’illumination indirecte (le rebond de lumière), le tout en temps réel… Pas vraiment le genre d’artifices à faire tourner décemment sur un smartphone (la cible évidente de moteurs de rendu WebGl, comme BabylonJS)… Bon, il va falloir optimiser sévère. Un exemple ? Prenez les tissus qui ornent la scène d’origine : Pas moins de 130 k triangles, en plein milieu du rendu (en rouge sur l’image en dessous).
Si l’on s’accorde sur le fait que des choix doivent être faits, et que ce que la team recherche, c’est avant tout un rapport qualité visuelle/ performances, on va pouvoir faire un peu de vide. J’ai donc supprimé pas mal de ces tentures, qui en plus de coûter bonbon en perf, me masquaient pas mal de volumes (les couloirs latéraux). J’ai juste conservé, après une bonne cure d’amaigrissement, les drapeaux du haut, histoire de préserver un peu de rebonds lumineux rouges sur les murs.
Un autre souci, c’est que le moteur de rendu par défaut de la scène était celui de 3dsMax. Mental Ray, car c’est son nom, est super, mais il n’est absolument pas compatible avec BabylonJS. Et comme le moteur de rendu influe directement sur les matériaux de la scène, j’ai eu pas mal de travail pour redéfinir, voire recréer de zéro, tous les matériaux qui habillent les objets du palace. Et, oui, il a fallu faire une croix sur l’éclairage d’origine, lui aussi fortement contraint par le moteur. Même pas peur.
De retour avec l’équipe
En tant que designer et artiste 3d, je travaille toujours avec un contexte : L’éclairage doit-il être réaliste ? Oui, assurément. Doit-il être temps réel, ou pré-calculé (compacté dans une texture) ? Pourquoi pas les deux ? Un éclairage matinal ou plutôt une ambiance de soirée ? Ma foi, j’aime bien l’idée de contempler le palace, après une nuit calme, avec des braises finissant de rougir dans les âtres. D’accord, jouons-le comme ça. Une nouvelle nuit consacrée aux réglages des éclairages, des ambiances et des lumières et boum, voici le premier rendu :
La réaction de l’équipe a été formidable. Ils ont été très (TRES) excités par ce projet et m’ont encouragé avec moult flatteries à continuer. Au début, je vivais un peu le moment comme une bonne blague, le fait qu’un simple exercice devienne une scène de démo BabylonJS officielle…
Pourquoi une version pré-calculée, encore une fois ?
Parce que, en regard de la qualité que je recherche, le meilleur moyen d’obtenir des résultats probants et rapides est le pré-calcul de la solution lumineuse. De plus, nous disposons d’outils efficaces et intégrés dans 3dsMax, donc un workflow très confortable pour effectuer ce processus. Même si cela manque un peu de dynamisme, on peut ainsi obtenir des résultats très fins, comme des ombres adoucies ou des renvois de photons, bref, autant d’effets visuels très durs à obtenir avec un éclairage dynamique (et calculés par la carte graphique, quand le type de calcul est prévu/possible/pertinent par le moteur).
De manière générale, « baker » l’éclairage d’une scène est une équation à deux termes : le premier est de créer un canal de texture permettant de convertir les faces en 3d d’un objet donné en une texture en deux dimensions. La complexité vient avec le degré d’exigence de ce repassage, lorsque l’on veut une texture propre (sans couture), efficace (le moins de vide possible) et performante.
Ensuite, utilisant le système lumineux définit auparavant, c’est plutôt simple. On effectue une série de rendus de chaque objet de la scène, en tirant parti des capacités du moteur de rendu natif de 3ds Max (Mental Ray) ou d’un plugin (Vray, par exemple). Dans cette scène, il s’agit bien sûr de radiosité, avec du lancer de photons par zone, puis un lissage de l’éclairage de type « force brute ». Ces rendus deviennent des textures qui sont ensuite multipliées entre elles pour obtenir le résultat attendu.
Pas de magie ici, j’ajoute autant de couches que nécessaire pour créer les matériaux dont j’ai besoin pour « aspectiser » mes objets (du point de vue de l’artiste, un matériau est un empilement de textures différentes). Le vrai génie vient du moteur 3d crée par David Catuhe (@deltakosh) et par David Rousset (@davrous), qui peut combiner pour moi ces textures et en faire un shader performant et adaptatif (un shader est un matériau, du point de vue du moteur).
La phase de conception des shaders et des matériaux est terminée lorsque tous les objets ont reçu l’aspect qu’ils méritent. Parfois, il faut bidouiller un peu et souvent tricher pour obtenir un résultat à la hauteur. En guise d’exemple, je citerai la tête de lion qui a nécessité l’ajout de deux sources lumineuses supplémentaires orange et spécifiques.
A force d’ajouter des canaux de textures et des couches aux couches, vous finissez par vous heurter au mur de la performance. Trop de textures veut souvent dire trop d’appels à la carte graphique, une trop grosse consommation mémoire et des temps de chargement trop longs (et je rappelle que nous sommes sur le web, donc que les contraintes de ce milieu s’ajoutent à celles du temps-réel). C’est donc le parfait moment pour un peu d’optimisation. Et dans ce domaine, les recettes de grand-mère sont encore les meilleures : On essaye de conserver des tailles de textures en multiples de 8 et surtout, on se souvient de son objectif : Il est rarement utile d’avoir une texture de 2048x2048 pixels lorsque la résolution de rendu attendue est de 1080p. Vous n’aurez, de toute façon, pas vraiment besoin de textures plus grandes que 512x512 pixels. Par contre la plus petite texture de Sponza est de 16x16 pixels.
Au passage, lors de ma phase d’optimisation, j’ai aussi été tenté par une version low-end de Sponza, avec une grosse réduction du nombre de textures autant que de leurs tailles, mais cela ne s’est pas réellement montré pertinent, puisqu’au final, j’ai dû gagner une moyenne de 5 images par seconde pour une perte de qualité graphique importante.
Une autre considération de l’équipe était d’introduire de l’animation dans l’univers de la scène. J’ai donc ajouté des bones (des structures invisibles qui se comportent comme des os) afin d’animer les drapeaux du haut de scène d’un léger balancement et de simuler visuellement un léger vent. J’ai également ajouté 5 trajectoires de camera pour un usage ultérieur. Le travail sur la scène était quasiment fini.
Pourquoi un éclairage temps-réel ?
Parce qu’on le peut ! David Catuhe a encore réalisé des miracles pour donner à la scène en pré-calculé une petite sœur, toute en éclairages dynamiques, qui en plus, est absolument performante ! J’ai testé deux/trois réglages (grâce au workflow super rapide d’exportation de BabylonJS), ajouté et animé deux lumières dans 3dsMax, jonglé un peu avec les paramètres (surtout la distance d’atténuation) et bien sûr supprimé toute les textures d’éclairages pré-calculées et laissé le moteur faire le reste. Nous avions notre scène avec éclairage temps-réel, et c’est démentiellement rapide !! Plus d’infos sur le sujet dans ce très bon article : https://blogs.msdn.microsoft.com/eternalcoding/2016/02/09/going-further-with-babylon-js-2-3-advanced-features/
On finalise et on passe le polish…
Nous sommes exigeants, c’est un fait. Nous n’étions toujours pas complètement satisfaits du résultat, car il restait encore quelques points potentiellement améliorables. Comme l’écran de chargement, que l’on voulait spécifique à cette scène. J’ai donc commencé à drafter quelques écrans et ai réalisé cette maquette :
C’est ici que l’expertise en HTML/CSS de David Rousset est devenue une arme de conviction massive, puisqu’elle a permis de réaliser un écran totalement responsif et entièrement dans notre cible (le mobile et sa fragmentation légendaire). Tout ceci est d’ailleurs relaté dans cet autre excellent article :
Et je ne parle même pas de la musique, conçue spécialement pour la scène par monseigneur Rousset, seigneur du bit sonore.
David Catuhe, de son côté, nous faisait la surprise de travailler sur un outil permettant de scénariser les différentes caméras. Si les cameras passent d’un point de vue à un autre, naturellement dans la démo Sponza, c’est bien grâce à ces nouveaux développements. D’ici à ce que ceci soit intégré, il n’y a pas loin…
Le chapitre, “au fait, une dernière chose… »
Avez-vous remarqué que les brasiers émettent des particules, comme des brandons ? C’est juste pour vous dire que ces effets (et un peu de débogage en live) ont été réalisés avec un truc totalement dément développé par Julien. Resté connectés, vous devriez avoir quelques nouvelles prochainement…
…et déjà la conclusion.
On adore tous avoir un semblant de contrôle sur nos trajectoires, on a l’habitude de se doter d’objectifs et de calendriers, jusqu’au moment où le jeune apprenti passe par là, vous demande une explication et vous en remet pour un tour. C’est ainsi que cette scène Sponza (la plus relayée, pour l’instant) a été conçue. J’en suis trop fier. C’est de loin la scène la plus travaillée en équipe de notre production, et elle nous apporte de grandes satisfactions personnelles et de nouvelles promesses.
Les dés ont donc décidé. Ce sera un double six.
http://www.babylonjs.com/Demos/Sponza/