Dorian Fevrier's blog - Mot-clé - guerillaJe m’appelle FEVRIER Dorian, je suis infographiste 3D passionné par mon métier, l’informatique en général, l’internet, la programmation et l’évolution de tout ce petit monde. Vous trouverez sur ce blog des tutoriaux, mes coups de cœurs, avis, etc.2024-01-02T23:48:05+01:00FEVRIER Dorianurn:md5:695d9c73474c33ce3dab043823509c4bDotclearLire les Light Stats dans Guerillaurn:md5:7eddc21e4a73a95f258b6fa8e4c6ae942021-12-14T23:25:00+01:002021-12-22T11:05:44+01:00NarannInfographie 3D - Boulotguerillalightlogrendustats<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_tn.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Depuis la version 2.3.9, Guerilla dispose d’un log de rapport de contributions des lights de vos scènes. Il n’est pas évident d’interpréter correctement ces valeurs : Elles ne sont pas forcément simples à comprendre, et encore moins à mettre en relation avec l’image. :reflechi:</p>
<p>Nous allons donc commencer par expliquer ce qu’elles représentent, puis nous commenterons un petit rendu visant à pousser l’efficacité de ses statistiques dans leur retranchement.</p>
<p>Notez que cette version est sortie ce soir et que je n’ai pas pu m’empêcher de faire un billet… :baffed:</p>
<div id="simple-translate">
<div>
<div class="simple-translate-button isShow" style="background-image: url("moz-extension://dd0ffa57-a8f2-46fd-9898-40a206abc3b9/icons/512.png"); height: 22px; width: 22px; top: 47px; left: 939px;"> </div>
<div class="simple-translate-panel " style="width: 500px; height: 300px; top: 0px; left: 0px; font-size: 13px; background-color: rgb(255, 255, 255);">
<div class="simple-translate-result-wrapper" style="overflow: hidden;">
<div class="simple-translate-move" draggable="true"> </div>
<div class="simple-translate-result-contents">
<p class="simple-translate-result" dir="auto" style="color: rgb(0, 0, 0);"> </p>
<p class="simple-translate-candidate" dir="auto" style="color: rgb(115, 115, 115);"> </p>
</div>
</div>
</div>
</div>
</div> <h3>Activer le rapport</h3>
<p>Pour activer le rapport de statistique des lights, il faut aller dans <em>Preferences</em>, <em>Rendering</em>, <em>Logs & Diagnostics</em>, mettre <em>Verbosity</em> à « <em>Diagnostics</em> » et cocher <em>Render Statistics</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/enable_light_stats.png" style="margin: 0px auto; display: table; width: 337px; height: 263px;" /></p>
<h3>Explication détaillée</h3>
<p>À la fin de votre rendu, vous aurez quelque chose qui ressemble à ça :</p>
<pre>
<code>Light Stats:
nSmp | TL | TL% | OL% | Eff% | Separate Lights
10.3M | 1065321.2 | 13.1 | 10.5 | 80.4 | Group9|SkyLight|Sky
nSmp | TL | TL% | OL% | Eff% | Shared Lights
5.46M | 405505.3 | 5.0 | 4.0 | 80.6 | Group8|SquareLight
5.45M | 880797.4 | 10.8 | 9.0 | 83.1 | Group9|SkyLight|Sun
1.80M | 307087.1 | 3.8 | 3.3 | 87.2 | Group7|SquareLight2
3.49M | 581026.5 | 7.1 | 6.3 | 87.9 | Group6|DistantSpotLight
2.10M | 372714.8 | 4.6 | 4.0 | 88.2 | Group7|SquareLight3
3.83M | 1379261.3 | 16.9 | 15.0 | 88.9 | Group5|DistantSpotLight1
2.37M | 103511.3 | 1.3 | 1.1 | 89.8 | Group3|SpotLight
2.53M | 243524.2 | 3.0 | 2.7 | 90.5 | Group2|SpotLight
4.31M | 709680.5 | 8.7 | 8.1 | 92.8 | Group7|SquareLight1
2.68M | 299954.9 | 3.7 | 3.4 | 92.9 | Group1|SpotLight
4.42M | 1806236.6 | 22.1 | 21.1 | 95.4 | Group4|DistantLight
-----------------------------------------------------------------------
48.7M | 8154621.0 | | | | Total</code></pre>
<p style="text-align: center;"><em>« Pas mal, non ? C’est français. »</em></p>
<p>Pas de panique, on va commenter tout ça ! :hehe:</p>
<p>Comme vous vous en doutez, <em>nSmp</em> est le nombre de samples envoyés sur la light. Je ne m’éternise pas. :redface:</p>
<p>Les deux autres termes sont en revanche, plus complexes, mais ne vous inquiétez pas, je vais écrire doucement pour ne pas vous perdre… :bete:</p>
<p><em>TL</em> est le total d’intensité lumineuse (<em>Total Luma</em>) émis par la lampe sans tenir compte de l’occlusion (c.à.d, sans prendre en compte le test d’ombre).</p>
<p>Je suis obligé de m’arrêter pour expliquer un peu comment fonctionne Guerilla (et je suppose que c’est le cas pour la majorité des ray tracer du marché). Je vais volontairement être très grossier, le but est de comprendre un log, pas de vous faire un cours sur les moteurs de rendu (si ça vous intéresse c’est <a href="https://pbr-book.org/" hreflang="en" title="Physically Based Rendering: From Theory To Implementation">par ici</a>).</p>
<p>Quand un rayon arrive sur une surface, le moteur calcul l’illumination de ce que nous allons appeler le <em>shading point</em> (en rouge sur le schéma ci-dessous). Pour cela il va utiliser la normale de la surface du <em>shading point</em> et en extraire un hémisphère (la normale étant la direction du pôle) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/schema.png" style="margin: 0px auto; display: table; width: 794px; height: 606px;" /></p>
<p>Avec cet hémisphère (en vert), le moteur peu déjà éliminer les lights étant « derrière l’hémisphère » (c.à.d, derrière la normale du <em>shading point</em>, light 1) ainsi que celles « dos au <em>shading point</em> » (c.à.d, qui montrent leurs fesses au <em>shading point</em>, light 3) car elles ne contribueront pas à l’illumination du <em>shading point</em>.</p>
<p>Reste les autres lights, celles qui sont face au <em>shading point</em> : Comment déterminer la light ayant la meilleure contribution ? :petrus:</p>
<blockquote>
<p>Dans notre exemple, il n’y en a qu’une (light 2), mais ce schéma ne servait à qu’à illustrer le mécanisme d’élimination des lights.</p>
</blockquote>
<p>On pourrait lancer des rayons au hasard sur toutes les lights, mais en pratique, seules quelques-unes contribueraient vraiment à l’illumination du <em>shading point</em>. La question est donc de savoir s’il existe un moyen de déterminer quelles sont les lights qui pourraient contribuer le plus si, en effet, elles étaient visibles du <em>shading point</em>.</p>
<p>Et c’est là que c’est contre-intuitif : Pour déterminer s’il est pertinent de faire un coûteux test de visibilité de la light par le <em>shading point</em>, on va prendre chaque light et déterminer sa contribution théorique, c.à.d l’intensité lumineuse qu’elle « pourrait » générer sur le <em>shading point</em> si elle est visible par ce dernier.</p>
<p>Dis autrement, avant d’envoyer notre unique et coûteux rayon d’occlusion (test de visibilité) sur une light, on détermine l’illumination théorique de chaque light sur le <em>shading point</em>.</p>
<p>Mais comment on détermine la contribution théorique d’une light sans traverser la scène ? On calcule sa contribution (ou une approximation) comme s’il n’y avait rien d’autre que la light qui nous intéresse. On fait ça pour toutes les lights pouvant contribuer au <em>shading point</em>, et c’est seulement une fois qu’on a isolé la lampe la plus pertinente qu’on teste sa visibilité (c.à.d, qu’on lance un rayon dessus pour vérifier si un mur/objet est devant ou non). Encore une fois : On procède ainsi car calculer la contribution d’une light sans lancer de rayon est beaucoup (beaucoup) plus rapide que le coût du rayon pour déterminer si elle est visible au <em>shading point</em>.</p>
<p>Mais l’effet de bord est évident : Si vous avez une light derrière un mur, mais en direction de votre <em>shading point</em>, le moteur privilégiera cette lampe.</p>
<p>C’est ça <em>le</em> problème des path tracers. On peut tenter d’y répondre par du bidir, du vertex merging, etc. Mais le path tracing a des avantages que ces solutions ne gèrent pas facilement (ray differential pour le mip mapping).</p>
<p>Comprenez, on l’a dans l’os, lapin l’choix, et c’est pour ça que dès qu’on a du mal à garder le contrôle sur un lighting (comprenez, qu’on ne fait pas un lighting aux petits oignons par plan), on crée forcément des situations où le path tracer se fait avoir. :IFuckTheWorld:</p>
<p>Une fois que vous avez compris ça, vous êtes en mesure d’expliquer la relation entre TL% et OL%.</p>
<p>Première chose : <em>TL%</em> est le pourcentage d’intensité lumineuse sans tenir compte de l’occlusion (comprenez, la contribution « théorique ») de la light par rapport à toutes les lights de la scène. La somme du <em>TL%</em> de toutes les lights est 100 % (vous pouvez faire le calcul :siffle: ).</p>
<p>Et enfin : <em>OL%</em> est le pourcentage d’intensité lumineuse en prenant en compte l’occlusion (comprenez, après un test de visibilité réussi) de la light par rapport à toutes les lights de la scène.</p>
<p>On a donc <em>OL%</em> / <em>TL%</em> = Ratio d’efficacité d’une light. Exemple dans notre cas sur la light la moins efficace :</p>
<pre>
<code class="language-python">>>> 4.0/5.0
0.8 # 80 %</code></pre>
<p>Et cela correspond bien à notre valeur de <em>Eff%</em> (moins les imprécisions). :youplaBoum:</p>
<p>Vous avez donc 20 % de perte (tests de visibilité échoué) pour cette light, sur votre image.</p>
<p>En pratique, la valeur <em>TL</em> n’est pas d’une grande aide, ce sont les valeurs <em>TL%</em>, <em>OL%</em> et <em>Eff%</em> qui sont importantes. Un <em>OL%</em> à 0.0 indique que la light n’amène pas grand-chose à l’image :</p>
<ul>
<li>Si ce <em>OL%</em> à 0.0 est combiné à un <em>TL%</em> élevé, ça veut dire que le path tracer se fait avoir.</li>
<li>Si le <em>TL%</em> est également proche de 0.0, l’<em>Eff%</em> peut être élevé, mais on peut se poser la question de l’intérêt de cette light qui ne semble pas énormément contribuer au rendu final.</li>
</ul>
<h3>Relation entre <em>separate sampling</em> et <em>shared sampling</em></h3>
<p>Comme vous avez pu le remarquer sur le log d’exemple, les lights sont divisées en deux groupes :</p>
<ul>
<li><em>Separate lights</em></li>
<li><em>Shared lights</em></li>
</ul>
<p>Sauf quelques exceptions (que nous verrons plus loin), une light est en <em>shared sampling</em> par défaut. Cela veut dire qu’elle fera partie du paquet de lights servant à déterminer laquelle est la plus pertinente à tester pour chaque <em>shading point</em>. C’est-à-dire que pour chaque <em>shading point</em> on fera une estimation de la contribution de chaque light du paquet et on en choisira une pour tester sa visibilité au <em>shading point</em>.</p>
<p>Guerilla permet de marquer une light comme <em>separate sampling</em>. Cela veut dire que cette light sera exclue de la boucle d’évaluation de la contribution théorique (en gros, elle ne fera pas partie des <em>shared lights</em>). Guerilla estimera qu’une telle light aura toujours une contribution significative et fera un test de visibilité dans tous les cas (sauf si elle est derrière le shading point ou dos à sa normale, mais ça, c’est logique). En gros, vous dites au moteur de vous faire confiance et de systématiquement utiliser cette light en plus de la light qu’il va choisir (notez le « en plus »). Il est donc important que l’attribut <em>separate sampling</em> ne soit coché que sur les lights qui apportent quasi systématiquement quelque chose à l’image.</p>
<p>C’est la raison pour laquelle les <em>env lights</em> ont l’attribut <em>separate sampling</em> par défaut.</p>
<h3>Le test du mur</h3>
<p>Comme je suis taquin, je vais tenter de piéger Guerilla et surtout de voir si les statistiques des lights me remonte cette information. :reflexionIntense:</p>
<p>Voici la scène :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_001.png" style="margin: 0px auto; display: table; width: 297px; height: 443px;" />Un plan, une sphère, deux lights positionnées à 180 l’une de l’autre et un mur sur celle de droite :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_002.png" style="margin: 0px auto; display: table; width: 249px; height: 161px;" />Le rendu :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_003.png" style="margin: 0px auto; display: table; width: 512px; height: 384px;" />Clairement la light derrière le mur ne contribue pas au rendu, et les statistiques le confirme :</p>
<pre>
<code>Light Stats:
nSmp | TL | TL% | OL% | Eff% | Separate Lights
nSmp | TL | TL% | OL% | Eff% | Shared Lights
15.8M | 4436347.0 | 42.2 | 0.0 | 0.0 | derriere_mur|SquareLight
23.2M | 6064878.0 | 57.8 | 48.7 | 84.4 | devant_mur|SquareLight
-----------------------------------------------------------------------
39.0M | 10501225.0 | | | | Total</code></pre>
<p>On remarque immédiatement l’<em>Eff%</em> de la light derrière le mur à 0. Cette light est inefficace et peut être retirée du rendu sans risque. :bravo:</p>
<p>La raison pour laquelle le <em>TL%</em> de la light derrière le mur n’est que de 42 % et non de 50 % comme on pourrait s’y attendre (la scène étant très symétrique d’un point de vue lighting) c’est parce que les <em>shading points</em> de la caméra vers le mur excluent de facto la light derrière le mur (rappelez-vous, l’hémisphère). Le mur représentant une partie non négligeable de l’image, il est logique que le moteur estime, à juste titre, que la light de gauche (devant le mur) contribue plus à l’image.</p>
<p>Regardons les temps de rendu. Ma <em>RenderPass</em> est à 256 samples, threshold à 0.03 et min samples à 16. Le rendu original se fait en 26 secondes sur mon modeste PC. Si je prune la light derrière le mur, je tombe à 19 secondes.</p>
<p>Allons encore plus loin et regardons les light stats de ce « lighting parfait » :</p>
<pre>
<code>Light Stats:
nSmp | TL | TL% | OL% | Eff% | Separate Lights
nSmp | TL | TL% | OL% | Eff% | Shared Lights
22.8M | 3876291.8 | 100.0 | 77.4 | 77.4 | devant_mur|SquareLight
-----------------------------------------------------------------------
22.8M | 3876291.8 | | | | Total</code></pre>
<p>Notez le 77.4 % de l’efficacité de la light. Elle semble diminuer par rapport au 84.4 % du rendu précédent. Rien d’anormal pour autant : Sur le premier rendu, le moteur avait le choix entre deux lights. Si, par exemple il tombait sur un <em>shading point</em> de la partie droite de la sphère (pointant vers la droite de la scène), il choisissait la light derrière le mur et c’est elle qui ratait son test de visibilité. L’efficacité de la light de droite était donc conservée.</p>
<p>Je soupçonne que quand il n’y a aucune light à choisir, Guerilla considère automatiquement le test de visibilité comme ayant échoué. C’est donc les ombres de la partie de droite de l’image qui entraînent un échec du test de visibilité.</p>
<p>Notez aussi le nombre total de samples lancé avant de converger : Un tiers de moins. Une information confirmée par l’AOV de heat.</p>
<p>Rendu avec les deux lights :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_heat_001.png" style="margin: 0px auto; display: table; width: 510px; height: 384px;" />Rendu avec une seule light, à gauche :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_12_18_guerilla_light_stats/scene_mur_heat_002.png" style="margin: 0px auto; display: table; width: 510px; height: 384px;" />Sur la première image, on remarque que Guerilla n’arrive pas à sampler une partie de l’image (en particulier partie droite de la sphère). Et pour cause, aucune light n’illumine ces zones. :cayMal:</p>
<p>Sur la seconde image, Guerilla ne se fait plus « avoir » en croyant que la light derrière le mur va illuminer le dos de la sphère.</p>
<h3>Conclusion</h3>
<p>L’analyse du sampling des lights est très complexe, car la frontière entre l’ombre d’un objet (test de visibilité raté, mais légitime) et le fait qu’une light particulière apporte peu contribution (voir aucune), est difficile à déterminer. Avec son log, Guerilla propose un moyen de mettre le doigt sur les lights étant réellement inefficace. Une light avec un <em>Eff%</em> à 0 peut être caché sans aucun risque pour vos rendus. :sauteJoie:</p>
<p>J’espère que cette brève présentation vous a plu et que cette nouvelle feature vous permettra d’identifier les lights parasites de vos rendus, avec, pourquoi pas, un parsing automatique des logs… :siffle:</p>
<p>À très bientôt !</p>
<center>:marioCours:</center>Faire un AOV d’occlusion avec la DiffuseColor dans Guerillaurn:md5:9eabbc909fb9e257a5159df830d120062021-10-09T23:29:00+02:002021-11-18T10:24:26+01:00NarannInfographie 3D - Boulotambientaovguerillaocclusion<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_tn.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Il y a plein de façons de faire de l’<em>ambiant occlusion</em>. :hehe: Certains sortent cette passe au moment du lighting pour donner de la flexibilité au compo ; pour assombrir les creux. D’autres sortent cette passe avant l’étape de rendu, au moment de l’animation, voir du layout ; pour du contrôle qualité. Dans chaque situation, le contenu de la passe d’<em>ambiant occlusion</em> est adapté au besoin ; pour du compo il faut qu’elle soit en niveaux de gris, pour du contrôle qualité on peut afficher chaque objet avec une couleur particulière, etc.</p>
<p>Quand le lookdev des assets est (enfin) disponible, il peut être intéressant d’avoir une <em>ambiant occlusion</em> générée avec les textures de lookdev plutôt que des couleurs uniformes. C’est ce que nous allons faire dans ce billet. :bravo:</p> <h3>Méthode de base</h3>
<p>Avant de faire des choses compliquées, on peut s’appuyer sur ce que Guerilla propose, à savoir les AOVs <em>Occlusion</em> et <em>Albedo</em>. Voici une scène éclairée avec amour :petrus: :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_001.png" style="margin: 0px auto; display: table; width: 261px; height: 203px;" /></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_002.png" style="margin: 0 auto; display: table;" /></p>
<p>Le lookdev des objets, c’est juste une texture colorée différente mise dans l’attribut « DiffuseColor » de leur « Surface2 » respectif. :siffle:</p>
<p>On lui ajoute les deux AOVs, <em>Occlusion</em> et <em>Albedo</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_003.png" style="margin: 0 auto; display: table;" /></p>
<p>Utiliser cette méthode implique de devoir recompositer les deux images en sortie de Guerilla (via un précomp, par exemple), mais ça nous oblige à gérer un processus externe. Ce serait quand même plus simple si Guerilla pouvait sortir l’ambiant occlusion en utilisant directement l’Albedo. :reflechi:</p>
<p>Ce n’est pas possible directement (on ne peut pas utiliser un AOV dans un autre AOV), mais on peut s’en rapprocher de façon détournée (disons).</p>
<h3>Logique de récupération des shaders dans Guerilla</h3>
<p>Petit rappel au cas où vous ne seriez pas au courant. :mayaProf:</p>
<p>Quand vous assignez un material dans un RenderGraph, Guerilla n’assigne en fait qu’un nom (ici, « Surface2 ») à l’attribut <em>shader.surface</em>. Pour vous donner une idée, sélectionnez un objet, faites « Shift+D » et regardez votre console pour voir la liste des attributs qui seront envoyées au moteur :</p>
<pre>
<code class="language-markdown">...
shade.opacity: 1
shade.opacitybakeres: {256,256}
shader.displacement: ""
shader.surface: "Surface2" << Notre assignation de shader de surface, ici.
shader.volume: ""
shade.scale: 1
shade.subshadersuseexternal: false
...</code></pre>
<p>Au moment de l’envoi au moteur, Guerilla va chercher le material auquel correspond ce nom en suivant une logique assez particulière :</p>
<ul>
<li>Votre scène.</li>
<li>La librairie.</li>
</ul>
<p>Pour faire court, si un material nommé « Surface2 » est présent à la racine de votre scène, il sera utilisé à la place du <em>Surface2</em> de la librairie :</p>
<p><img alt="Guerilla surface2 scene vs library" class="media" height="242" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/guerilla_ao_diffuse_color_001.png" style="margin: 0px auto; display: table;" width="405" /></p>
<p style="text-align: center;"><em>Ici, c’est le Surface2 à gauche qui sera envoyé au moteur, prenant le pas sur celui de la librairie, à droite. </em>:tuComprendRien:</p>
<p>Et comme vous le savez sûrement, il est possible de modifier le material importé dans votre scène. Ces deux particularités permettent, finalement, d’éditer le comportement d’un shader pour toute la scène. :idee:</p>
<p>Donc si on modifie notre <em>Surface2</em> importé localement afin que sa seule sortie soit une <em>occlusion</em> multipliée par son attribut <em>DiffuseColor</em>, le calcul d’illumination de tous les objets sera l’ambiant occlusion utilisant ses propres textures.</p>
<p>Faisons donc ça ! :youplaBoum:</p>
<h3>Méthode avancée</h3>
<p>Créez un shader Surface2 à la racine (« Ctrl+Espace », « surface2 », « Entrée ») :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_004.png" style="margin: 0px auto; display: table; width: 286px; height: 94px;" /></p>
<p>Le shader s’importe à la racine de votre scène :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_005.png" style="margin: 0px auto; display: table; width: 624px; height: 188px;" /></p>
<p>Entrez à l’intérieur et supprimez tout ce que vous y trouvez !</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_006.png" style="margin: 0 auto; display: table;" /></p>
<blockquote>
<p>Notez qu’un bug est présent en version 2.3.0, il faut laisser le nœud « Surface » pour avoir un rendu correct. Ce bug est corrigé en version 2.3.1.</p>
</blockquote>
<p>Ajouter un nœud AOV (« Ctrl+Espace », « aov », « Entrée ») :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_007.png" style="margin: 0px auto; display: table; width: 125px; height: 134px;" />Renommer « Value » par un nom perso « ColoredAO » :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_008.png" style="margin: 0px auto; display: table; width: 446px; height: 251px;" /></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_009.png" style="margin: 0 auto; display: table;" /></p>
<p>Mettre un nœud « Occlusion » et le connecter à « ColoredAO » :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_010.png" style="margin: 0px auto; display: table; width: 231px; height: 192px;" /></p>
<p>Dans la RenderPass, créez un AOV. Vous pouvez le nommer comme vous voulez :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_011.png" style="margin: 0px auto; display: table; width: 249px; height: 139px;" /></p>
<p>Dans cet AOV, mettez <em>Accepted expression</em> à <em>[Technical] Primary</em> et <em>Shader Color</em> à <em>ColoredAO</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_012.png" style="margin: 0px auto; display: table; width: 439px; height: 277px;" /></p>
<p>Si vous rendez à ce stade, vous aurez une occlusion tout simple :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_013.png" style="margin: 0px auto; display: table; width: 512px; height: 384px;" /></p>
<p>Mais ce qu’on veut, c’est de la couleur ! :perplex:</p>
<p>Pour ça, il faut renommer le paramètre responsable de la couleur (ici, blanche) pour qu’il utilise la « DiffuseColor ». Sélectionnez votre nœud « Occlusion » et renommez l’attribut « SkyColor » en « DiffuseColor » :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_014.png" style="margin: 0px auto; display: table; width: 269px; height: 457px;" /></p>
<p>Puis cochez « Exposed » :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_015.png" style="margin: 0px auto; display: table; width: 320px; height: 138px;" /></p>
<p>Notez que vous pouvez le faire en cliquant sur l’attribut du nœud, directement dans le graph :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_016.png" style="margin: 0px auto; display: table; width: 132px; height: 207px;" />Et sous vos yeux ébahis :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_017.png" style="margin: 0px auto; display: table; width: 512px; height: 384px;" /></p>
<h3>Que pour les « Surface2 » ?</h3>
<p>Si vous n’overridez que le <em>Surface2</em> sur votre scène de production, vous allez vite vous rendre compte que ça ne fonctionne pas sur beaucoup de surfaces. En effet, il faut faire cet override sur tous les types de shader que vous utilisez dans vos scènes. Avec un peu de chance ça devrait se résumer aux <em>Hair</em>, <em>Curve</em> et <em>Eye</em>.</p>
<p>Il faut adapter le nom de l’attribut pour chaque type de shader. Si dans le cas du « Surface2 », l’attribute « DiffuseColor » fera très certainement l’affaire, dans le cas du shader de <em>Hair</em> ou de <em>Curve</em>, vous utiliserez sûrement la « Color » ou la « RootColor », suivant votre workflow. :pasClasse:</p>
<p>Notez que vous pouvez aussi multiplier les couleurs vous-même si le cœur vous en dit (je n’ai jamais testé) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_019.png" style="margin: 0px auto; display: table; width: 445px; height: 251px;" /></p>
<h3>Le cas du shader de Eye</h3>
<p>Le cas du Eye shader est plus compliqué, car il ne dispose pas d’attribut de shader défini, comme le « DiffuseColor » du « Surface2 ». :bete:</p>
<p>Pour que ça fonctionne, il faut l’évaluer totalement. Pour cela, connectez directement l’Albedo à occlusion, comme ici :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_10_09_ambiant_occlusion_aov_diffuse_color/scene_cube_and_sphere_018.png" style="margin: 0px auto; display: table; width: 405px; height: 251px;" /></p>
<p>Ceci évalue tout le shader des yeux, mais comme ils ne sont pas particulièrement coûteux, on peut se le permettre.</p>
<p>Voilà ! En espérant que ça serve à quelqu’un !</p>
<p>À très bientôt !</p>
<center>:marioCours:</center>Les variations de lookdev par tags dans Guerillaurn:md5:82a7c9a4470a1e19db42755b8954104d2021-10-02T23:32:00+02:002021-10-02T23:32:00+02:00NarannInfographie 3D - Boulotguerillalookdevtagvariation<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_21_var_lookdev_guerilla_tag/variation_lookdev_tag_01_001_tn.png" style="float: left; margin: 0px 1em 1em 0px;" />Dans ce billet, je vous propose une méthode pour gérer les variations de lookdev. Nous allons voir que la notion de « variation » est un concept assez flou tant il peut rapidement impacter tous les départements. En pratique, il peut y avoir plusieurs méthodes, chacune ayant ses spécificités. :sourit:</p>
<p>Cette méthode est une des plus simples à mettre en place. Vous allez voir que la partie dans Guerilla est assez rapide, mais ce sera surtout un prétexte pour réfléchir à comment organiser son travail dans le cadre d’une production. :sauteJoie:</p>
<p>La conclusion restera ouverte…</p> <h3>La variation, un concept flou</h3>
<p>S’il y a bien un truc difficile à exprimer correctement en production, c’est le concept de « variation ». J’ai tendance à éviter d’utiliser ce mot en réunion, car il dispose d’un pouvoir de confusion assez important (au prorata du nombre de personnes dans la discussion). Et si la confusion n’est pas instantanée (chacun comprenant ce qu’il veut) elle le devient dès que le mécanisme entre concrètement dans le pipeline et que les départements commencent à interagir avec lui. C’est à ce moment-là que <strong>tout le monde</strong> comprend que <strong>personne</strong> ne voyait la même chose. :tuComprendRien:</p>
<p>Mais pourquoi ? D’où vient le problème ? :reflexionIntense:</p>
<p>Chacun peut y aller de sa petite théorie, la mienne étant qu’il y a un écart énorme entre l’idée de « variations », qui est un concept très large, et sa réalité en production qui est contrainte par des choses très concrètes, elles-mêmes dépendante de ce qu’on cherche à faire varier. :redface:</p>
<p>Intégrer un concept de variation nécessite de se poser pas-mal de questions. En vrac :</p>
<p>Si j’ai « toto » et sa variation « sale ». Est-ce que « sale » est une surcouche/override (et donc dépends) de « toto » ? Si oui, quelles sont les implications pour « toto » ? Sa hiérarchie, ses attributs, ses tags, etc. Et si ces choses sont modifiées, comment réagit la variation ? N’est-ce pas à la variation de s’ajuster à « toto » et non l’inverse ? Y a-t-il un risque, une fois en production qu’un plan soit fait avec une version de « toto » et de « sale », mais que la nouvelle version de « toto » casse la variation ? Comment gérer ça ? Dois-je bloquer les versions une fois un plan commencé ? OK, mais si la gestion du blocage des versions au plan est trop chronophage pour les gens qui doivent maintenant constamment mettre des choses à jours des choses, car on est en flux tendu, alors qu’avant, ils ne se posaient pas la question, est-ce que le coût de gestion des variations n’est pas en trains de beaucoup trop complexifier le pipeline ?</p>
<p>Finalement, pourquoi s’embêter à gérer « toto » et « sale » de façon indépendante, ne serait-il pas plus simple de combiner « toto » et « sale » pour avoir un asset « toto_sale » et en faire ce que je veux ? Mais si les UVs de base de « toto » changent avec sa texture, ai-je un mécanisme de propagation des modifications ? Mais est-ce que ce n’est pas trop lourd si j’ai une variation « propre » qui apparaît…</p>
<p>Il est impossible de trouver un système qui permet de résoudre tous ces problèmes d’un coup, et ce n’est pas le but. :cayMal:</p>
<p>Ce qu’il faut comprendre, c’est que si vous n’êtes pas au clair sur ce que le système que vous mettez en place pourra faire ou non, vous prenez le risque de mettre des gens en difficulté (en imposant un suivi supplémentaire aux équipes). :triste:</p>
<p>Mon humble conseil est donc de ne jamais utiliser le terme « variation » sans y coller un terme caractérisant « son implémentation technique » (une expression pompeuse pour dire « la méthode utilisée dans le logiciel »), par exemple :</p>
<ul>
<li>Variation par tag.</li>
<li>Variation par set.</li>
<li>Variation par groupe.</li>
<li>Variation par attribut.</li>
<li>Variation par PrimVar.</li>
<li>Variation par tag d’asset.</li>
<li>Variation par namespace.</li>
<li>etc.</li>
</ul>
<p>Vous remarquez qu’il n’y a pas un, mais des mécanismes de variations. En utilisant de tels termes, vous imposerez implicitement à tout le monde de s’accorder sur la méthode et vous simplifierez pas-mal de discussions avec et entre les superviseurs. :titille:</p>
<p>Gardez à l’esprit qu’il n’est pas utile que tout le monde comprenne toutes les subtilités de ces mécanismes, juste que les gens communiquent avec des termes différents pour désigner des choses différentes.</p>
<p>Fini le pâté de texte, maintenant on rentre dans le vif du sujet ! :enerve:</p>
<h3>Présentation de la méthode par tag</h3>
<p>C’est sûrement la plus simple, et celle que vous avez instinctivement en tête quand vous utilisez Guerilla, tant les tags y sont omniprésents. Pourtant, vous allez voir que même dans ce cas il y a plusieurs façons de les utiliser. :joue:</p>
<h3>À l’intérieur du RenderGraph</h3>
<p>Vous pouvez embrancher votre lookdev directement dans le RenderGraph de lookdev, via l’utilisation d’un tag :</p>
<p><img alt="Variation par tag dans un RenderGraph Guerilla" class="media" height="372" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_21_var_lookdev_guerilla_tag/variation_lookdev_tag_01_001.png" style="margin: 0px auto; display: table;" width="665" /></p>
<p>Ici, « var1 » et « var2 » applique un override sur le shader « Surface2 ».</p>
<h3>Via un RenderGraph dédié</h3>
<p>L’idée est d’avoir un RenderGraph s’appliquant <em>après</em> celui du lookdev (attribut <em>order</em> plus élevé) et dédié à l’override d’attributs propres à cette variation :</p>
<p><img alt="Variation par RenderGraph dans Guerilla" class="media" height="321" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_21_var_lookdev_guerilla_tag/variation_lookdev_tag_02_001.png" style="margin: 0px auto; display: table;" width="689" /></p>
<p>Remarquez comme on a juste découpé le RenderGraph précédent.</p>
<p>Ensuite, on configure les deux RenderGraph (de droite) pour qu’ils s’appliquent sur leur tag respectif (et un <em>order</em> suivant celui du RenderGraph de base) :</p>
<p><img alt="" class="media" height="64" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_21_var_lookdev_guerilla_tag/variation_lookdev_tag_02_002.png" style="margin: 0px auto; display: table;" width="234" /></p>
<p>Au passage, en faisant ceci, c’est le RenderGraph qui défini le tag sur lequel il s’applique (« var1 » sur l’image), il est donc inutile d’utiliser un nœud de tag (« var1 » ou « var2 ») à l’intérieur du RenderGraph.</p>
<p>S’arrêter à ce stade pose pas mal de problèmes :</p>
<p>Ici, j’assigne uniquement le tag de variation (« <em>var1</em> ») au RenderGraph, mais ça veut dire que si deux assets ont ce tag, ils passeront tous les deux dans ce RenderGraph. Ça veut dire ce RenderGraph devra gérer la « <em>var1</em> » d’assets très différents (chaise, maison, personnages, montagnes) et que ça fonctionne tout le temps. Même si cela peut être une méthode en soit (si on souhaite utiliser cette méthode de façon générale, sur son pipeline) il y a peu de chance que ce soit vraiment ce que vous souhaitiez faire. En effet, overrider globalement des attributs artistique de lookdev, c’est le risque de se retrouver avec une chaîne de RenderGraphs qui applique trop des choses. :perplex:</p>
<p>Au lieu d’assigner un seul tag « <em>var1</em> » à ce RenderGraph, on peut également lui coller un second tag, lié à l’asset. Dans le cas de l’asset chaise, on aurait : « <em>asset_chaise, var1</em> ». Faire cela résout notre problème d’assignation trop « large », mais implique que le reste de votre pipeline passe par l’assignation par tag. Si c’est ce que vous voulez, tant mieux. Mais sachez que vous n’aurez pas toujours cette option (si votre pipeline utilise «<em> prefix</em> » où « <em>reference</em> », par exemple).</p>
<p>La première méthode (À l’intérieur du RenderGraph) à l’avantage de supporter toutes les méthodes d’assignation de RenderGraph :laClasse: , mais peut devenir limitante si vos variations sont importantes.</p>
<h3>Un nœud SetTags, pour les chambouler tous !</h3>
<p>J’en profite pour dire qu’il existe un nœud <em>SetTags</em> qui permet d’assigner dynamiquement des tags à des objets (via des <em>regex</em> dans des <em>Path</em>, par exemple). La seule contrainte étant que ce nœud doit être dans un RenderGraph <em>précédent</em> le RenderGraph utilisant le tag :</p>
<p>Si un RenderGraph « A » utilise le nœud <em>SetTags pour </em>appliquer le tag « toto » sur des objets, ce tag ne pourra être utilisé que dans RendreGraph « B », dont l’attribut <em>order</em> est plus grand que celui de « A ». On aurait donc une chaîne de RenderGraph ressemblant à ça :</p>
<p><img alt="" class="media" height="345" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_21_var_lookdev_guerilla_tag/variation_lookdev_tag_03_set_tag_01.png" style="margin: 0px auto; display: table;" width="608" /></p>
<p>L’ubiquité des tags dans Guerilla fait qu’un tel nœud offre des possibilités intéressantes, mais gardez à l’esprit que trouver une méthode qui fonctionne, ce n’est que 50 % de la réflexion. Il vous faut identifier ce que vous ne pouvez pas faire et estimer si c’est pénalisant. :neutral:</p>
<p>Ce besoin de passer par deux RenderGraph n’est pas une contrainte négligeable, en particulier quand plusieurs départements relatifs au rendu (lookdev, lighting, compo) veulent aussi pouvoir le faire.</p>
<h3>La limitation de la méthode par tag</h3>
<p>Nous avons vu plusieurs façons d’utiliser les tags pour faire des variations de lookdev. L’objectif n’était pas tant de vous apprendre des choses sous Guerilla que de vous ouvrir aux questions que pose l’organisation d’un workflow de variations. :bete:</p>
<p>Ces mécanismes de gestion des tags ont en commun de s’appuyer sur le <em>SceneGraph</em> (la <em>Node List</em>), c.-à-d. sur les nœuds de la scène. Si c’est cette particularité qui donne de la flexibilité au système (en permettant des modifications directement dans Guerilla), cela devient limitant quand on cherche à travailler « sous » l’objet. Par exemple, pour un système de particule dont on souhaite faire varier les instances et leur lookdev.</p>
<p>Cela pourra faire l’objet d’un billet dédié… :jdicajdirien:</p>
<p>Les petits malins, adeptes de Houdini, pourraient être tentés de sortir autant de fichier Alembic qu’il y a de variation, chaque Alembic ne contenant <em>que</em> les objets d’une seule variation et d’appliquer un tag sur chacune des références. Ça fonctionne (je confirme ! :aupoil: ), mais c’est un cas classique de « contorsion du pipeline » : Ont fait rentrer un nouveau type de problèmes en se servant d’un mécanisme existant et fiable, mais de façon peu élégante. Ce genre de bricolage peut être courant sur des gros pipelines de production (avec parfois, des outils dédiés !).</p>
<p>En espérant vous avoir donné des éléments de réflexion sur le sujet. :youplaBoum:</p>
<p>À bientôt !</p>
<center>:marioCours:</center>Faire un AOV de translucence avec Guerillaurn:md5:593d9f409a9e93b5eef19fae39da14832021-09-19T18:25:00+02:002021-09-20T16:06:01+02:00NarannInfographie 3D - Boulotaovguerillarendutranslucence<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_18_guerilla_translucence/guerilla_translucence_tn.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />La <em>translucence</em> est un effet couramment utilisé en rendu pour les surfaces fines ; feuilles, papiers, etc. Il permet de récupérer l’illumination et les ombres projetées d’un côté pour les projeter de l’autre.</p>
<p>Si vous utilisez Guerilla (ce que vous devriez faire… :siffle: ) vous avez peut-être remarqué que la <em>translucence</em> n’est présente dans aucun AOV de base.</p> <h3>Réponse courte</h3>
<p>Vous avez des plans à sortir, pas l’temps d’niaiser. :grenadelauncher:</p>
<ul>
<li>Créez un AOV.</li>
<li>Mettez <strong>C<TD>.*#</strong> dans <em>Accept Expression</em>.</li>
<li>Rendez.</li>
<li>C’est gentil d’être passé. :baffed:</li>
</ul>
<h3>Réponse illustrée</h3>
<p>Si vous regardez du côté de <a href="http://guerillarender.com/doc/2.3/User%20Guide_Rendering_Light%20Path%20Expression.html">la documentation</a> des <em>Light Path Expression</em> (LPE), vous verrez qu’il est explicitement stipulé que la <em>translucence</em> ne fait pas partie de l’AOV de Diffuse :</p>
<blockquote>
<p>Note that this expresion <b>does not</b> include the translucence, as it is categorized as <strong class="lpe_tag"><TD></strong> for Transmitted Diffuse.</p>
</blockquote>
<p>Ça me fait penser qu’il faudra vraiment que je fasse un vrai billet sur les LPE… :pasClasse:</p>
<p>Si votre boulot c’est de sortir des images, je vous invite à regarder et vous familiariser avec ce tableau qui liste ce que les AOVs de base représentent en termes de LPE.</p>
<p>Je vais prendre la scène d’exemple livré avec Guerilla dans : Help/Samples/Surface.</p>
<p>Créez l’AOV. Nommez-le comme vous voulez (Utilisez « Translucence » si vous n’êtes pas inspiré… :jdicajdirien: ) et mettez le <em>light path expression</em> <strong>C<TD>.*#</strong> dans <em>Accept Expression</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_18_guerilla_translucence/guerilla_translucence_panel.png" style="margin: 0px auto; display: table; width: 404px; height: 255px;" /></p>
<p>Note : Vous devriez pouvoir mettre « Caustics » dans <em>Ignore Expression</em> pour être cohérent avec les AOVs de base, mais je ne suis pas sûr de moi, à vérifier. :reflexionIntense:</p>
<p>Arrêtons-nous un peu sur cette expression. :reflechi:</p>
<p>Les LPE sont un peu au lancer de rayon ce que <a href="https://fr.wikipedia.org/wiki/Expression_r%C3%A9guli%C3%A8re" hreflang="fr" title="page wikipédia sur les expressions régulières">les expressions régulières</a> (<em>regex</em>) peuvent être aux chaînes de caractères. :redface:</p>
<p>Oui, donc il faut savoir ce que sont les <em>regexs</em>, mais si vous faites du lighting, je pars du principe que vous en avez déjà entendu parler. :youplaBoum:</p>
<p>Il y a trois types de propagation de rayons, chacune représenté par une lettre :</p>
<ul>
<li>Spéculaires « <strong>S</strong> ».</li>
<li>Glossy « <strong>G</strong> ».</li>
<li>Diffuse « <strong>D </strong>».</li>
</ul>
<p>Et quatre types de rayons :</p>
<ul>
<li>Réflexion « <strong>R </strong>» : Les rayons rebondissants sur la surface ; miroirs, parquets, métaux brossés, etc.</li>
<li>Transmission « <strong>T </strong>» : Ou « Réfraction », Les rayons entrants dans la surface ; verre, feuilles fines (nos surfaces translucides, justement).</li>
<li>Volume « <strong>V </strong>» : Les rayons entrants dans un volume ; fumée, nuages, etc.</li>
<li>Intra-objet « <strong>O </strong>» : Les rayons se propageant dans l’objet lui-même (SSS).</li>
</ul>
<p>Note : On pourrait caler un cinquième type pour les rayons de caméras « <strong>C</strong> », mais ce dernier ne peut pas se combiner à un type de propagation (c’est un rayon de caméra, point barre… :redface: ).</p>
<p>Et tout ça peut se mélanger :</p>
<ul>
<li><strong>RS</strong> les réflexions brutes (miroirs).</li>
<li><strong>RG</strong> les réflexions douces (parquets, métaux brossés).</li>
<li><strong>RD</strong> les réflexions de diffuse (illumination indirect).</li>
</ul>
<p>Pareil pour <strong>VS</strong>, <strong>VG</strong>, <strong>VD</strong>, etc. :hehe:</p>
<p>L’expression <strong>C<TD>.*# </strong>prend tous les rayons partant de la caméra (<strong>C</strong>), de type transmission diffuse (<strong>TD</strong>), quel que soit le type de rayon « après » <strong><TD></strong>.</p>
<p>Le « <strong>.*</strong> » est un caractère (le <em>point</em>) et un quantificateur (l’<em>astérisque</em>) :</p>
<ul>
<li>Le <em>point</em> est un caractère spécial voulant dire « n’importe quel rayon ».</li>
<li>L’<em>astérisque</em> est un quantificateur s’appliquant au caractère qu’il précède et veut dire « aucune fois, 1 fois ou plus ».</li>
</ul>
<p>Le dernier caractère « <strong>#</strong> » bloque l’expression qui ne peut aller plus loin (ça ne veut pas dire que le moteur s’arrête, juste que c’est cette partie du rayon qui sera stocké en AOV).</p>
<p>En gros, l’expression <strong>C<TD>.*# </strong>prends n’importe quel rayon venant de la <em>translucence</em>.</p>
<p>On a donc :</p>
<p>La Translucence direct : <strong>C<TD>#</strong><br />
La Translucence indirect : <strong>C<TD>.+#</strong><br />
Les deux (celle qu’on utilise ici) : <strong>C<TD>.*#</strong></p>
<p>Si vous êtes habitué aux regex, vous devriez comprendre ces expressions, mais ça ne nous dit pas vraiment ce qu’il y a dedans…</p>
<p>La « Translucence direct », c’est l’illumination <em>direct</em> sur la surface opposée à ce qu’on voit. C.-à-d. la lumière (direct) et les ombres projetées sur la face opposée à notre regard.</p>
<p>La « Translucence indirect » c’est l’illumination <em>indirect</em> (la diffuse) sur la surface opposée à ce qu’on voit. En gros, l’équivalent à ce que sortirait l’AOV de <em>Diffuse Indirect</em> si on regardait la surface de l’autre côté.</p>
<p>Mettez une couleur de translucence à l’une des sphères (un vert pur, pour montrer que vous avez du goût :vomit: ) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_18_guerilla_translucence/guerilla_translucence_attribute.png" style="margin: 0px auto; display: table; width: 400px; height: 118px;" /></p>
<p>Puis rendez.</p>
<p>La Beauty :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_18_guerilla_translucence/guerilla_translucence_result_diffuse.png" style="margin: 0px auto; display: table; width: 241px; height: 160px;" />L’AOV <em>Translucence</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_09_18_guerilla_translucence/guerilla_translucence_result_aov.png" style="margin: 0px auto; display: table; width: 279px; height: 177px;" /></p>
<p>Et voilà ! En espérant que ça serve à quelqu’un !</p>
<p>À très bientôt !</p>
<center>:marioCours:</center>Guerilla, Hair, et Back specularurn:md5:e76a2ab68fe302c89c0cd8f23e5b93582021-06-06T14:34:00+02:002021-09-21T14:41:19+02:00NarannInfographie 3D - Boulotaovguerillapoilrenduspéculaire<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/in_diffuse_wip_tn.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Aujourd’hui un billet inutile et vraiment spécifique pour vous parler d’un problème que vous ne rencontrerez sûrement jamais. :laClasse: En fait il est probable que vous ne rencontriez ce problème que sur de la série, où la contrainte de la puissance de calcul est importante. :pafOrdi:</p>
<p>Quand on rend des poils avec le shader <em>Hair</em> de Guerilla (et je suppose avec n’importe quel autre moteur de rendu) il peut être intéressant de supprimer les-dit poils du trace set <em>« Diffuse</em> » pour économiser leur coût de calcul dans l’indirect (BIM ! Direct dans le bain sans politesse ni respect pour son lecteur :grenadelauncher: ), mais dans ce cas précis, on risque d’obtenir un effet bizarre, presque esthétique, et je vous propose de voir ce dont il s’agit. :hehe:</p> <h3>Le <em>back</em> dans le shader <em>Hair</em></h3>
<p>Dans la vraie vie vivante qu’on partage avec ces foutus moustiques si propice à ruiner cette si chouette période de l’année :fuck: , les poils ont des propriétés physiques difficiles à modeler. Les shaders de poils ne sont pas les trucs les plus simples à comprendre et à coder :perplex: . Un petit coup d’œil sur le papier <a href="https://www.graphics.stanford.edu/papers/hair/hair-sg03final.pdf" hreflang="en">Light Scattering from Human Hair Fibers</a> devrait vous convaincre. <a href="https://www.cemyuksel.com/research/dualscattering/dualscattering.pdf" hreflang="en">Et</a> <a href="https://www.researchgate.net/profile/Eugene-Deon/publication/220506677_An_Energy-Conserving_Hair_Reflectance_Model/links/59dc2874a6fdcc1ec89fb0c0/An-Energy-Conserving-Hair-Reflectance-Model.pdf" hreflang="en">si</a> <a href="https://graphics.pixar.com/library/DataDrivenHairScattering/paper.pdf" hreflang="en">vous</a> <a href="https://benedikt-bitterli.me/pchfm/" hreflang="en">êtes</a> <a href="https://www.pbrt.org/hair.pdf" hreflang="en">motivé</a>…</p>
<p>Au passage, je pense que le rendu temps-réel est complètement à la ramasse sur ce sujet. <em>« Le temps-réel, c’est le futur »</em>, sauf si on a encore des cheveux, sinon : :vomit:</p>
<p>Si vous utilisez le shader <em>Hair</em> de Guerilla, dont la documentation se trouve <a href="https://guerillarender.com/doc/2.3/Library_Materials_Hair.html" hreflang="en" title="Page de documentation du shader Hair de Guerilla">ici</a> (avec des potards à bouger comme dans vos logiciels préférés ! :bravo: ), vous savez qu’il se compose de trois composants de spéculaires ; <em>primary</em>, <em>secondary</em> et <em>back</em> (nous n’aborderons pas les paramètres <em>Multiple Scatter</em> et <em>Diffuse</em> :nannan: ).</p>
<p>Quand on regarde les images de la documentation officielle, on pourrait être tenté de confondre le <em>back</em> avec un effet de <em>rim</em> de light (une light, souvent forte, venant quasiment de derrière un modèle) :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/marschner.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/guerilla_hair_back.png" style="margin: 0px auto; display: table;" width=200 height=200 /></a></p>
<p>Nous allons voir que le <em>back</em> n’a rien à voir avec une <em>rim</em>.</p>
<p>Cette image dérobée sur <a href="https://guerillarender.com/doc/2.3/Library_Materials_Curves.html" hreflang="en" title="Page de documentation du shader Guerilla Curve">la page de documentation</a> du shader <em>Curve</em> permet de simplifier le comportement qu’on cherche à reproduire avec ces trois composants :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/marschner.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/.marschner_m.png" style="margin: 0px auto; display: table;" width=680 height=309 /></a></p>
<p>Nous avons donc trois composants :</p>
<ul>
<li>La primaire correspond aux réflexions à la surface du poil (en rouge sur le schéma).</li>
<li>La secondaire correspond aux réflexions internes à l’intérieur du poil (en violet).</li>
<li>Et une dernière, le <em>back</em> correspond à la transmission à travers le poil (en vert).</li>
</ul>
<p>Notez à que le <em>back</em> est dans l’alignement de la <em>light</em>.</p>
<p>C’est ici qu’on comprend quelle différence il y a avec une <em>rim</em> light et que ça devient visuellement intéressant. Là où on s’imagine assez bien le comportement des deux premiers spéculaires, qui réagissent à peu près comme sur un shader de base, en miroir (c.à.d, réfléchissent la lumière en face d’eux), l’intensité du spéculaire <em>back</em> dépend de la lumière qui se trouve derrière. :reflechi:</p>
<p>En gros : Plus la lumière <em>derrière</em> le poil (donc devant vous) est importante, plus le spéculaire de <em>back</em> apparaît. C’est contre-intuitif, et c’est pourquoi je vous demande de bien observer ce schéma et de l’avoir en tête pour la suite de ce billet.</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/maurane_back.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/.maurane_back_m.jpg" style="margin: 0px auto; display: table;" width=680 height=255 /></a></p>
<p>Vous l’aurez compris, c’est ce que produit le <em>back</em> qui va nous intéresser.</p>
<h3>Rendu</h3>
<p>Tout ça c’est bien joli, mais ça donne quoi en image ? :petrus:</p>
<p>Voici six AOV d’un rendu :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/out_diffuse_wip.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/out_diffuse_wip.png" style="margin: 0px auto; display: table;" width=600 height=400 /></a></p>
<p>La scène est composée :</p>
<ul>
<li>D’un plan avec <a href="https://drive.google.com/drive/folders/1K_G_hbFyohR8-xCCAlYx8xhsd_a7Ir7G" hreflang="en">une texture</a> de Maurus Loeffel (merci à lui) en <em>DiffuseColor</em>.</li>
<li>D’une sphère (rouge pur) faisant office de scalp à une procédurale de poils.</li>
<li>Sur les poils, un shader <em>Hair</em> par défaut, avec une <em>DiffuseColor</em> gris fonçé.</li>
<li>Une grosse <em>SquareLight</em> au-dessus (une « douche »).</li>
</ul>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/test_scene_guerilla.png" style="margin: 0px auto; display: table; width: 323px; height: 225px;" /></p>
<p>Dans l’ordre des AOVs, nous avons :</p>
<ul>
<li>Beauty, Albedo, Diffuse.</li>
<li>Specular, Reflection, IndDiffuse.</li>
</ul>
<p>Notez que les poils cachent totalement la sphère rouge (son scalp).</p>
<p>On remarque que le <em>back</em> est sur l’AOV de <em>Reflection</em> et semble visuellement jouer son rôle.</p>
<p>Mais pourquoi l’AOV de <em>Reflection</em> ?</p>
<p>Rappelez-vous : Le <em>back</em> simule le spéculaire de la lumière venant de derrière le poil. Pour faire cela, le moteur va lancer un rayon comme il le ferait pour un spéculaire standard, mais il va le faire suivant la logique du spéculaire <em>back</em>, tout droit, devant lui (voir schéma). Le <em>back</em> est donc une réflexion qui part dans le sens du rayon original. Le moteur va simplement traverser le poil et récupérer ce qui se trouve derrière. S’il tombe sur d’autres poils il s’arrête, sinon, il touche le plan texturé (d’où la teinte colorée du <em>back</em>).</p>
<p>On comprend pourquoi cet effet n’est visible que sur les bords des poils : Sur les bords, un rayon a peu de chances de croiser un autre poil sur sa route lorsqu’il trace le <em>back</em>, mais quand on se situe au milieu et qu’on trace le <em>back</em>, on tombe rapidement sur un ou plus de poils, ce qui arrête son tracé. On comprend aussi que par extension, le <em>back</em> a un coup de calcul important, par rapport à ce qu’il apporte ; il est tracé partout, mais n’apparaît que sur les bords.</p>
<p>Donc si vous avez des poils très courts et très denses, il faut sérieusement se poser la question de son apport artistique avant de l’activer, car son coût est important. :redface:</p>
<p>En effet, le temps de rendu de ma petite scène de sphère est de 1 min 43 sec (ça aura son importance dans la suite de ce billet).</p>
<p>Maintenant faisons notre super <em>trick</em> de la mort qui va nous permettre de sauver du temps de rendu, la production, notre salaire et draguer en discothèque : Supprimons les poils du trace set <em>« Diffuse »</em> (ici, via le nœud <em>« -Diffuse »</em>) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/fur_out_diffuse.png" style="margin: 0px auto; display: table; width: 381px; height: 146px;" /></p>
<p>(Au passage, je ne vais pas en discothèque, parce que tout le monde sait bien que<a href="https://youtu.be/antqm4BdEgg?t=4" hreflang="fr">…</a>)</p>
<p>Bref, on vire les poils du trace set <em>« Diffuse »</em> et on rend :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/in_diffuse_wip.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/in_diffuse_wip.png" style="margin: 0px auto; display: table;" width=600 height=400 /></a></p>
<p>On remarque immédiatement que l’AOV de <em>Reflection</em> est « bizarre » et ressemble plus à une sorte de verre trouble qu’une réflexion. Si vous avez bien suivi ce qu’on a dit plus haut, vous avez peut-être compris ce qui se passe. :sauteJoie:</p>
<p>Je vous disais que pour calculer le <em>back</em>, le moteur lance un rayon de réflexion, mais orienté dans son sens original (c’est le spéculaire de <em>back</em> qui veut ça, voir le schéma). S’il touche un autre poil, il s’arrête, s’il ne touche pas de poil, il touche le plan (ou parfois ici, la sphère faisant office de scalp). C’est pour ça qu’en principe, ça ne fonctionne que sur les bords, le rayon ayant peu de chances de taper d’autres poils.</p>
<p>Sauf qu’ici, il semble que tout le spéculaire de <em>back</em> se soit comporté comme s’il n’avait rencontré aucun poil… Comme si, le trace set utilisé pour tracer le <em>back</em> ne contenait pas les poils… D’ailleurs, il utilise quoi comme trace set Guerilla pour tracer ses poils ? :petrus:</p>
<p>Allez dans <em>« Hair / Advanced / Trace Set »</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/guerilla_hair_trace_set_diffuse.png" style="margin: 0px auto; display: table; width: 405px; height: 226px;" /></p>
<p>Mais, les bras m’en tombent ! :bete:</p>
<p>Alors forcément, là vous êtes pépouze, le cul posé dans votre siège à lire un billet de blog écrit avec amour et vous comprenez peut-être ce qui se passe, mais je vous assure que quand un rendu comme ça tombe dans votre boite mail avec pour objet : « UrGeNt ! A rEnDrE pOuR aVaNt Yèr !!11! », vous envisagez sérieusement une reconversion dans le recyclage de mugs usagés au tréfonds de la Sibérie. :casseTeteMur:</p>
<p>Vous l’aurez compris, en virant les poils du trace set <em>« Diffuse »</em>, vous avez purement et simplement supprimé les poils de leur propre réflexion… :slow_clap:</p>
<p>On peut se demander ce qu’on y gagne réellement : Après tout, il suffirait de remettre les poils dans le trace set <em>« Diffuse »</em> et on pourrait rendre sa production heureuse… :sourit:</p>
<p>C’est là qu’interviennent les temps de rendu. La dernière image, avec le poil supprimé du trace set <em>« Diffuse »</em> met 48 secondes à se calculer. Pour rappel, le rendu original met 1 min 43 sec, plus du double (l’écart n’est pas aussi important sur des rendus de production, mais pas loin). Ni l’un, ni l’autre n’est une solution acceptable pour la production.</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/maurane_rendu.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/.maurane_rendu_m.jpg" style="margin: 0px auto; display: table;" width=680 height=255 /></a></p>
<h3>Comment on fait ?</h3>
<p>Donc je disais : La Sibérie… :seSentCon:</p>
<p>OK, à partir d’ici il faut commencer à manipuler des trace set :enerve: , donc si vous n’êtes pas à l’aise avec ce concept, vous pouvez lâcher ce billet en choisissant :</p>
<ul>
<li>Soit vous avez une grosse ferme de calcul, vous laisser les poils dans la <em>Diffuse</em>. :grenadelauncher:</li>
<li>Soit vous êtes limité par votre puissance de calcul, vous pouvez proposer à la production de <s>niquer</s> virer l’<em>back</em>. :siffle:</li>
</ul>
<p>Et c’est gentil d’être passé ! :IFuckTheWorld:</p>
<p>Pour les autres, voici le moment que vous attendiez secrètement en commençant la lecture de ce billet, ce plaisir coupable qui vous prend quand vos temps de rendu foutent le camp, ce truc qui crée chez certains leads des envies de meurtre vis-à-vis de leurs graphistes partis en vacances, ce machin réfléchi et posé dans le wiki du studio avec plus grand sérieux du monde par le sup lighting en début de prod et qui n’a plus aucune réalité à la seconde où les premiers plans commencent à sortir. J’ai nommé : Les trace set. :youplaBoum:</p>
<p>En vrai, je taquine, car c’est loin d’être ingérable. :trollface:</p>
<p>En effet, comme le trace set par défaut, <em>« Diffuse »,</em> est celui contenant tout ce qui est tracé par les rayons d’indirect (et c’est bien la raison pour laquelle on vire les poils de ce trace set), il suffit que les poils aient leur propre trace set. :idee:</p>
<p>On peut imaginer un trace set <em>« Hair »</em> (ou <em>« Char_Hair »</em>, tant qu’à faire) contenant toutes les primitives de poil, et l’ajouter à la liste des trace set tracé par le (ou les) shader de <em>Hair</em> :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2021_06_guerilla_hair_back_spec_diffuse/trace_set_diffuse_hair.png" style="margin: 0px auto; display: table; width: 379px; height: 89px;" /></p>
<p>Avec une tel approche, les poils sont bien retirés du trace set <em>« Diffuse »</em> (c.à.d qu’ils ne sont pas pris en compte dans le calcul de l’indirect du reste de votre scène), mais ils sont pris en compte par le shader de <em>Hair</em>, et donc le <em>back</em> est calculé correctement. :papi:</p>
<p>Avec une telle approche le rendu est similaire à la première image (le <em>back</em> est joli tout pleins), à l’exception de l’AOV d’indirect qui devient totalement noir (les poils n’étant plus dans la diffuse) et le temps de rendu passe à 1 min 10 sec.</p>
<p>À vous de voir si c’est justifié. :sourit:</p>
<h3>Conclusion</h3>
<p>Comme le disait le poète :</p>
<blockquote>
<p>Sauve ta tournette, créé un trace set.</p>
</blockquote>
<p>À bientôt !</p>
<center>:marioCours:</center>Guerilla, le shutter et Yetiurn:md5:88bee7da37bd347ece0a511cad6ec3262019-08-19T22:55:00+02:002019-08-21T14:17:48+02:00NarannInfographie 3D - Boulotguerillarendermanshutteryeti<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_yeti_node_tn.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Dans ce billet on va encore parler de poils et tout particulièrement du <em>motion blur</em> de Yeti dans Guerilla.</p>
<p>Rien de révolutionnaire, on va juste faire le tour des choses à savoir quand on doit gérer cette combinaison. :reflechi:</p> <p>À l’époque, calculer le <em>motion blur</em> était très coûteux pour un <em>ray tracer</em>. Muni de nos passes de <em>motion vector</em> (en <em>.tiff</em>…), on bricolait au compo pour éviter de provoquer des crises d’épilepsie chez le spectateur (car à par les animateurs qui trouvent que l’effet stroboscopique d’un <em>playplast</em> est trop cool, tout le monde à mal au crâne).</p>
<p>C’était l’époque ou une roue ou une sphère tournant rapidement sur un plan n’augurait rien de bon… :triste:</p>
<p>S’il est intéressant de voir que les techniques à base de passes de <em>motion vector</em> au compo n’ont jamais complètement disparues, on ne peut, en revanche, pas ignorer que le <em>motion blur 3D</em> (c.à.d, rendu) arrive avec son lot de complications.</p>
<p>Ce billet part du principe que vous savez manipuler Yeti et Guerilla. :cayMal:</p>
<h3>Guerilla et le motion blur</h3>
<p>Il faut bien comprendre que Guerilla n’est pas un logiciel comme Maya qui va « sampler » la scène à des valeurs temporelles données. Il n’assume rien du sampling interne des éléments de la scène (<em>Alembic</em>, <em>Realflow</em>, etc.). Il récupère tout ce qui peut pour un <em>shutter</em> donné.</p>
<p>Ce mécanisme permet de faire coexister, dans une même scène, des <em>Alembic</em> exportés avec différentes valeurs de <em>step</em> (e.g. la majorité en 2 <em>samples</em> : 0.0-0.2 et les personnages rapides en 5 <em>samples :</em> 0.0-0.05-0.1-0.15-0.2, etc.).</p>
<h3>Les procédurales RenderMan</h3>
<p>Guerilla supporte <a href="https://rmanwiki.pixar.com/display/REN22/Procedural+Primitives" hreflang="en" title="Procedural Primitives">les procédurales</a> au format <em>RenderMan</em>. Une procédurale est un objet (une <em>primitive</em> plutôt) de votre scène de rendu qui déploie son contenu quand le moteur le demande (souvent, quand un rayon touche sa <em>bounding box</em>). À ce moment, le moteur appelle la procédurale avec ses paramètres. Chaque procédurale dispose de ses propres arguments, un peu comme une ligne de commande.</p>
<h3>La procédurale Yeti</h3>
<p>Pour que Yeti crache ses poils au moteur, il nécessite un fichier .fur généré par vous au moment de l’export Maya. Ce fichier contient tout ce qu’il faut à Yeti pour générer des poils :</p>
<ul>
<li>Le graph Yeti (celui que vous manipuler dans Maya).</li>
<li>Les guides (courbes).</li>
<li>Le groom.</li>
<li>La géométrie animée (le <em>scalp</em> de votre personnage) et samplé (à 0.0 - 0.2 par exemple).</li>
<li>La géométrie en <em>rest pose</em>, utilisé comme référentiel pour la distribution des poils sur la surface. Il faut que sa topologie soit identique à celle du <em>scalp</em>.</li>
</ul>
<p>La documentation du format de cache (.fur) est <a href="http://documentation.peregrinelabs.com/yeti/workingwithcaches.html" hreflang="en" title="Yeti - Working With Caches">ici</a> si vous voulez un peu plus d’information.</p>
<p>Au moment de l’appel de la procédurale, on lui donne ce fichier, ainsi que certain paramètres (<em>density</em>, <em>width</em>, <em>thread</em>, etc.) et elle fait ensuite son travail. :mechantCrash:</p>
<p>La documentation des paramètres de la procédurale Yeti se trouve <a href="http://documentation.peregrinelabs.com/yeti/commandlineandrendering.html#rendering" hreflang="en" title="Yeti procedural parameters">ici</a>. Si vous la regardez, vous remarquerez la présence de l’argument <em>--samples</em>. Comme expliqué, Yeti va cracher les samples de <em>motion blur</em> aux valeurs données dans cet argument.</p>
<h3>Yeti dans Guerilla</h3>
<p>Avant qu’un nœud Yeti d’interfaçage n’existe dans Guerilla, il fallait faire une <em>RIB box</em> contenant l’appel de la procédurale. Ce n’était pas super pratique, mais on avait un contrôle absolu sur l’appel (c’est nous qui donnions les arguments).</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_rib_box_001.png" style="margin: 0px auto; display: table; width: 244px; height: 93px;" /></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_rib_box_002.png" style="margin: 0px auto; display: table; width: 144px; height: 100px;" /></p>
<p style="text-align: center;"><em>Le manque d’icône devrait vous donner une idée du côté user friendly…</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_rib_box_003.png" style="margin: 0px auto; display: table; width: 388px; height: 160px;" /></p>
<p style="text-align: center;"><em>Et toto.rib est le fichier ouvert par Guerilla.</em></p>
<p>Pour vous donner une idée de ce qu’on écrivait dans ce fichier :</p>
<pre>
<code class="language-bash">Procedural "DynamicLoad" ["pgYetiPrmanRender" --density 1 --length 1 --width 1 --frame 1 --samples 0.0 0.2 --file "/path/to/my.fur"]</code></pre>
<p><a href="https://renderman.pixar.com/resources/RenderMan_20/proceduralPrimitives.html#procedural-primitive-dsos" hreflang="en" title="Procedural Primitives">Du bonheur en boite</a> ! :petrus:</p>
<p>Comme c’était <em>un brin</em> casse-pieds, un nœud Yeti a vu le jour :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_yeti_node.png" style="margin: 0px auto; display: table; width: 389px; height: 272px;" /></p>
<p style="text-align: center;"><em>Documentation du nœud <a href="http://guerillarender.com/doc/2.2/TD%20Guide_Third%20Party%20Tools_Yeti.html" hreflang="fr" title="Documentation du nœud Yeti dans Guerilla">ici</a>.</em></p>
<p>Ce nœud encapsule la procédurale, ce qui lui permet de bénéficier du <em>workflow</em> de Guerilla (<em>overrides</em> notamment). Dès lors, il faut se demander quelles sont les valeurs que Guerilla passe à <em>--samples</em> ?</p>
<p>Et bien, par défaut, Guérilla demande deux samples, un au <em>shutter open</em> et l’autre au <em>shutter close</em> du projet. Rappelez-vous :</p>
<ul>
<li>Guerilla ne peut pas savoir quels sont les samples présents dans le .fur.</li>
<li>La procédurale Yeti demande explicitement les samples à générer et ne permet pas de générer tout ce qu’elle a (ce pourrait être une demande légitime à faire au développeur).</li>
</ul>
<p>Pour pallier à ça vous pouvez passer une liste explicite de samples dans l’attribut <em>Motion Samples</em> du nœud Yeti de Guerilla. À vous, toutefois, de vous assurer que ces valeurs sont cohérentes avec ce qu’il y a dans votre <em>.fur</em> ainsi qu’avec le <em>shutter</em> fourni à Guerilla.</p>
<p>J’espère avoir rendu tout ça moins opaque. :pasClasse:</p>
<p>Un tout petit écart pour vous dire que vous pouvez baker la procédurale en <em>.ghostdata</em>. Guerilla va générer le contenu de la procédurale et l’enregistrer, vous pouvez ensuite l’importer dans et Yeti n’est plus nécessaire. Ce sera lourd, mais dans le cas d’éléments statiques c’est très pratique.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_yeti_node_bake_001.png" style="margin: 0px auto; display: table; width: 355px; height: 169px;" /></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/guerilla_yeti_node_bake_002.png" style="margin: 0 auto; display: table;" /></p>
<p>Et bien entendu, vous pouvez scripter ça :</p>
<pre>
<code class="language-python">import guerilla
guerilla.Procedural.baketoarchive("/path/to/my.ghostdata")</code></pre>
<p>Pensez-y si vous êtes ric-rac coté licences (et que vous avez <em>vraiment</em> beaucoup de stockage).</p>
<p>Fin de la parenthèse. :hehe:</p>
<h3>Jouer avec les paramètres Yeti</h3>
<p>Cette seconde partie s’apparente plus à du partage d’expérience sur le comportement de la procédurale Yeti elle-même.</p>
<p>Détail comme ça : Assurez-vous toujours que les valeurs de <em>FPS</em> sont identiques entre Maya et Guerilla. Évidant, mais comme un TD est amené à faire du support sur plusieurs projets, ce n’est pas inutile de le rappeler. Je me suis fait avoir lors d’un débogage sur un projet parallèle qui n’avait pas les mêmes <em>FPS</em> que le projet principal. :ideenoire:</p>
<p>Passons… :slow_clap:</p>
<p>Envisageons le scénario suivant : Le <em>.fur</em> Yeti est exporté sur 2 samples (0.0, 0.2). La trajectoire est donc linéaire :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/yeti_2_samples_001.png" style="margin: 0px auto; display: table; width: 283px; height: 148px;" /></p>
<p>Si Guerilla demande 0.0, 0.1, Yeti interpole correctement :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/yeti_2_samples_002.png" style="margin: 0px auto; display: table; width: 283px; height: 148px;" /></p>
<p>En revanche, si Guerilla demande 0.0, 0.3, Yeti « stop » le mouvement :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_17_mb_yeti/yeti_2_samples_003.png" style="margin: 0px auto; display: table; width: 381px; height: 148px;" /></p>
<p>D’un côté, c’est logique, Yeti ne peut vraiment fournir l’information. Gardez ça à l’esprit si vous augmentez vos <em>shutters</em> sur un plan pour ajouter un peu de <em>motion blur</em>. et que vos poils sont en décalage de vos <em>scalps</em>.</p>
<h3>Générer des bounding box pour ses .fur</h3>
<p><em>pgYetiCacheInfo</em> est une ligne de commande qui permet d’extraire quelques informations d’un <em>.fur</em>. La plus intéressante étant la <em>bounding box</em>.</p>
<p>En effet, <a href="http://guerillarender.com/doc/2.2/TD%20Guide_Third%20Party%20Tools_Yeti.html" hreflang="en" title="Yeti Guerilla">comme le dit clairement la doc</a>, Guerilla lui-même utilise <em>pgYetiCacheInfo</em> pour extraire la <em>bounding box</em>, mais de mécanisme par défaut est tellement lourd qu’un autre système est proposé.</p>
<p>Si un fichier <em>.bbox</em> existe à coté d’un <em>.fur</em>, Guerilla lira ce dernier pour en extraire la <em>bounding box</em>. L’idée est donc de générer ces fichiers au moment (enfin juste après) de la génération des .fur. Vous pouvez faire ça en farm. Gardez tout de mème à l’esprit que, sous le capot, <em>pgYetiCacheInfo</em> va générer le système de fur au complet. Donc les machines qui s’occupent de ça doivent en avoir dans le pantalon. :banaeyouhou:</p>
<p>Vous pouvez aussi bricoler cette <em>bounding box</em> vous-même depuis Maya en prenant celles des <em>scalps</em> que vous grossissez un peu, mais sur des systèmes de fur un peu complexe, vous risquez d’en faire une trop petite et payer la note au rendu.</p>
<p>Sachez également que l’argument –samples permet, comme pour la procédurale de prendre en compte les samples donnés pour la génération de la <em>bounding box</em>.</p>
<h3>Conclusion</h3>
<p>J’espère que ce billet vous aura plus, et que vous allez, etc. etc.</p>
<p style="text-align: center;">:marioCours:</p>LOD, suite et fin v2 (les poils)urn:md5:f60266c84b48fb9f0f29810ca97b35de2019-08-17T17:52:00+02:002019-08-19T19:46:42+02:00NarannInfographie 3D - Boulotautomatisationfurguerillalodmathpoil<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_fur_v2_tn.png" style="float: left; margin: 0 1em 1em 0;" />J’espère qu’avec ce billet je vais enfin terminer cette longue et indigeste série sur les LOD. :vomit:</p>
<p>Attaquons enfin la densité des poils au plan. Ce dernier billet va être un peu technique. On va faire un peu de trigonométrie (espace caméra, toussa) et parler de <em>farm</em>.</p> <p>Si vous avez suivi <a href="https://www.yumpu.com/en/document/read/43603224/stochastic-simplification-pixar-graphics-technologies" hreflang="en" title="Stocastic Simplification">un des liens</a> de <a class="ref-post" href="https://www.fevrierdorian.com/blog/post/2019/08/10/LOD-suite-et-fin">mon premier billet</a>, vous avez peut-être remarqué que la méthode stochastique est utilisée pour diminuer la densité des poils sur <em>Ratatouille</em> à la volée, au moment du rendu, en prenant en compte la distance, le <em>motion blur</em> et le <em>DOF</em>. Je ne reviendrais pas sur les raisons pour lesquelles ce n’est plus facilement faisable de nos jours (il faut lire le billet :IFuckTheWorld: ), mais l’idée générale reste inspirante et on peut tenter de se l’approprier pour bricoler quelque chose. :dentcasse:</p>
<blockquote>
<p>Cette méthode est un peu brouillonne et les habitués de trigonométrie auront sûrement une approche plus fine du problème.</p>
</blockquote>
<p>Sur un plan, on cherche à calculer la densité et l’épaisseur optimale des poils d’un personnage sur ce plan.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_density_width_proc.png" style="margin: 0px auto; display: table; width: 310px; height: 205px;" /></p>
<p style="text-align: center;"><em>C’est ça qu’on cherche à calculer.</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_fur_compare.png" style="margin: 0px auto; display: table; width: 352px; height: 267px;" /></p>
<p style="text-align: center;"><em>Un même système de poil, différentes densités et épaisseurs.</em></p>
<p>Ces valeurs ne peuvent pas être animées au risque d’engendrer des inconsistances de nombre de poils entre deux échantillons temporels, ce qui mettrait le moteur dans une bien mauvaise passe au moment où ce dernier calcule les vecteurs de mouvement des poils. D’après mes tests (sous <em>Guerilla</em> et <em>Arnold</em>, je suppose que <em>Renderman</em> fait pareil) les moteurs désactivent simplement les vecteurs de mouvement du système de poil incriminé et lèvent un <em>warning</em>.</p>
<p>Il va donc falloir déterminer ces deux valeurs pour chaque système de poil <u>sur l’ensemble du plan</u>.</p>
<p>Il nous faut deux choses (suivant son pipeline, on peut utiliser de l’<em>Alembic</em> ou la combinaison <em>Rig</em> + <em>ATOM</em>) :</p>
<ul>
<li>La caméra du plan.</li>
<li>La géométrie du personnage à exporter.</li>
</ul>
<p>Une fois ces deux éléments dans notre scène, le bonheur est à notre porte. En effet, les mathématiques commencent. :baffed:</p>
<p>Pour chaque image du plan (et pour chaque <em>step</em> de <em>motion blur</em>), nous allons identifier le sommet géométrique qui soit à la fois le plus proche de la caméra et présents en son tronc (<em>frustrum</em>).</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_cam_frustum_2.png" style="margin: 0px auto; display: table; width: 259px; height: 254px;" /></p>
<p>Finalement, nous calculons le diamètre, en espace caméra, du disque projeté d’une sphère de 1 unité de diamètre.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_cam_frustum_1.png" style="margin: 0px auto; display: table; width: 287px; height: 154px;" /></p>
<p>Nous récupérons ainsi le plus grand diamètre du plan.</p>
<p>Notez que quand, comme moi, on ne sait pas gérer ce mécanisme de façon totalement mathématique ( :seSentCon: ), on peut fabriquer une sphère et projeter chaque vertex via ce bout de code (honteusement inspiré de <a href="https://gizmosandgames.com/2017/05/21/frustum-culling-in-maya/" hreflang="en" title="Frustrum culling in Maya">ce billet</a>) :</p>
<pre>
<code class="language-python">import maya.cmds as cmds
import maya.OpenMaya as om
# retrieve MObject from node
sel = om.MSelectionList()
sel.add("myCamera")
sel.add("myGeo")
cam_dag_path = om.MDagPath()
geo_dag_path = om.MDagPath()
sel.getDagPath(0, cam_dag_path)
sel.getDagPath(1, geo_dag_path)
# generate projection matrix
cam_inv_world_mtx = cam_dag_path.inclusiveMatrixInverse()
fn_cam = om.MFnCamera(cam_dag_path)
proj_mtx = fn_cam.projectionMatrix()
proj_mtx = om.MMatrix(proj_mtx.matrix) # convert MFloatMatrix te MMatrix
post_proj_mtx = fn_cam.postProjectionMatrix()
post_proj_mtx = om.MMatrix(post_proj_mtx.matrix)
view_proj_mtx = cam_inv_world_mtx * proj_mtx * post_proj_mtx
# iterate over each geo vertex
vtx_iter = om.MItGeometry(geo_dag_path)
# init 2D bounding box values
proj_x_min = 999999.0
proj_x_max = -999999.0
proj_y_min = 999999.0
proj_y_max = -999999.0
while not vtx_iter.isDone():
# get vertex position in world space
geo_pos = vtx_iter.position(om.MSpace.kWorld)
# compute projected position on cam
proj_pos = geo_pos * view_proj_mtx
proj_pos_x = (proj_pos.x / proj_pos.w) / 2.0 + 0.5
proj_pos_y = (proj_pos.y / proj_pos.w) / 2.0 + 0.5
proj_x_min = min(proj_pos_x, proj_x_min)
proj_x_max = max(proj_pos_x, proj_x_max)
proj_y_min = min(proj_pos_y, proj_y_min)
proj_y_max = max(proj_pos_y, proj_y_max)
vtx_iter.next()</code></pre>
<p>À ce stade, on a, pour un plan et un personnage, un diamètre de la partie la plus proche. :sourit:</p>
<p>Mais vous vous doutez qu’il va falloir la comparer avec une autre valeur. Cette valeur, c’est le diamètre du disque projeté de la sphère sur une caméra donnée quand l’asset est a une densité de 1 (densité nominale : 100 % de poils).</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_cam_frustum_3.png" style="margin: 0px auto; display: table; width: 493px; height: 326px; text-align: center;" /></p>
<p style="text-align: center;"><em>Ce diamètre se récupère au niveau de la modé/lookdev.</em></p>
<p>On se retrouve donc avec deux diamètres. On fait ensuite un simple ratio qui peut être utilisé pour calculer la valeur de densité.</p>
<p>Super : Reste l’épaisseur : En admettant que <em>facteur</em> soit la valeur de densité (1.0 pour 100 %, 0.5 pour 50 %, etc.), j’applique la formule suivante :</p>
<p>Épaisseur nominale * (1 + (−ln(facteur)÷ln(2)))^2</p>
<blockquote>
<p>Neuh, que, nan, mais, de quoi ? Mais… Mais… Mais… Dorian ! Ça n’a aucun putain d’sens !!!</p>
</blockquote>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_je_sais.png" style="margin: 0px auto; display: table; width: 500px; height: 500px;" /></p>
<blockquote>
<p>T’es mauvais ! Je savais bien qu’il n’y avait pas que dans les yeux que tu avais de la merde !!!</p>
</blockquote>
<p>Je ne vais pas risquer de me vautrer en démonstrations. Les plus matheux d’entre vous auront peut-être remarqué la présence de X = ln(A)/ln(2) pour résoudre l’équation 2<sup>x </sup>= A. L’idée est de calculer une puissance, plus d’information <a href="https://www.ilemaths.net/sujet-commen-t-calculer-la-puissance-d-un-nombre-109026.html" hreflang="fr">ici</a>.</p>
<p>En gros j’avais remarqué que la formule de calcul d’épaisseur suivante fonctionnait bien :</p>
<ul>
<li>Exposant à 7 (100 % de densité), Épaisseur nominale * <strong>1</strong>^2 = 0.002</li>
<li>Exposant à 6 (50 % de densité), Épaisseur nominale * <strong>2</strong>^2 = 0.008</li>
<li>Exposant à 5 (25 % de densité), Épaisseur nominale * <strong>3</strong>^2 = 0.018</li>
<li>Exposant à 4 (12.5 % de densité), Épaisseur nominale * <strong>4</strong>^2 = 0.032</li>
<li>Exposant à 3 (6.25 % de densité), Épaisseur nominale * <strong>5</strong>^2 = 0.05</li>
<li>Exposant à 2 (3.125 % de densité), Épaisseur nominale * <strong>6</strong>^2 = 0.072</li>
<li>Exposant à 1 (… % de densité), Épaisseur nominale * <strong>7</strong>^2 = 0.098</li>
</ul>
<p>Pour info, à chaque fois qu’on baisse l’<em>Exponent</em> de un, on divise la densité par deux.</p>
<p>Il fallait donc que je réussisse à trouver les valeurs en gras pour chaque facteur de densité. En gros, il faut trouver une formule pour convertir 0.03125 en 6… J’avoue ne pas avoir trop le niveau et je ne me fais aucun doute sur le fait qu’une méthode plus sérieuse existe. Le graph est <a href="https://www.desmos.com/calculator/gmg1bzv6ix" hreflang="en" title="LOD Fur density graph">là</a> pour ceux qui veulent faire mumuse.</p>
<p>Il n’empêche que je voudrais quand même vous montrer les résultats en rendu. :redface:</p>
<p>On part sur ces valeurs :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_guerilla_proc_values.png" style="margin: 0px auto; display: table; width: 335px; height: 272px;" /></p>
<p>Et le rendu de référence :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_001.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 7, Width 0.002</em></p>
<p>Et en commence à descendre :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_002.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 6, Width 0.008</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_003.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 5, Width 0.018</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_004.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 4, Width 0.032</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_005.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 3, Width 0.05</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_006.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 2, Width 0.072</em></p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_test_density_guerilla_007.jpg" style="margin: 0px auto; display: table; width: 341px; height: 256px;" /></p>
<p style="text-align: center;"><em>Density 50, Exponent 1, Width 0.098</em></p>
<blockquote>
<p>« Le monsieur fait mine que ça marche, mais il dit qu’il sait pas comment… » :neutral:</p>
</blockquote>
<h3>Mouaih…</h3>
<p>Comme vous vous en rendez compte, cette méthode est limitée (pas de prise en compte du <em>DOF</em>, ni du <em>motion blur</em>, ni de la réfraction), mais avant de crier au scandale, il faut bien comprendre qu’on ne peut, de toutes façons, pas arriver à un résultat parfait sans que ce soit le moteur qui nous donne lui-même les informations. C’est sûrement faisable en calculant un mini rendu d’une AOV de l’aire de la surface au pixel combiné à une AOV de <em>motion vector</em>, mais je n’ai jamais mis cela en place. :seSentCon:</p>
<p>Le but est d’arriver à proposer une valeur au graphiste qu’il pourra, de toutes façons, modifier si les besoins du plan l’impose. Il y a fort à parier que la plupart des plans sur lesquels vous travaillerez n’auront rien d’exotique et avoir une valeur cohérente sous le coude vous évite de perdre du temps en essais/erreurs. :laClasse:</p>
<h3>Toujours plus loin ?</h3>
<p>On doit pouvoir améliorer ce mécanisme. Par exemple, si votre logiciel de <em>lookdev</em> supporte les valeurs animées, vous pourriez extraire les valeurs par <em>frame</em> (en regroupant les <em>steps</em>)et animer la densité. Je n’ai jamais testé, je ne peux donc pas vous dire si la « saute » de densité à chaque frame est visible à l’écran. :reflechi:</p>
<h3>Conclusion</h3>
<p>Les LOD en début de prod :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_napoleon.png" style="margin: 0px auto; display: table; width: 825px; height: 437px;" /></p>
<p>Vous, à deux semaines de la livraison :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/Berezyna.jpg" style="margin: 0px auto; display: table; width: 800px; height: 463px;" /></p>
<p>J’espère que cette suite de billets, bien trop verbeux, j’en ai conscience, vous auront tout de même intéressés et élargie vos horizons techniques sur le sujet.</p>
<p style="text-align: center;">:marioCours:</p>LOD, suite et fin (automatique VS manuel)urn:md5:0ae280c172085b93cc6a8c9e456e32852019-08-10T21:25:00+02:002019-08-17T16:59:57+02:00NarannInfographie 3D - Boulotfurguerillahairlod<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_suite_tn.png" style="float: left; margin: 0 1em 1em 0;" />Je me suis rendu compte que j’ai oublié de parler de deux-trois choses dans mon billet précédent et je suis parfois passé trop rapidement sur certains points.</p>
<p>Je vous propose un billet d’appoint pour corriger le tire, ce sujet aux branchements infinis le mérite bien. :sourit:</p>
<p>Aujourd’hui, je comparerai l’approche automatique et semi-manuelle pour gérer les LOD géométriques, j’aborderai la relation entre le département de <em>modeling</em> et de <em>lookdev</em> puis on finira par les poils.</p> <h3>Système automatique</h3>
<h4>Avant propos</h4>
<p>Si c’est la production ou la supervision qui met le sujet sur le tapis, il est probable que ce soit avec l’idée d’en faire un truc « automatique et transparent pour l’utilisateur », ce qui, ironiquement, correspond à la définition d’un truc « magique et opaque ».</p>
<p>Il va de soi que plus le projet est ambitieux, plus l’automatisation est importante, personne ne veut voir ses graphistes passer leurs journées à faire des opérations rébarbatives à la main. Et pourtant…</p>
<p>En pratique l’ajout de LOD géométriques dans vos projets veut dire que vous faites intervenir, dans vos tuyaux/scènes, une « particularité » de vos assets. Ainsi, même si vous automatisez la gestion des LOD, ces derniers ne disparaissent pas, vous ne les voyez simplement plus, jusqu’à ce qu’ils posent problèmes. Vous me répondriez : Pourquoi diable voulez-vous qu’ils posent problèmes, car leur gestion est « automatique et transparent pour l’utilisateur » ? :bete:</p>
<p>Cette perception nie la nuance. En effet, on ne fabrique pas des plans comme on fabrique des objets dont l’essence est d’être identique (agroalimentaire, informatique, jouets, etc.). La « nature » des plans varient. Par nature, j’entends ce qui en détermine sa fabrication ; un plan de visage a ses propres problématiques de fabrication (<em>SSS</em> des yeux/cou/vêtements, cheveux, <em>Rim light</em>, arrière-plan, etc.), de même qu’un plan de décor (nombre d’objets, <em>lookdev</em> d’ensemble, <em>matte painting</em>, etc.). Les deux ne se fabriquent pas de la même manière et la pertinence d’utiliser des LOD ou non en est très dépendante. D’une manière générale, plus on pousse la qualité vers le haut, plus des contrastes assez net s’opèrent dans la façon dont les plans sont fabriqués.</p>
<p>On commence à comprendre pourquoi les LOD, prétendument automatiques, reviennent toujours sur le tapis. Les graphistes travaillent avec un ensemble de choses simples (Alembic d’animation, assignation de <em>lookdev</em>, surcharge des positions/attributs, etc.) qui s’entremêlent, formant un tout complexe. Le rendu est le plus touché car c’est le département qui rassemble tout. Si la gestion des LOD est automatique et qu’ils ne sont donc pas explicitement « choisis » par les graphistes, ces derniers devront les ajouter aux potentielles raisons des problèmes qu’ils ont sous les yeux.</p>
<p>La production (et dans une certaine mesure, la supervision) a parfois du mal à juger de cet effet indirect.</p>
<p>Après ce (trop) long aparté, rentrons dans le vif du sujet : À quoi faut-il penser quand on automatise la gestion des LOD ? :reflechi:</p>
<h4>Concrètement</h4>
<p>Je pars du principe que vous êtes un TD à qui on a refilé la patate chaude et que ni le <em>modeling</em>, ni le <em>lookdev</em> ne veut intervenir (« transparent pour l’utilisateur » toussa).</p>
<p>L’approche naïve consiste à prendre toutes les géométries de sa scène et de leur appliquer un gros <em>Reduce</em>. Le résultat est très moche, mais a priori, c’est pas le sujet. :vomit:</p>
<p>Comme dit dans mon billet précédent, il faut s’assurer que les UV de la géométrie réduite ne soit pas détruits et correspondent à la géométrie originale.</p>
<p>Le plus gros problème c’est taille de la hiérarchie. Si elle est trop grosse, vous pourriez vous retrouver avec des milliers d’objets qui ne font chacun que deux ou trois polygones. Suivant vos méthodes de travail il est fort probable qu’une fois instancié des milliers de fois, vos logiciels de <em>lookdev</em> pédalent à traverser la hiérarchique de vos LOD.</p>
<p>On pourrait être tenté de supprimer les petits objets (petites <em>bounding boxes</em>) mais si c’est ce qui compose l’ensemble de votre asset (e.g. un arbre, une plante), vous risqueriez d’en supprimer une partie visible importante et vous retrouver avec un asset tout nu ce qui peut mettre le modeleur mal à l’aise devant son superviseur :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/20190807_pas_de_talent.png" style="margin: 0px auto; display: table;" /></p>
<p>Si vos superviseurs <em>modeling</em> et <em>lookdev</em> sont de connards qui ne veulent rien entendre, il vaut mieux éviter les LOD. Si vous ne pouvez pas intervenir sur cette décision, vous êtes foutu. Vous pouvez mettre à jour votre <em>Linked’In</em> et commencer à postuler ailleurs, car les départements rendus vont pleurer du sang.</p>
<p>Mais on est dans le vrai monde, celui des Bisounours et des glaces à la vanille, celui ou les superviseurs comprennent les intérêts des solutions que vous leur proposez, pour peu que vous leur parliez lentement.</p>
<p>Ce qui m’amène au second point : La méthode semi-manuelle. :sauteJoie:</p>
<h3>Système semi-manuel</h3>
<p>Au passage, appelez-la semi-<em>automatique</em>, c’est plus facile à vendre à la production… :trollface:</p>
<h4>Aider les graphistes par « contrat »</h4>
<p>Cette approche vise à résoudre les problèmes précédents par « contrat » avec les graphistes. Dans le cas de la hiérarchie trop dense, vous pouvez proposer la chose suivante à votre graphiste :</p>
<p>« Si ton groupe de nœuds porte le suffixe « _combined », le contenu sera combiné à l’export et le suffixe sera supprimé. »</p>
<p>En gros, vous garantissez que la hiérarchie suivante :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_suite_maya_hierarchy_1.png" style="margin: 0 auto; display: table;" /></p>
<p>Sera converti en ça :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_suite_maya_hierarchy_2.png" style="margin: 0 auto; display: table;" /></p>
<p>La confiance n’excluant pas le contrôle, vous n’aurez qu’à ajouter un <em>sanity check</em> s’assurant que chaque groupe suffixé « _combined » ne contient que des géométries et sans attributs, ces derniers étant perdu lors du <em>combine</em>.</p>
<p>Cette approche à l’avantage de laisser le graphiste contrôler la livraison de son travail par simple renommage des nœuds, directement dans Maya et c’est le code qui s’occupe de la partie rébarbative, le sanity check s’étant assuré qu’il ne puisse pas y avoir de surprise.</p>
<p>Il y a fort à parier que les personnes au <em>lookdev</em> y trouveront un intérêt en proposant des modifications au <em>modeling</em>, voir, en les faisant elles-mêmes. :laClasse:</p>
<p>Cette approche par contrat implique de rester aussi simple que possible. La raison est que le graphiste peut se débrouiller tout seul en cas de problème sans que les outils d’automatisation ne soient un obstacle à la compréhension. Un réflexe que peuvent avoir les TD qui ne sont pas graphistes de formation est de trouver dommage de limiter le graphiste à ses propres compétences, là ou des supers outils, tout d’héritage de classes vêtus, pourraient l’aider à une échelle supra luminique. C’est vrai, jusqu’à ce que les TD deviennent les seules personnes à comprendre le travail des graphistes. Si vous ne laissez qu’un contrôle partiel à ce genre de contrat, vous « prenez » l’autonomie du graphiste sur des taches qui devraient rester sous sa responsabilité et que, par conséquent, il doit parfaitement comprendre, en vu de l’assimiler en tant que méthode. Vous voyez que vous êtes sur la bonne voie quand les graphistes développent de nouvelle façon de travailler tout seul, en s’appuyant sur ces « contrats ». Pour cela, il faut que ces derniers soient simples. :petrus:</p>
<p>Dans un pipeline, certaines choses sont humainement infaisables, c’est là-dessus que votre cerveau doit être créatif. Accélérer le travail du graphiste implique de se mettre sous sa perspective. Ce sont des erreurs d’estimation qui peuvent coûter cher. :neutral:</p>
<p>Il est plus facile de faire tout ça via des jobs d’export Alembic, car vous n’avez pas à mettre une logique de « retour à l’état précédent » une fois la scène modifiée ; vous ouvrez, vous modifiez, vous exportez, vous quittez.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_pwalone.png" style="margin: 0 auto; display: table;" /></p>
<p>Mais ne nous arrêtons pas en si bon chemin…</p>
<h4>Les <em>close up</em></h4>
<p>Au même titre qu’une version basse définition, il peut arriver que des projets nécessitent des versions « high » (ou <em>close up</em>). Les toits des bâtiments par exemple. Vous pouvez « résoudre » la hiérarchie du graphiste suivante :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_closeup.png" style="margin: 0 auto; display: table;" /></p>
<p>Vous pouvez procéder de plusieurs façons. La méthode bourrine consiste à tout exporter dans un seul Alembic. C’est l’assembleur (ou le graphiste au rendu) qui s’occupera de cacher l’un ou l’autre au besoin (via une petite expression par exemple), la version <em>close up</em> est caché par défaut.</p>
<p>Disons que c’est mieux que rien, mais ce n’est pas comme ça que l’on brille en société.</p>
<p>En effet, il est dommage de se trimbaler de la géométrie <em>close up</em> dans tout le pipeline, même si cette dernière est cachée. Il nous faut donc procéder à deux exports. :reflechi:</p>
<p>Vous pouvez proposer un contrat en deux clauses :</p>
<ul>
<li>« Durant un export standard, tout groupe contenant le suffixe « _closeUp » est supprimé. » (on supprime les géométries de <em>close up</em> de l’export de base)</li>
<li>« Durant un export <em>close up</em>, toute géométrie ayant un homologue portant le suffixe « _closeUp » est supprimé. » (non, non, je n’ai rien oublié, lisez la suite)</li>
</ul>
<p>Le résultât d’un export standard sera :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_methode_2_standard.png" style="margin: 0 auto; display: table;" /></p>
<p>En celui d’un export <em>close up</em> sera :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_methode_2_closeUp.png" style="margin: 0 auto; display: table;" /></p>
<p>Pourquoi ne pas avoir renommé « toiture_closeUp » en « toiture » ? Ce serait, en effet, plus logique, mais, dépendant de votre façon de gérer les assignations, cela risquerait de couper l’herbe sous les pieds du <em>lookdev</em> qui peut avoir besoin de faire la distinction entre l’objet « toiture » et le contenu de « toiture_closeUp ».</p>
<p>Mais ça, c’est quand votre logiciel de <em>lookdev</em> c’est du caca (ou que vous ne savez pas l’utiliser :gniarkgniark: ).</p>
<p>Vous pouvez contourner ce problème en s’appuyant sur les rangées des UDIM :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_toiture_udim.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/.lod_toiture_udim_m.png" style="margin: 0 auto; display: table;" /></a></p>
<p>Ainsi, vous gardez le contrôle via textures, indépendamment de la hiérarchie. Gardez toutefois à l’esprit que compenser l’accès à la géométrie par des UDIM implique que la moindre <em>retake</em> de <em>lookdev</em> nécessitera un export de texture, ce qui amène à des situations qui défient l’entendement : Là ou diminuer le <em>spec</em> ou la <em>diffuse</em> pourrait se faire en un <em>override</em> sur l’objet en question, vous devez ouvrir votre projet Mari/Designer/Toshop, faire la modification et exporter avant de pouvoir tester. La limite entre une gestion par <em>override</em> et une gestion 100 % texture est un sujet à part qui mériterait son propre billet, mais je vais fermer la parenthèse. :dentcasse:</p>
<p>Si votre logiciel de <em>lookdev</em> vous permet de faire la distinction d’assignation entre « toiture » et « toiture|poutre17 », alors il ne faut pas se priver et faire en sorte que la version <em>close up</em> prenne la place de la hiérarchie originale :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_methode_2_closeUp1.png" style="margin: 0 auto; display: table;" /></p>
<p>Comme ça, si le rendu fait une expression pour modifier « toiture », cela fonctionnera, que le modèle soit en <em>close up</em> ou non.</p>
<p>Mais, bordel de m* :injures: , on peut aller encore plus loin !!! :grenadelauncher:</p>
<h4>Le <em>merge</em> de hiérarchie</h4>
<p>Si vous avez Katana, vous pouvez opérer un <em>merge</em> exclusif entre deux hiérarchies. Si <em>A</em> est la hiérarchie <em>standard</em> et <em>B</em> la hiérarchie <em>close up</em>, vous pouvez demander à Katana de « superposer » les hiérarchies en choisissant la hiérarchie <em>B</em> en cas de conflit.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_merge_hierarchy.png" style="margin: 0 auto; display: table;" /></p>
<p style="text-align: center;"><em>À gauche, arbre.abc, au milieu, arbre_closeup.abc et à droite, la hiérarchie résolu.</em></p>
<p>Ça veut dire que votre Alembic de <em>close up</em> ne contient plus que les nœuds ayant précédemment le suffixe<em> </em>« _closeUp », sans les géométries <em>standards</em>, car la hiérarchie de <em>close up</em> est tout le temps combiné (<em>mergé</em>) à la hiérarchie <em>standard</em>.</p>
<p>Je ne sais plus du tout comment on fait ça par contre, va falloir me croire sur parole. :slow_clap:</p>
<p>Autre point important qui rejoint le sujet des <em>combines</em>,</p>
<p>Sans aller jusque-là, je pense avoir pas mal poussé le truc pour vous donner matière à réflexion. L’objectif étant toujours de rendre les graphistes autonomes tout en leur proposant des « outils » (ce n’est peut-être pas le bon mot) qui correspondent à ce qu’ils font.</p>
<h3>Dans tous les cas</h3>
<p>Quelle que soit la méthode utilisée, tout ceci demande un travail supplémentaire, et avec les moteurs de rendu actuel, ce n’est pas toujours justifié.</p>
<p>Faire l’économie de la vérification de ce qui sort des tuyaux peut se payer cher plus tard. Il vaut mieux vérifier en amont (via tournettes) si les données générées sont propres et « rendent » bien, mais c’est encore un temps à passer à regarder des assets. Les LOD sont des objets internes à la fabrication. Jouez pas au con et ne présentez pas ça au réal…</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_upload_shotgun.png" style="margin: 0 auto; display: table;" /></p>
<h3>Note sur le transfert d’UV</h3>
<p>Là, on passe en manuelle ! Donc nous allons parler de techniques à ajuster au cas par cas.</p>
<p>C’est une technique a priori un peu bancale mais c’est parce que je l’ai vu fonctionner que je vous la partage.</p>
<p>Des studios font faire les UV directement au <em>lookdev</em> au motif, tout à fait justifié, qu’il est le premier concerné par le résultat. Dès lors, vous avez un croisement entre les données générées par vos graphistes et l’ordre dans lesquels vous les produisez : Si le <em>lookdev</em> est censé faire les UV, mais que les LOD sont déjà fait par le <em>modeling</em>, comment assurer que les UV des LOD sont cohérents ?</p>
<p>Par le transfert d’UV pardi ! :banaeyouhou:</p>
<p>Je suis sûr qu’il y a des cas où ça foire (les arbres), mais les résultats sont convaincants si la géométrie des modèles basses définitions correspond à leur homologue en hautes définitions.</p>
<p>Ça nécessite quelques nuances dans l’organisation : La modé ne fait aucun UV, le <em>lookdev</em> qui les prends tous à sa charge. Il est important que la production ait cette information car ça nécessite un glissement des ressources vers le <em>lookdev</em>, ces derniers auront plus de travail par asset et mettront plus de temps à travailler. En revanche vous pouvez séparer le travail intelligemment en laissant le <em>lookdev</em> faire les UV des assets compliqués (personnages, bâtiments de premier plan, etc.) et laisser le <em>modeling</em> faire les UV d’asset de second plan (<em>props</em>, etc.).</p>
<p>Vous en voulez encore ? :gniarkgniark:</p>
<h3>Le TriPlanar</h3>
<p>Celle-là je la sors de Guerilla, mais je suis sûr qu’on peut la déporter sur d’autres moteurs. Le principe est de faire plusieurs rendus de trois caméras (face, côté, dessus). Pour chaque rendu dont on exporte l’albédo, le masque le spéculaire et surtout, la normale. Guerilla permet de faire ça assez simplement (doc <a href="http://guerillarender.com/doc/2.1/User Guide_Rendering_Light Path Expression.html" hreflang="en" title="2.1 User Guide Rendering Light Path Expression">ici</a>).</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_suite_guerilla_aov.png" style="margin: 0 auto; display: table;" /></p>
<p>On fait ensuite un <em>shader</em> très simple (Couleur de diffuse + une couche de spéculaire grossière + la normale), une géométrie très simple (des cubes + un toit = 6 faces) et on a un asset très léger qui a un peu de gueule quand il y en a (vraiment) énormément. On est très proche du jeu vidéo (peu de poly, tout dans la texture).</p>
<p>Cette technique marche assez bien sur les bâtiments lointains (genre l’horizon d’un Paris…). Vous devriez pouvoir étendre le principe aux arbres (la vielle technique des plans superposées), mais je n’ai jamais testé.</p>
<h3>Les transitions</h3>
<p>Si vous utilisez un système qui permet de permuter un LOD suivant la distance et la caméra, et que vous faites ça sur une foule ou un amas (une forêt), il est probable que ce passage d’un LOD à l’autre entraîne un « saut » inesthétique entre les changements de LOD. :perplex:</p>
<p>Si vous avez la main sur le mécanisme de distribution, vous pouvez définir une zone, assez large dans laquelle les LOD sont mélangés au prorata de la distance. Admettons que vous voulez que la transition se fasse entre 100 m et 200 m. Pour un arbre à X m, vous calculez un <em>random</em> (entre zéro et un) multiplié par le ratio de X par rapport à 100 m et 200 m :</p>
<pre>
<code class="language-python">ratio = (X-100)/(200-100)
if ratio <= 0.0:
# high resolution
elif ratio > 1.0:
# low resolution
else:
# pseudo random choice
if random * ratio <= 0.5:
# high resolution
else:
# low resolution</code></pre>
<p>La documentation <a href="https://help.autodesk.com/cloudhelp/2018/ENU/Maya-Tech-Docs/Nodes/setRange.html" hreflang="en" title="Maya Node setRange">du nœud le setRange</a>. Je la regarde à chaque fois que j’ai un doute sur l’équation.</p>
<p>Faire une transition de LOD implique tellement de choses qu’il vaut mieux s’en passer autant que possible. Si votre plan est animé ? Tentez de gérer le tout en haute définition. En effet, le grain que vous souhaitez chasser via vos LOD (c’est le but après tout) risque de ne jamais être visible du fait du mouvement de caméra.</p>
<p>Si vous pouvez les éviter, alors faites-le. :papi:</p>
<h3>Subdivision et displacement</h3>
<p>C’est tellement basique, mais je soupçonne que les logiciels permettant de gérer des <em>lookdev</em> en masse et le fait que les <em>path tracer</em> mangent du poly nous pousse à ne trop penser à la subdivision est au <em>displacement</em>. Pourtant, ça ne coûte pas grand-chose de couper sa <em>subdivision</em> et son <em>displacement</em> sur tout ce qui est éloigné ou peu visible de la caméra. Vous pouvez chercher toutes les méthodes de LOD du monde, si vous ne faites pas ça, ça ne sert à rien. :redface:</p>
<h3>Les poils</h3>
<p>Et nous arrivons à la raison pour laquelle je voulais vous faire ce second billet : J’avais oublié de vous parler des poils (fur/hair/Yeti/XGen, j’utiliserais le mot <em>poil</em> pour désigner cet ensemble). J’y vois deux gros cas de figures : Les poils des personnages principaux et les poils « statiques » (par arbre, par buisson, etc.).</p>
<h4>Les poils « statiques »</h4>
<p>Ils sont moins fréquents, mais le plus simple à gérer, car vous les considérez comme de la modé : Vous les générez une seule fois pour votre asset et vous l’instanciez comme une géométrie. Comme sortir un LOD de poil est assez facile, vous pouvez générer plusieurs versions et laisser les graphistes afficher l’une ou l’autre, l’idée étant d’éviter de générer ces poils par plan et par asset.</p>
<p>J’ai vu des graphistes utiliser cette méthode pour des buissons et arbustes d’un décor visible sur peu de plans. Plutôt que de s’embêter à faire une modélisation dédiée (quand on sait à quel point placer des feuilles est casse-pied), le superviseur a proposé de faire une géo de branche, instancié de gros poils dessus, cuire ça (via les <em>ghostdata</em> de Guerilla) puis l’instancier. C’est malin et terriblement efficace. Car ils ont pu faire plusieurs variations de formes de buisson assez différentes (rendu totalement différente par les couleurs du <em>lookdev</em>), mettre ça des milliers de fois dans un décor et ça tournait sans trop de difficultés.</p>
<p>Je vais aussi vous parler d’un problème difficile à déboguer. Il est peu probable que cela vous arrive, mais ce dernier ne sautant pas aux yeux, je trouve intéressant de vous en parler : Suivant le système de poil que vous utilisez (ici, Yeti, mais je pense que d’autres pourraient avoir le même problème), il est possible de l’utiliser pour générer la végétation de tout un décor. Votre moteur peut se faire avoir en assignant une <em>bounding box</em> unique à tout ce que la procédurale génère. En pratique, l’impact est négligeable, car les moteurs sont rapides. Mais il est toujours difficile de gérer tout un décor et les graphistes peuvent être tenté de faire leur dispersion d’éléments en couches (cailloux au sol, vielles branches, buissons, arbustes et enfin, arbres), voir par section du décor. Si vous avez six couches, vous avez six <em>bounding box</em> de la taille du décor qui vont être questionné inutilement pour chaque rayon. Et là ça commence à se sentir sur les performances.</p>
<p>Encore une fois, il est peu probable que vous n’ayez jamais à gérer un tel problème, mais c’est aussi un rappel à garder ses <em>bounding box</em> cohérentes.</p>
<h4>Les poils « dynamiques »</h4>
<p>Voila pour les poils statiques. Les poils dynamiques sont plus compliqués à gérer. Compliqués parce qu’ils sont souvent sur les personnages principaux, ce qui en nécessite beaucoup, à cela s’ajoute un <em>shading</em> complexe. Ces plans rentrent dans la <em>farm</em> comme un barbare dans un couvent de nonnes.</p>
<p>Je pense qu’il n’y a pas de solutions qui marchent à tous les coups, mais on peut s’éviter du sang et des larmes en gardant quelques réflexes dont je vais essayer de faire le tour.</p>
<p>Ce qui prend de la mémoire, c’est la géométrie, mais il est important de ne pas s’arrêter au nombre de poil, car la complexité de chacun peut drastiquement peser dans la balance.</p>
<pre>
<code>Pour chaque poil:
Pour chaque point par poil (3 minimums pour une courbe):
la position (3 float) * step de motion blur (2 minimums)
la couleur (3 float)</code></pre>
<p>Il est difficile de donner une équation parfaite, car les moteurs ont différentes stratégies que vous pouvez, plus ou moins, contrôler. Par exemple, vous pouvez (ou non) avoir des <em>step</em> de <em>motion blur</em> pour la couleur, voir ne pas avoir de couleur du tout, ou une seule couleur par poil, etc.</p>
<p>De plus, vous pouvez activer la compression ce qui influe encore sur le résultat. Pas de secret, il faut tester.</p>
<p>Pour ce qui est du temps de rendu, c’est le <em>shading</em> qui est le plus influant et autant on dispose de marge de manœuvre avec la géométrie (couleur, <em>step</em> de <em>motion blur</em>), autant le <em>shading</em> est plus capricieux car visible et toute modification visuelle risque d’entraîner des discussions difficiles. Si vous êtes superviseur, vous avez un rôle à jouer. Ne laissez pas vos graphistes les gérer seul, car ils peuvent baisser les bras et vous prenez le risque de partir en production avec des choses inrendables.</p>
<p>En vrac :</p>
<ul>
<li>La transparence coûte cher. Il vaut mieux biaisé en montant le nombre de poil que l’activer.</li>
<li>Certains modèles d’illumination fonctionnement mieux avec les poils longs (cheveux) que les poils courts. Lisez les détails d’implémentation dans la documentation, parfois votre moteur propose d’autres modes.</li>
<li>Vos poils ne pardonneront pas les inconsistances d’éclairage de vos scènes. Si votre <em>lighting</em> fait n’importe quoi, il y a fort à parier que vos poils y réagiront plus vivement que le reste des matériaux de votre scène.</li>
<li>Et réciproquement, les bricolages de <em>trace set</em> peuvent être plus difficiles à généraliser.</li>
<li>Éviter le <em>SSS</em> sous les poils, suivant vos optimisations, il est possible qui le calcul du <em>SSS</em> ne prennent pas en compte l’ombrage des poils, ces derniers étant supprimé du <em>trace set</em> de <em>SSS</em>. Vous avez le risque qu’un sample traverse les poils et renvoi un calcul d’illumination de la peau complètement biaisé qui formera une mouche.</li>
<li>Les <em>shader</em> de poil <a href="https://benedikt-bitterli.me/pchfm/" hreflang="en" title="A Practical and Controllable Hair and Fur Model for Production Path Tracing">sont</a> <a href="https://www.pbrt.org/hair.pdf" hreflang="en" title="THE IMPLEMENTATION OF AHAIR SCATTERING MODEL">complexes</a>, évitez de mettre des textures pour tout et n’importe quoi, cela rend les problèmes d’illumination difficile à déboguer.</li>
<li>Suivez les conseils de la documentation de votre moteur qui donne souvent de précieuses informations. Vous devez comprendre chaque paramètre et les privilégier.</li>
<li>Faites des tournettes et ne laissez rien passer. Les tournettes ont souvent des éclairages très simple, si petit artefact apparrait, il est probable que vous ayez à vous le coltiner toute la production.</li>
<li>Les env ball, c’est la vie, ne l’oubliez pas.</li>
<li>Lisez la putain de doc ! :RTFM:</li>
</ul>
<p>D’une manière générale, vous devez maîtriser les <em>shaders</em> que vous utilisez en production, c’est encore plus vrai en ce qui concerne les <em>shader</em> de poil pour éviter de s’arracher les cheveux.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_10_lod_suite_fin/lod_lol.png" style="margin: 0 auto; display: table;" /></p>
<p>Croyez-le ou non : J’ai créé ce second billet avec l’ambition de vous parler de l’automatisation de la densité des poils au plan, mais le fil de mes développements lui ont donné une taille conséquente et ce sujet me semble suffisamment complexe pour mériter son propre billet, je vais donc m’arrêter là et je vous dis à bientôt !</p>Aperçu du concept de LODurn:md5:12692765fef9efd58850db9695ed723a2019-08-04T16:44:00+02:002019-08-07T18:56:20+02:00NarannInfographie 3D - Boulotguerillalodmayarendu<p><img alt="lod_jeu_de_mot" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/elle_aude.png" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Bonjours, dans ce billet je vous propose de faire le tour de ce qu’on entend par LOD (<em>Level Of Detail</em>), en quoi ça consiste, à quoi ça sert, quand faut-il l’utiliser et quand vaut-il mieux s’en éloigner.</p>
<p>Vous vous rendrez compte que derrière ce concept simple se cache des réalités techniques assez nuancées. :reflechi:</p> <p>La question des LOD est récurrente dans les différentes disciplines liées à l’informatique graphique. Le principe est de décomposer la complexité de ce qu’on souhaite visualiser (souvent, de la géométrie) dans le but d’accélérer son calcul/affichage.</p>
<p>Et comme ce concept peu sembler simple à comprendre, il peut apparaître comme une solution séduisante quand tes rendus n’avancent pas et que ta prod prend l’eau :</p>
<p><img alt="Fais des LOD" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.faire_des_lod_m.png" style="margin: 0px auto; display: table;" /></p>
<h3>Les différents types de LOD</h3>
<p>Le type de LOD le plus connu est la diminution de la géométrie de l’objet.</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.lod_visage_maya_m.png" style="margin: 0px auto; display: table;" /></p>
<p>Ce mécanisme est très utilisé en jeu vidéo où l’on privilégiera plutôt des grosses textures de <em>normal map</em>s pour l’ajout de détails plutôt que des triangles. En effet, moins il y a de triangles, plus la <a href="https://fr.wikipedia.org/wiki/Rast%C3%A9risation" hreflang="fr" title="Rastérisation">rastérisation</a> est rapide. Les performances des GPU tombent également quand la taille du triangle à calculer est plus petite que la taille du pixel.</p>
<p>Cette méthode oblige le stockage d’une seconde géométrie (voir plus) en mémoire, là ou stocker des milliers d’instances d’arbres en haute définition ne pose plus de problèmes à nos moteurs. C’est un énorme désavantage, car le <em>switch</em> entre la version haute et basse géométrie doit se faire avant le rendu pour pouvoir être efficace.</p>
<p>Il y a des dizaines de façons de gérer ce type de LOD, la « bonne » va grandement dépendre du degré de flexibilité requis par la production et il est difficile de rester générique quant aux solutions à proposer à ce problème.</p>
<h3>Le <em>shading</em></h3>
<p>Une autre façon de faire du LOD consiste à diminuer le <em>shading</em> en fonction de la distance et/ou du nombre d’objet à rendre. Cela peut être une diminution des spéculaires afin d’éviter que des samples de hautes lumières ne sois récupérés par le raytracer pour des petits objets au fond le l’image (des cheminées/antennes métalliques sur des plans large de villes) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.lod_ville_m.png" style="margin: 0px auto; display: table;" /></p>
<p>Voici un plan magnifique de villes tout d’instances vétu. Quand on regarde ce qu’il y a dans un pixel, on se rend compte que de nombreux détails apparaissent. Ici, neuf samples sont lancés (3 × 3), mais l’un d’entre eux vient taper l’antenne qui a un haut spéculaire et une très forte valeur. Même une fois moyenné, la valeur du pixel restera très importante (vous aurez des mouches). Si vous avez un problème de la sorte, il y a fort à parier que le problème vient de votre <em>shading</em>, mais quand on a passé 3 jours à éclairer son plan et que quelques mouches cassent les pieds, on prend la solution la plus simple : Désactiver le spéculaire sur l’antenne à partir d’une certaine distance. :grenadelauncher:</p>
<p>Ce type de LOD est vraiment mis à contribution dans le rendu en lancé de rayon où quelques samples peuvent récupérer des valeurs très disparates comparé à leurs voisins du fait d’objets denses en petites géométries et lointains, ce qui occasionne du grain. Idem pour le <em>SSS</em>/<em>bump</em>/<em>normal map</em> qui peut-être volontairement désactivé sur les objets lointains.</p>
<p>C’est au cas par cas, suivant ce qu’on cherche à rendre, sachant que les moteurs gèrent parfois les optimisations de <em>shading</em> en interne, la logique étant toujours de diminuer la variation (variance) des samples en vu de diminuer le grain :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.lod_variance_m.png" style="margin: 0px auto; display: table;" /></p>
<center><em>Sur le graphique de droite, la moyenne sera beaucoup moins « stable » suivant les pixels.</em></center>
<h3>Les <em>mipmaps</em></h3>
<p>L’autre mécanisme utilisé à la fois en jeu vidéo et en rendu est l’utilisation de <em>mipmaps</em>. Ce mécanisme est tellement répandu qu’il est souvent géré directement par le moteur de rendu sans manipulations explicite de l’utilisateur. En pratique, vous utilisez l’outil <em>maketx</em> (<em>render --buildtex</em> sous Guerilla) pour convertir les textures dans un format prévu pour le moteur (souvent en <em>.tex</em>). L’outil se charge de générer les <em>mipmaps</em> et le moteur ira piocher à la profondeur nécessaire aux vues de la distance et des surfaces (flous ou nets) parcourues par le rayon. Plus d’informations <a href="https://graphics.stanford.edu/papers/trd/" hreflang="en" title="Tracing Ray Differentials">ici</a> et <a href="https://renderman.pixar.com/resources/RenderMan_20/integratorRef.html" hreflang="en" title="Writing Integrators">ici</a>.</p>
<h3>Le Stochastic Pruning</h3>
<p>Une autre méthode assez impressionnante mais très compliqué à mettre en place : Le <a href="https://graphics.pixar.com/library/StochasticPruning/index.html" hreflang="en" title="Stocastic Pruning">Stochastic Pruning</a>. Je vous invite à regarder <a href="http://graphics.pixar.com/library/StochasticPruning/paper.pdf" hreflang="en" title="Stocastic Pruning PDF">le PDF</a>, il est très bien illustré (comme tous les PDF de Pixar :siffle:).</p>
<p>Le principe ne peut fonctionner que sur des objets composé de petits objets assez similaires. Les arbres sont un parfait candidat et c’est une (la ?) technique de simplification par excellence des arbres dans le jeu-vidéo. Le fonctionnement est très bien expliqué dans <a href="https://blog.mmacklin.com/2010/01/12/stochastic-pruning-for-real-time-lod/" hreflang="en" title="Stocastic Pruning for Real-Time LOD">ce billet</a>. Je vous le traduis ici :</p>
<blockquote>
<ol>
<li>Construisez votre objet de N éléments (les feuilles dans le cas d’un arbre, habituellement représenté par des quads).</li>
<li>Ranger les éléments dans un ordre aléatoire (Une manière robuste de le faire consiste à utiliser le <a href="https://fr.wikipedia.org/wiki/M%C3%A9lange_de_Fisher-Yates" hreflang="fr" title="Mélange de Fisher-Yates">mélange de Fisher-Yates</a>).</li>
<li>Calculez U, la portion d’éléments à rendre en se basant sur la distance de l’objet.</li>
<li>Rendez N*U éléments « non-taillé » (<em>unpruned</em>) avec une aire mise à l’échelle par 1/U.</li>
</ol>
</blockquote>
<p><a href="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/PrunedCloseup.mp4" title="Stocastic Pruning Pruned Closeup">Une petite vidéo</a> du résultat (Rendu rapproché d’un buisson alors que la camera se recule). Et si vous voulez encore plus d’images, c’est <a href="https://www.yumpu.com/en/document/read/43603224/stochastic-simplification-pixar-graphics-technologies" hreflang="en" title="Stochastic Simplification Pixar Graphics Technologies">par ici</a>.</p>
<p>Comme je le disais, ce système est assez difficile à mettre en place, car il nécessite une relation forte entre le moteur et ce qu’il rend. Je soupçonne qu’il tende à résoudre un problème apparaissant principalement sur un <a href="https://en.wikipedia.org/wiki/Reyes_rendering" hreflang="en" title="Reyes rendering">REYES</a> (Vieux Renderman) qui, lui aussi, pédale quand le nombre de triangles par pixel augmente, et à ma connaissance, seul <em>Pixar</em> et <em>Weta</em> l’ont utilisé (sur <em>Cars</em>, <em>Ratatouille</em> et <em>Avatar</em>). Pour être honnête, je pense que cette technique est désuète pour les <em>path tracers</em> (j’explique plus loin pourquoi) mais elle m’a toujours très impressionné alors je partage. :joue:</p>
<h3>L’env ball</h3>
<p>Celle-là, vous l’avez peut-être déjà utilisée. C’est la bonne vielle technique qui consiste à calculer une <em>env ball</em> à l’endroit ou se trouve le personnage (ou le centre d’intérêt) et d’exclure ce dernier de l’illumination du décor pour ne l’illuminer qu’avec l’<em>env ball</em> (ce qui diminue la variance des <em>samples</em>, et donc, le grain) :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.lod_env_ball_m.png" style="margin: 0px auto; display: table;" /></p>
<center><em>À gauche, le plan. En haut, à droite, on calcule l'env ball (en bleu) à la place de la tête du personnage. En bas, à droite, on illumine uniquement le personnage (en rouge) avec cette env ball en ayant pris soin de l’exclure des autres éclairages.</em></center>
<p>Cette technique est très efficace sur les plans où le centre d’intérêt est complexe à sampler (<em>SSS</em> dans le cou, cheveux, etc), où il ne bouge pas trop et ou la zone de contact entre l’objet à illuminer et le reste est caché (personnage qui parle au premier plan). Bien entendu, en cas de changement drastique d’éclairage, il faut recalculer l’<em>env ball</em>. Ça fait un certain nombre de contraintes, mais si vous cochez toutes les cases, vous êtes bon ! :banaeyouhou:</p>
<p>Dernière contrainte : Comme le personnage est illuminé par une seul light, l'<em>env ball</em>, certaines AOV (réflexions) seront difficile à obtenir.</p>
<h3>Les harmoniques sphériques</h3>
<p>J’hésitais à vous en parler, car elles ne sont plus vraiment utilisées en lancé de rayon, mais le principe s’apparente un peu à celui expliqué précédemment. L’idée est de calculer des minis <em>env balls</em> (un terme plus adapté serait plutôt <em>light probes</em>) un peu partout dans un décor. De cette façon, on stocke l’illumination à plusieurs endroits et on interpole en fonction de la distance entre chaque <em>env ball</em>.</p>
<p>Sauf qu’on n’appelle pas ça harmoniques sphériques pour rien… La compréhension du mécanisme nécessitent de bonnes bases en mathématique, mais le principe, plutôt qu’une <em>env ball</em> (qui nécessite du sampling de texture), est d’utiliser des coefficients désignant, grosso modo, la couleur suivant des directions. Voici une image honteusement tirée de <a href="https://gen-graphics.blogspot.com/2017/11/spherical-harmonics-in-graphics-brief.html" hreflang="en" title="Spherical Harmonics in Graphics A Brief Overview">ce très instructif billet</a> :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/Spherical_harmonics.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/.Spherical_harmonics_m.jpg" style="margin: 0px auto; display: table;" /></a></p>
<p>C’est rapide à calculer et comme vous vous en doutez, c’est très utilisé en jeu-vidéo, mais, comme les <em>env balls</em>, la gestion des zones de contact nécessite son propre mécanisme.</p>
<h3>Les LOD et la production</h3>
<p>Comme tout mécanisme que vous souhaitez utiliser dans vos productions, son fonctionnement doit avoir une réalité technique ou vos graphistes risquent de se battre contre leurs outils pour faire ce que vous avez décidé.</p>
<p>Le truc qu’un responsable (production et supervision) doit savoir, c’est que soit l’usage des LOD est exceptionnel (c-à-d. au cas par cas) et c’est la compétence du graphiste qui prend le relais. Dans ce cas, l’utilisation de LOD est justifié et son usage est adapté, car la portée de sa mise en place est connu ; eg. un simple plan. Les graphistes qui maîtrisent différentes méthodes et savent gérer leurs LOD au plan sont du pain béni pour la fabrication, surtout quand le projet est complexe et que le support est congestionné par des demandes générales. Soit le projet implique une utilisation des LOD plus fréquente/constante, ce qui implique de l’automatisation (le mot magique des incantations occultes) et les discussions sur comment ils doivent être gérés (les « choix techniques » au fond) doivent être mené entre la production, la supervision et la technique. Le but étant d’anticiper les besoins et d’éviter de se retrouver, plus tard, dos au mur ; « Mais on ne peut pas faire ça ? », « Non, tu ne l’as jamais demandé… », « Mais enfin, c’est <em>évidant</em> ! ».</p>
<p>Bref, c’est un sujet complexe alors soyez pro. :hehe:</p>
<h3>Conclusion</h3>
<p>Voici pour ce billet qui ne répond, finalement, pas à grand-chose, mais que j’espère instructif. :smileFou:</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/lod_001.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2019_08_04_lod/lod_001.png" style="margin: 0px auto; display: table;" /></a></p>
<center>:marioCours:</center>Exécuter du Python au démarrage de Guerillaurn:md5:ddcba8426cf4b66399d43e6179ae43092017-06-25T23:51:00+02:002020-11-12T09:42:57+01:00NarannScript et codeguerillaluapythonscript <p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/logos/guerilla.png" style="float: left; margin: 0 1em 1em 0;" />Un peu comme Maya et son <em>userSetup.mel</em>, <a href="https://www.fevrierdorian.com/blog/post/2016/06/25/www.guerillarender.com/" hreflang="en">Guerilla</a> permet d’exécuter des scripts au démarrage, mais que du lua. Voici un petit truc rapide pour exécuter du Python :</p>
<p>Si vous allez dans le nœud <em>Preferences</em>, dans <em>LocalSettings/Directories/User Plugins</em> vous pouvez définir une liste de chemins (<em>paths</em>).</p>
<p>Sachez que tous les fichiers <a href="https://www.lua.org/" hreflang="en" title="Site web de Lua">lua</a> présents dans ces différents chemins seront exécutés au démarrage de Guerilla. Sachez aussi que le lua de Guerilla intègre <a href="http://labix.org/lunatic-python" hreflang="en">une passerelle</a> vers Python. Ainsi, si votre fichier lua contient :</p>
<pre>
<code class="language-javascript">require('python')
python.execute('import myModule; myModule.doit();')</code></pre>
<p>Celui-ci exécutera le code Python :</p>
<pre>
<code class="language-python">import myModule
myModule.doit()</code></pre>
<p>Vous savez maintenant comment exécuter du Python au démarrage de Guerilla ! :bravo:</p>Post mortem: Ballerinaurn:md5:107657fad4613eb3c9236696f77dd6812017-06-11T16:26:00+02:002020-12-04T18:14:31+01:00NarannInfographie 3D - Boulotanimationballerinaguerillalong métragepipelineqube<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/post_mortem_ballerina_tn.jpg" style="float: left; margin: 0px 1em 1em 0px; width: 150px; height: 150px;" />Je viens enfin de finir le post mortem de mon travail sur le long-métrage Ballerina. Je vous préviens, c’est long.</p>
<p>En espérant que ça vous plaise. :popcorn:</p> <h3>La bande annonce</h3>
<p>Ce post mortem contient évidemment son lot de <em>spoil</em>. Je considère que vous avez déjà vu le film. Si vous ne l’avez pas fait, franchement faites-le. Le montage est rapide et on ne s’ennuie pas et vous lâcherez sûrement une petite larme. Dans tous les cas, voici la bande annonce :</p>
<p style="text-align: center;"><iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/M5-LjE4LSLA" width="560"></iframe></p>
<h3>Mon poste</h3>
<p>J’ai eu plusieurs casquettes durant le projet (comme d’hab’ en fait…). C’était du pip’, du pip’, du pip’. Voici une liste non exhaustive de ce que j’ai fait :</p>
<ul>
<li>Lookdev (<a href="http://www.guerillarender.com/" hreflang="en">Guerilla</a>)</li>
<li>Lighting (<em>Guerilla</em>)</li>
<li>Renderfarm (<em><a href="http://www.pipelinefx.com/" hreflang="en">Qube</a></em>)</li>
<li>Hair/Végétation (Maya/<em><a href="http://peregrinelabs.com/yeti/" hreflang="en">Yeti</a></em>)</li>
</ul>
<h3>Un démarrage difficile</h3>
<p>Sans rentrer dans les détails, le studio appartenait aux producteurs du film. C’était leur premier long-métrage. Le projet a connu un certain nombre de difficultés et a dû “recommencer” en cours de route. Je suis arrivé alors que le projet avait été mis en pause et une bonne partir des équipes, mise <span class="st">à</span> pied. Il n’y avait pas (plus en fait) d’outils, pas de pipeline. Nous n’étions pas nombreux dans le studio (moins de dix). La R&D commençait le pipeline et le département artistique continuait ses recherches. Il était d’ailleurs difficile de se dire, en arrivant le matin, qu’un film allait sortir de tout ça. La masse de travail abattu lors des premiers mois fut importante.</p>
<h3>Shotgun</h3>
<p>Le temps et les ressources disponibles étant limitées, nous avons opté pour <em><a href="http://shotgunsoftware.com/" hreflang="en">Shotgun</a></em> pour gérer l’intégralité de notre base de données (comprenez qu’il n’y avait aucune autre base de données que <em>Shotgun</em>, même pas un petit <a href="https://www.mysql.com/" hreflang="en">MySQL</a>, planqué sur un serveur en loucedé près des toilettes, rien !). C’est (très) cher mais au vu de la configuration du studio et de ce que <em>Shotgun</em> propose, je pense, avec du recul, que c’était un bon choix.</p>
<p>Une grosse partie du travail de départ concernait les <em>template</em> de chemin de fichier de <em>Shotgun</em> pour réussir à publier en utilisant <em>Shotgun</em> mais notre propre structure de fichier.</p>
<p>Viens ensuite la suppression des step/task de <em>Shotgun</em> au profit d’un système maison. C’est vraiment un truc idiot, dans <em>Shotgun</em>, que les steps et les tasks puissent être créées et modifiées par les coordinateurs, car on ne peut, du-coup, pas s’appuyer dessus en termes d’infrastructure. Il fallait donc les remplacer pour faire la même chose mais en plus robuste.</p>
<p>Comme tout changeait tout le temps, les chemins de fichier n’utilisaient pas les noms des assets et des plans mais leurs ids, donnant des chemins de fichier difficile à lire. Bien que ça puisse paraître dangereux, cela n’a posé aucun souci majeur en pratique car tout était fait pour éviter aux personnes d’avoir à naviguer dans la structure des dossiers.</p>
<p><em>Shotgun</em> est lent. Quand le builder est arrivé (voir plus bas) on s’est retrouvé à littéralement mettre <em>Shotgun</em> à terre avec des requêtes importantes (en gros, notre hiérarchie de scène c’était <em>Shotgun</em>…). Après pas mal d’optimisation de leur part, on a aussi mis un système de cache basé sur <em><a href="https://redis.io/" hreflang="en">Redis</a></em>. <em>Redis</em> est un système de cache sur serveur. Le principe est de stocker, dans <em>Redis</em>, le résultat des requêtes demandées à <em>Shotgun</em> pour éviter d’avoir à les refaire :</p>
<ul>
<li>Notre code fait une requête.</li>
<li>Il vérifie, dans <em>Redis</em>, si le résultât de la requête existe.</li>
<li>S’il existe, il l’utilise.</li>
<li>S’il n’existe pas, notre code fait la requête dans <em>Shotgun</em>, attends (looooooooongtemp…), récupère le résultât de la requête, le met dans Redis, puis l’utilise.</li>
</ul>
<p>Vous l’aurez compris : <em>Redis</em> c’est bon, mangez-en ! :sourit:</p>
<h3>Modeling, Rigging et Lookdev commencent</h3>
<p>Ces trois départements ont commencé rapidement et fonctionné en parallèle presque immédiatement, ce qui nécessitait, du fait de l’impossibilité d’anticiper, un nombre conséquent d’aller-retour. Il fallait être continuellement vigilant sur ce que chaque département livrait/récupérait. Ce fut épuisant pour tout le monde mais, et c’est peut être du fait des Québécois, personne ne râlait quand il fallait repasser sur un certain nombre de choses (chapeau aux modeleurs pour le nombre incroyable de retake techniques). Souvent nous comprenions tous pourquoi tel ou tel chose devait être modifié. L’ambiance générale était très bonne malgré les journées de travail éreintantes (c’est peut-être lié). Ça été ça pendant vraiment longtemps, doute-investigation-stresse-correction-test-avance.</p>
<h4>Tout override !</h4>
<figure style="margin: 0 auto; display: table;"><img alt="guerilla.png" class="media" src="https://www.fevrierdorian.com/blog/public/logos/guerilla.png" /></figure>
<blockquote>Note : Il faudra que je prenne le temps, un jour, d’expliquer le principe du lighting par override. Bien que cette pratique soit très utilisée en long-métrage et série, tout le monde ne la connaît pas nécessairement.</blockquote>
<p><em>Guerilla</em> est un superbe outil, je le crie à qui veut l’entendre. La logique mise en place sur <em>Ballerina</em> a été la suivante :</p>
<p>Un RenderGraph initial pour mettre les paramètres par défaut. Par exemple, appliquer un shader gris-neutre sur tous les objets, assigner un shader de curve sur les objets de type curve, modifier des paramètres en fonction des tags assignés sur les objets, etc.</p>
<p>Le second RenderGraph était appliqué par asset. Ce sont les RenderGraphs que les artistes du lookdev faisaient et publiaient. Il assignait des séquences d’UDIM par attribut du shader (spéculaire, couleur diffuse, etc.) et modifiait les paramètres ne nécessitant pas de textures. Le tout en s’accrochant aux tags des objets.</p>
<p>Enfin venaient les RenderGraphs du Lighting séparés en trois : Un pour la séquence, un pour un groupe de plan et le dernier pour le plan.</p>
<p>Chacun de ces RenderGraph changeait (overridait) les paramètres du RenderGraph précédent.</p>
<p>Cette liste ne s’est pas faite d’un coup. Par exemple, les lighters ont longtemps travaillé qu’avec un RenderGraph de plan unique, les RenderGraph de séquence sont arrivés plus tard, tout comme les RenderGraph de groupe de plan arrive quasiment à la fin.</p>
<h3>Recrutement des TDs</h3>
<figure style="margin: 0 auto; display: table;"><img alt="modus_fx_logo.jpg" class="media" src="https://www.fevrierdorian.com/blog/public/logos/.modus_fx_logo_m.jpg" /></figure>
<p style="text-align: center;">Ceci n’est pas un fournisseur d’accès internet. :trollface:</p>
<p>On a eu de la chance (dira-t-on), Modus FX a <a href="http://www.3dvf.com/actualite-9002-modus-fx-ferme-ses-portes-une-centaine-d-employes-licencies.html" hreflang="fr" title="Modus FX ferme ses portes, une centaine d'employés licenciés">fermé ses portes</a> au moment où on cherchait des TDs. On s’est donc récupéré énormément de TD expérimentés. Avec le recul, il aurait été difficile de sortir le pipeline sans leur aide, ils ont vraiment fait du bon boulot. Chaque TD avait la responsabilité d’un (ou plusieurs) département, mais nous codions dans le même repo git avec les mêmes standards de code. Il était d’ailleurs vraiment impressionnant de pouvoir sauter dans le code de ses collègues sans avoir l’impression d’être largué. Cette approche (très rigide à l’entrée) a réussi à créer une cohésion entre les TD qui a vraiment permis une « avancée de front ». Au passage : <a href="https://www.python.org/dev/peps/pep-0008/" hreflang="en">PEP 8</a> est un compromis, pas un standard.</p>
<p>Mon travail concernait principalement le lookdev. Nous avons utilisé <em><a href="https://www.foundry.com/products/mari" hreflang="en">Mari</a></em> et <em>Guerilla</em>. Comme la hiérarchie n’était pas fixe, nous nous sommes appuyé sur les tags. C’est un peu fastidieux et contre productif au premier abord, car les graphistes doivent placer leurs tags dans Maya, exporter leur abc et faire leur surfacing dans <em>Guerilla</em>. Mais il faut bien garder à l’esprit que la hiérarchie changeait constamment à cette période (rien n’était encore décidé en rig) il fallait donc trouver un moyen au lookdev de livrer sans dépendre d’autres départements. Ça été, je pense, une bonne décision.</p>
<p>Le travail consistait grossièrement à travailler dans <em>Mari</em>, exécuter un script qui sortait en <em>.tif</em> les UDIMs des channels sélectionnés, puis faire un Update dans <em>Guerilla</em> qui transformait ses mêmes <em>.tif</em> en <em>.tex</em> pour le rendu. C’était fastidieux et nous aurions pu améliorer la détection des updates pour éviter beaucoup de temps perdu, notamment lors de petites retakes. Notez que seul les <em>.tex</em> étaient publiés. Cela n’a pas posé de soucis en pratique.</p>
<h3>Builder</h3>
<p>Le builder (layout), c’est la colonne vertébrale d’un pipeline d’un film. Il permet la relation entre les informations de plan en base de donne et les logiciels. Un des gros chantiers de tout long-métrage c’est la capacité à construire les plans, si possible dans n’importe quel logiciel. Je ne me suis pas occupé du Builder du côté de la base de donne, mais de son intégration dans <em>Guerilla</em>. C’est d’ailleurs quand les plans ont commencé à se builder sans trop de soucis que j’ai réellement pris confiance en notre capacité à sortir le projet. Tant que vous n’avez pas le moyen de reconstruire des plans, à jour, en partant de rien, vous êtes dans une situation difficile (et si vous avez des équipes qui travaillent sur des plans avant d’avoir cet outil vous êtes franchement dans la m… Ouai nan… Faites un builder avant toute chose…). Du builder découla les quality check d’animation (Ambiant Occlusion) et leur automatisation sur la render farm.</p>
<h3>Instanciation implicite</h3>
<p>Une fois que vous avez un builder, vous construisez des plans de plus en plus gros, jusqu’à ce qu’ils ne rendent plus. L’intérieur de l’opéra (entre autres) montait anormalement en mémoire. On a donc creusé un peu pour se rendre compte que le modeling appliquait systématiquement un combo <em>reset transforms</em>/<em>freeze transforms</em> sur tous les objets, garantissant au rig que tous les objets étaient au centre du monde, ce qui simplifiait leur travail. Cela avait pour effet, lors de l’export en alembic, de casser les instances implicites.</p>
<h4>C’est quoi</h4>
<p>Le principe est simple : Quand deux shapes sont identiques, on considère qu’elles sont en instance. Ce qui définit une shape c’est (entre autres) la position de ces points par rapport à son centre. Si chaque objet a un centre différent, leurs points, une fois dans l’alembic, sont à des positions différentes. Ainsi, si vous dupliquez mille fois un objet, que vous écrasez les transforms de tous les objets, chaque objet a son centre au centre du monde, et donc, chaque objet a un centre différent de celui du voisin, et donc, tous les point qui compose un objet sont différents de ceux du voisin.</p>
<blockquote>
<p>Note : Maya fait une distinction entre le centre géométrique et le point de pivot. Il est donc possible de déplacer le point de pivot sans déplacer le centre géométrique.</p>
</blockquote>
<h4>Comment résoudre ça</h4>
<p>On était très avancé en modeling, il fallait une solution simple sans trop d’intervention humaine. L’approche prise est pragmatique et pas super mathématique : On avait remarqué que la topologie des objets étaient conservés. Nous avions donc la garantie que les deux premières arêtes connectées au premier point étaient les même sur tous les objets. S’ensuit un peu d’algèbre linéaire (produit vectoriel, scalaire, merci PyMEL) et on avait un algo capable de récupérer les objets qui pouvaient être implicitement instancié et récupérer un centre identique. Une UI plus tard les modeleurs pouvaient repasser sur les gros sets pour récupérer l’instanciation implicite des objets en quelques cliques.</p>
<p>Il n’empêche que malgré cet outil, il fallait quand même rouvrir tous les assets pour repasser dessus. Un travail assez laborieux et ingrats. Il y eut quelques tensions autour de ça (parce qu’il a déjà fallu repasser sur presque tous les assets auparavant pour des histoires de hiérarchie). J’avoue avoir pas mal forcé auprès de la prod pour que ce soit fait. Ce n’est jamais très apprécié de faire du forcing de la sorte, mais je pense que tout le monde a bien compris qu’on allait avoir de gros soucis si on ne le faisait pas.</p>
<h4>Effet indirect</h4>
<p>On a remarqué qu’en plus de diminuer drastiquement la consommation mémoire de <em>Guerilla</em>, les gros assets, en particulier les buildings, se chargeaient bien plus vite et étaient bien plus fluide à la navigation dans <em>Mari</em>.</p>
<h3>Hiérarchie des assets</h3>
<p>Comme je vous le disais, le rig n’était pas défini. Il a donc fallu repasser sur tous les assets pour conformer leur hiérarchie. On a donc fait des petites boucles qui ouvraient tous les assets du film pour passer un sanity check et savoir exactement quels assets devaient être rouverts. Mais on est allé plus loin : Avec les modeleurs, on a identifié les cas de “correction scriptable” pour le faire automatiquement. Après que les modeleurs aient teste la méthode sur quelques assets, on envoyait ça sur tous les assets de la prod. Si envoyer une boucle qui ouvre tous les assets pour faire passer un sanity check n’engage à rien. Le fait de modifier, en batch, des centaines d’assets est extrêmement risqué. On a fait la procédure et le suivi à deux, l’un à côté de l’autre pendant plusieurs jours ce qui permettait une réflexion et une remise en question continue (ne jamais laisser une seule personne faire du batch qui modifie les scènes toute seul). Car derrière l’apparente simplicité, le risque de casser des centaines d’asset est réel. On a donc fait ça avec le sérieux et le professionnalisme qui s’imposait, on a relu plusieurs fois notre code, on a fait des tests et forcement, on a tout pété! :baffed:</p>
<p>Bon, on a été malin, le commentaire de publication utilisé pour mettre à jour les assets contenait un mot très particulier. Il a donc été assez simple de rechercher les publications puis de les omettre dans Shotgun. Mais bon, je me rappelle qu’à ce moment, l’état d’esprit de la production c’était : :mitraille: :enerve: :tuComprendRien: :injures: :casseTeteMur: :nervous: :grenadelauncher:</p>
<p>Un petit fix, on a relancé la boucle et c’était bon… :siffle:</p>
<h3>Hair</h3>
<p>Les hairs ont été faits avec <em>Yeti</em>. Du fait des autres chantiers, les hairs sont restés longtemps sans personne (en R&D) pour leur assurer un pipeline propre. On savait qu’on allait le payer et ça n’a pas raté. La liste des problèmes rencontrés est très longue et, il faut bien l’avouer, assez misérables. Le rig n’était pas recentre, c’est-à-dire que plus les personnages étaient loin du centre, plus la géométrie avait des problèmes de précision (J’entends souvent que « c’est le B-A BA » mais je n’ai jamais vu son application sur un long. Le rigs étant souvent trop complexe).</p>
<p>En pratique les soucis de précision n’auraient pas dû être un problème car dans tous les cas, nous recentrions les scènes. C’était sans compter sur la boite noire qu’était <em>Yeti</em>. Nous n’avons jamais eu la confirmation de quoi que ce soit (les échanges de mail étant assez improductif) mais je soupçonne que <em>Yeti</em> essai de se rattacher à la surface d’une distance au prorata de la densité de point. C’est-à-dire que plus il y a de point, moins <em>Yeti</em> va chercher la surface. Le problème que cela posait était le suivant : Afin de pouvoir générer un vecteur de motion blur, chaque point de chaque courbe qui compose les hairs doit être présent deux fois à t et t+0.5. Sauf que si <em>Yeti</em> n’arrivait pas à retrouver une surface lors d’un des samples, il ne calculait pas la courbe, le nombre de point devenait donc inconsistant entre t et t+0.5. Sans un nombre consistant de point, <em>Guerilla</em> ne pouvait générer les <em>motion vectors</em>, il ne lui restait donc qu’à cacher la partie des hairs qui posait problème en affichant un warning. La solution ? Recentrer les hairs avant l’export de la simulation, sauvegarder l’offset et l’appliquer dans <em>Guerilla</em> avant rendu B-D. Je vous passe les détails mais ça été un beau bordel. Toutefois, le truc cool en code c’est qu’à force d’effort et d’acharnement, ça finit par marcher mais ça été long et fastidieux.</p>
<h3>La végétation</h3>
<p>Une autre de mes taches sur le projet a été de faire un outil pour gérer la végétation, en particulier les arbres et les buissons. La première question est pourquoi ne pas utiliser <em>Yeti</em> ? C’est difficile à expliquer si on ne sait pas comment fonctionne un pipeline. <em>Yeti</em> génère des <em>.fur</em> tout-en-un qui sont “déroulés” dans <em>Guerilla</em> au moment du rendu. Cette étape est très longue, la mémoire prise par <em>Yeti</em> lors de la génération des primitives est énorme, la bounding box est globale, l’instanciation compliquée et surtout : Une mise à jour d’un des assets nécessite un reexport du système de <em>.fur</em> entier. Dans une logique de pipeline d’animation, chaque département n’est supposé publier que le minimum de ce qui est nécessaire. Dans le cas de la végétation seul des informations de position/rotation/échelle ainsi que l’id de l’asset à placer (avec ses attributs de variations) sont nécessaires. Ainsi, dans <em>Guerilla</em>, on amène l’alembic contenant uniquement les positions des assets, la géométrie source de l’asset (que l’on cache), un script pour lier chaque position à la source et c’est terminé. On avait quelques soucis de performances, isolé dans ticket, résolu par les gars de <em>Mercenaries</em> (les développeurs de <em>Guerilla</em>) dans la semaine et on avait un système d’instance très léger, qui rendait immédiatement.</p>
<p>L’outil a été un peu long à écrire, mais on l’a étendu à un certain nombre de plans, notamment pour placer des personnages en instance sur les vues d’ensemble.</p>
<p>Mon seul regret de technophile à poil dur fut la demande de diminuer le nombre d’arbres “parce qu’il y en avait trop” alors qu’on avait virtuellement aucune limite.</p>
<h3>Lighting</h3>
<p>La production a fait du bon boulot, car Le Petit Prince venait de se terminer et on a pu embaucher bon nombre de lighters déjà formé sous <em>Guerilla</em>. Je me rappelle avoir présenté le pipeline à une juniore qui, après m’avoir écouté déclarer mon amour pour les overrides, me fit comprendre qu’elle connaissait déjà tout ça. Tous les lighters étaient à l’aise avec <em>Guerilla</em>. Ils avaient travaillé avec une ancienne version pendant un long-métrage entier et découvrait également que beaucoup de leurs soucis avaient été résolus depuis.</p>
<h4>Publier</h4>
<p>On a choisi de versionner les séquences d’image de manière granulaire, à l’AOV (pass/layer/aov/<version>). Comme nous avions beaucoup d’AOV, il y avait énormément de versions à publier à chaque fois. On a fait une UI tout-en-un pour simplifier le travail de gestion des rendus des lighter (et aussi éviter qu’ils aillent se perdre et tout casser dans la hiérarchie de dossier :P). Sous le capot, l’interface était threadé à mort. Il fallait, en effet, s’assurer que le lighter voit, quand une séquence était incomplète, quelles images manquaient (et il y avait beaucoup de séquences). Le gros problème venait de <em>Shotgun</em> qui lâchait parfois prise et bloquait les publications sans raisons apparente, il fallait donc reprendre là ou il s’était arrêté (heureusement les cas d’arrêt pendant la copie d’une séquence d’image était rare).</p>
<h4>Override à la séquence, par groupe de plan, puis par plan</h4>
<p>Il est intéressant de constater qu’une des feature du pipeline qui permet d’économiser énormément de temps n’est arrivé que lors des six/sept derniers mois du projet. C’est quelque chose qui a été discuté très tôt, avant même l’arrivée du modeling. C’est un des trucs dont je suis le plus fier et qui a réellement augmenté la vitesse de sortie des plans. Le principe est de pouvoir overrider à la séquence mais surtout par groupe de plan. Dans la pratique, le lighter pouvait grouper les plans d’une même séquence similaires (exemple : champ/contre-champ) et appliquer des overrides pour chacun des groupes puis de propager sur toute la séquence. Ainsi, les lighter ne travaillaient plus au plan mais à la séquence. Les seniors ont rapidement sauté dessus. De manière surprenante, certains juniors ont également vite emboîté le pas. Ce n’était pas parfait, les rigs de light devaient toujours être propage manuellement et la UI de gestion des groupes n’était pas terrible, mais les séquences passaient en revu en entier très rapidement après avoir été commencé. La vitesse gagne en lighting sur certaines séquences simples était vraiment énorme.</p>
<h4>Shot group</h4>
<p>Il y avait deux façons de publier un rendergraph de lighting : À la séquence, et au plan. Le rendergraph de plan overridant le rendergraph de séquence. L’idée était que, quand un graphiste commençait une séquence, il remonte toutes les modifications nécessaires sur toute la séquence dans le rendergraph de séquence pour ne laisser dans le rendergraph de plan que les modifications spécifiques au plan. C’est une approche assez conventionnelle quand on travaille avec des overrides, car bien souvent, le pipeline permet de publier des choses à la séquence ou au plan. Mais elle laisse un trou énorme : Que faire quand on souhaite éclairer deux plans similaires. :reflechi:</p>
<p>Si par exemple votre séquence se compose de quelques plans d’intro (souvent large), puis d’un enchainement de champ/contre champ, identique en termes de lighting, puis trois plans de sortie, vous avez 4 groupes de plan :</p>
<ul>
<li>intro (2 plans)</li>
<li>part_1_char_1 (4 plans)</li>
<li>part_2_char_2 (5 plans)</li>
<li>outro (3 plans)</li>
</ul>
<p>Chaque studio semble faire sa tambouille mais après quelques semaines de travail, on a commencé à réfléchir a un moyen de publier des choses « par groupe de plan ». Et ne croyez pas que c’est évidant. Sur un plan purement ingénierie, cette approche est « anti-hiérarchique » dans un pipeline, car si la hiérarchie « studio/projet/séquence/plan/cam » est fixe, les groupes de plan peuvent être défini différemment suivant qu’on est en lighting ou en animation (ou autre). Il s’agissait donc d’une structure par séquence (il fallait bien la mettre quelque part) non connu à l’avance, donc difficilement structurable.</p>
<p>Les lighters avait donc moyen, par séquence, de faire des groupes de plan. Ils visualisaient la séquence et commençait déjà à réfléchir comment ils allaient publier chacun de leur rendergraph.</p>
<p>Au moment de construire le plan, on récupérait le rendergraph publié au plan, puis on demandait le groupe dans lequel était le plan en cours, puis on récupérait le rendergraph publié dans ce groupe. Les rendergraph s’enchainaient dans cet ordre : « sequence/shot group/shot ».</p>
<p>Cette méthode est arrivée très tard sur le film (je dirais le dernier quart en termes de planning) mais elle a permis quelque chose d’énorme : Les lighteurs pouvaient prendre et éclairer des séquences complètes. Ça prenait un peu plus de temps à démarrer (comparé à un éclairage au plan) mais quand ils avaient fini, ils envoyaient toute leur séquence en rendu et l’itération se faisait par séquence.</p>
<p>Un autre effet fut que l’éclairage était beaucoup plus cohérent entre les plans. Très souvent, les éclairages au plan tendent à casser l’homogénéité de la séquence. Ce sont les lead qui veillent constamment a l’homogénéité de l’ensemble (éclairage, couleur, etc.), mais malgré ça, ça se voit toujours. Le fait de repousser la modification par plan aussi loin que possible permettait de sucrer une bonne partie des retakes d’homogénéité. Au final, le rendergraph de plan était quasiment vide d’information d’éclairage.</p>
<p>J’avoue ne jamais avoir vu de système semblable aussi pousse. Bien entendu, ce n’est pas parce que je n’en ai pas vu que ça n’existe pas. Mais bien souvent ce sont des outils de propagation qui permettent d’envoyer l’éclairage d’un plan dans un autre plan, pas une publication entre la séquence et le plan.</p>
<h3>Render farm</h3>
<p>Disons-le clairement, la gestion de la render farm n’était vraiment (mais alors vraiment) pas quelque chose qui m’attirait. Et pourtant, ça été très intéressant. Et pour cause, la render farm ne concerne pas uniquement le rendu. C’est de la puissance disponible pour de l’automatisation de tâche. Et on en a bien usé:</p>
<ul>
<li>Génération des alembic en sortie du modeling, de l’animation et des fx.</li>
<li>Export automatique des séquences de <em>.fur</em> (<em>Yeti</em>) en sortie du département d’animation.</li>
<li>Build et calcul des ambiant occlusion pour le contrôle de qualité des animations.</li>
<li>Trigger lors des validations.</li>
<li>Mise à jour automatique des plans de lighting avant rendu.</li>
<li>Build et rendu des precomps.</li>
<li>Et bien entendu : Rendu des images</li>
</ul>
<p>On a utilisé <em>Qube</em>. Un truc qu’il faut savoir concernant les gestionnaires de ferme de rendu c’est le “bruit réseaux” qu’ils produisent. Le nombre de machine augmentant (certaines n’étaient pas situe dans la boite mais à plusieurs une centaine de mètres du studio), il peut arriver qu’une quantité non négligeable des accès réseau ne soit prise que par le gestionnaire de ferme de rendu qui communique avec ses clients. Le problème apparaît lorsqu’il y a congestion ou chaque client a besoin de contacter le serveur sans que ce dernier ne soit capable de répondre, s’ensuit un effondrement des performances générales. Certains gestionnaires, plein de fonctionnalités qui se veulent pro-actifs (vérifier que toutes les images sont sorties, qu’elles ne sont pas corrompues, etc.) sont capables, de par leur activité, minime mais intrusive, de mettre à terre un réseau déjà bien occupé à charger des gigas de données. C’est un détail à prendre en compte quand on commence à monter en charge. Au-delà de ça, Qube a une API assez soviétique sur les bords, on sent le logiciel mature, stable et tu le payes par une API complexe.</p>
<h3>Matte Painting</h3>
<p>On ne peut pas vraiment parler de pipeline pour le département de matte painting, mais de support. C’était rafraîchissant : Transfert de caméras de projection entre <em>Guerilla</em> et <em>Nuke</em> (avec ce sentiment de satisfaction quand on attend enfin le <em>pixel-perfect</em>). J’ai également pu constater à quel point <em>Nuke</em> était mauvais en 3D et à quel point un “vrai” logiciel de matte painting manquait. Je ne parle bien évidemment pas pour la peinture digitale mais pour la gestion de la 3D (projection et manipulation de la géométrie).</p>
<h3>Commentaire de plan</h3>
<p>Sur un long-métrage, chaque plan a une histoire. Entre le nombre de département qui passe dessus (modeling, layout, animation, rendu, compositing) et les allez-retours de validation entre chaque étape, chaque personne ayant travaillé sur le projet a une d’histoire à raconter. En revoyant le film, je me suis dit que j’avais envie de commenter les plans. C’est parti !</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_001.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_001_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Voici un plan typique d’arbres et d’herbe. Je pense qu’il y a eu une difficulté de communication autour du placement des arbres. Aucun décor breton (et français d’une manière générale) ne ressemble a ça, les arbres sont supposés délimiter les champs alors qu’ils sont placés de manière très aléatoire ici. Je soupçonne que l’esthétisme a été privilégié mais du-coup ça manque un peu de vie. Autre remarque sur Yeti : On l’a aussi utilisé pour placer des branches et des cailloux, mais on se retrouvait avec des bounding box énormes pour finalement peu de géométrie, ce qui a pas mal ralenti le rendu.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_002.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_002_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Le décor de l’orphelinat, l’un de mes préférés.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_003.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_003_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Il est à noter que cette pièce est utilise à la fois pour la cuisine et pour le dortoir. Les lits remplaçant les tables. Ça passe super bien dans le film et ça a permis de se focaliser sur une seule pièce.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_006.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_006_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Je ne peux plus vérifier, mais je crois que ce plan a été rendu dans les derniers, quand la farm était quasi vide et mettait 14 h l’image :aupoil: . Si je me rappelle bien, on savait que c’était lié à tous les rochers et branches par terre, mais on a décidé de ne pas trop chercher plus loin.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_008.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_008_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>La boite à musique, ou comment un plan totalement anodin peut rendre fou. Dans Maya les sous frames de l’animation étaient parfaites, mais une fois exporte en alembic puis réimporte, le motion blur explosait certaines pièces (notamment le <a href="https://fr.wikipedia.org/wiki/Trisk%C3%A8le" hreflang="fr">triskèle</a>). C’était devenu un <em>running gag</em>… Je ne sais même plus comment on a fini par résoudre le souci, mais je ne serais pas surpris qu’on ait totalement désactivé le motion blur 3d sur ce plan.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_009.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_009_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Les escaliers sont souvent une tanne à rendre, mais je trouve que l’équipe lighting s’en est sorti à merveille.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_010.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_010_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>J’adore cette séquence de nuit. Le fait d’avoir une seule source principale de lumière (celle de la moto) donne à la séquence un aspect dramatique. Encore une fois, je pense qu’on a trop négligé le placement des arbres, ça manque de vie.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_011.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_011_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Notez le renfoncement de la route sur toute cette séquence. L’objectif, vous vous en doutez, est d’éviter d’avoir à travailler l’horizon sur l’ensemble des plans.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_012.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_012_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Et voila un keyshot. Le principe d’un « keyshot » (ou « plan-clef ») sur un long-métrage (et en animation 3d d’une manière générale) est de valider l’éclairage type d’une séquence (couleur, ombres et tout ce qu’il est possible de définir dès cette étape en fait). Ils sont donc souvent plus travaillés que les autres et permettent aussi de mettre le doigt sur les problèmes techniques avant d’entamer le travail à la séquence. Ce sont souvent les seniors qui font ses plans. L’objectif est de se représenter l’intégralité de la séquence et comment tous les plans vont être fait et de « passer la main » aux graphistes juniors qui (en principe mais là on rêve un peu) ajuste un éclairage donné sans se prendre la tête.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_013.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_013_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Le train a été utilisé pour faire quelque chose d’assez peu courant (longue explication en approche): Sur ce projet, le layout avait la possibilité de bouger les contrôleurs de certains objets des assets pour éviter la répétition. Un bon exemple sont les volets des maisons, les portes, les tables, etc. Le problème c’est que du-coup, les assets en questions ne sont plus vraiment en position d’origine ce qui est assez problématique, car vous ne pouvez plus simplement considérer, dans votre base de donne, qu’un shot contient une instance d’asset place a tel endroit, il faut aussi avoir la liste des modifications de placement quelque part. Très souvent (enfin j’ai vu ça partout jusqu’à présent), la solution retenue face à ce dilemme est : « Si ce n’est pas juste un déplacement du contrôleur global, c’est de l’animation » et donc, c’est exporté avec l’alembic d’animation du plan (qui contient les personnages et les props déplacés). Mais avouez que c’est bête d’imposer l’export par plan d’un asset au complet quand seul un des objets qui le compose (un volet, une porte, etc.) est modifie… On a donc décidé de se lancer dans une quête un peu folle consistant à récupérer les modifications de placement des sous objets au layout pour pouvoir les appliquer sur l’asset original lors de la construction du plan au rendu. Pour être honnête, on eut pas vraiment le choix, le layout avait fait un gros travail de placement (il y a des contrôleurs, ils les bougent, c’est normal) quasiment plus aucun asset ne correspondait a sa position d’origine… Il fallait donc, pour les assets en questions, stocker la position des objets qui ne sont pas à leur placement d’origine. Sauf qu’il peut y avoir une différence entre le placement d’un contrôleur (que le layout déplace) et le placement de la géométrie qu’il contrôle. Le rig garantie (en principe, mais ce n’est pas le problème ici) que la relation de position entre un contrôleur et la géométrie qu’il contrôle est toujours la même. Mais il ne garantit pas que l’origine de la géométrie en question soit constante entre les versions de rig. Pas grave me diriez-vous, c’est pas le truc qui change souvent… Et devinez quoi ? Oui, c’est ce qui c’est passé, l’origine des géométries bougeait entre les versions de rig :smileFou: . Rappelez-vous, le rig n’a été défini que très tard sur le projet et chaque choix se confrontait a ce qui était déjà en place. On ne pouvait donc pas s’appuyer sur la position des géométries mais uniquement sur celle des contrôleurs… Bon, on a les positions des contrôleurs modifiant un asset au plan, mais comment je connais la relation avec la géométrie ? C’est ici que les histoires sérieuses de sanity check on commencées. Il a fallu être extrêmement rigoureux sur la façon dont les contrôleurs « non-déformant » étaient connectées aux objets qu’ils contrôlaient. De sorte qu’il n’y eut qu’une simple matrice (intitulée sobrement <em>offset matrice</em> ou « matrice de décalage ») à appliquer sur la position en espace monde du contrôleur pour obtenir la position en espace monde de la géométrie (matrice du contrôleur + offset matrice = position identique dans Maya et Guerilla !). Il fallait donc stocker, par publication de rig, l’offset matrice de chaque contrôleur « non-déformant » puis l’utiliser lors de l’import d’un asset dans un plan. Mais attendez ! Attendez ! C’est même pas fini en plus lol ! Certains objets nécessitaient une hiérarchie de contrôleurs non-déformant et il fallait que mon bordel fonctionne avec eux aussi ! XD Il fallait donc stocker des numéros indiquant la profondeur du contrôleur pour appliquer les offset matrice dans le bon sens ! :aupoil: Le wagon était le premier assez du genre. La porte du wagon étant coulissante et compose d’un second objet (la serrure de la-dite porte). Je me rappelle de ma scène Guerilla que je passais mon temps a builder en tournant mon wagon et les contrôleurs de la porte et de la serrure dans tous les sens, a tous les niveaux de la hiérarchie en croisant les doigts pour obtenir le même résultât. J’ai du y passer une ou deux semaines à plein temps en mode chien méchant mais ça été super robuste car c’est une partie du code que je n’ai plus du tout touche par la suite.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_015.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_015_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Cette séquence dans le wagon me fait toujours rire car Victor allume et éteint une lampe à huile en la touchant vaguement et certaines pommes sont posées sur des surfaces plates sans bouger alors que les plans subissent un <em>shake cam</em> pour simuler le mouvement des wagons :sourit: .</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_017.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_017_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Éclairer le contenu d’une boite fermée… Tout un programme. Si je me souviens bien les planches du fond et du dessus n’étaient pas visible des lights. Vous pouvez le remarquer sur les cheveux et le bras de Félicie. Les pommes étaient faites en particule. Je me rappelle avoir bossé sur un moyen de faire des variations de teinte sur le lookdev des pommes suivant un attribut de particule. Un effet subtil de variation de teinte.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_018.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_018_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Un des <em>money shot</em> du film. Un <em>money shot</em> (qui peut se traduire de deux façons suivant qu’on l’achète ou suivant qu’on le budget :hihi: ) est un plan qui est caractérisé par le cout nécessaire a sa fabrication et par l’effet <em>Woaw !</em> qu’il est supposé engendrer chez le spectateur. Celui-ci part du <a href="https://fr.wikipedia.org/wiki/Pont_d%27I%C3%A9na" hreflang="fr">pont d’Iéna</a>, passe entre les fondations de la tour Eiffel puis fini sur une vue d’ensemble. C’était LE plan test du builder. Beaucoup de bâtiment, beaucoup de géométrie, beaucoup de personnages, beaucoup de spéculaire, beaucoup de textures, beaucoup de matte painting, etc. Paradoxalement, le fait d’anticiper ces plans très tôt (dès le layout tu te fais une idée de la difficulté) fait qu’au final il n’a pas pose de problèmes majeurs. Les problèmes vraiment contraignant arrivent souvent sur des plans totalement anodins.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_020.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_020_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Celui-là je ne mets pas parce qu’il est joli ( :trollface: ) mais pour la petite histoire : Pour une raison qu’on ignore totalement, la texture des bouées (sur les bords du bateau) popait au rendu. On a jamais compris pourquoi et malgré tous nos tests (hashing des textures, hashing des uvs, compression, etc.) on a pas eu le temps de régler le souci suffisamment rapidement. Du-coup (et après discussion) elles ont été supprimées du bateau. Notez que ce n’est pas la règle. On ne supprime pas un truc à chaque fois qu’il nous embête, simplement qu’il faut constamment prioritiser les choses à faire, et parfois il faut trancher. Mais ce n’est jamais fait de gaité de cœur.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_021.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_021_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce plan (et la séquence d’une manière générale) fut le plan de test. On y est reste longtemps pour affiner nos méthodes d’exports d’alembic, de rendu sur la farm, déterminer quels AOVs on sort… Bref, pousser le pipeline pour faire, ce que j’appelle, la première boucle (un pipeline qui marche du début jusqu’au plan final composite). À l’époque il n’y avait pas de lighters ni de compositeurs, seuls les superviseurs de ces deux départements étaient présents. C’est, je trouve, un des plans les plus travaillé du film. La subtilité du rendu du sol ne se retrouve sur aucun plan. Il est aussi moins sature que le reste des plans.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_022.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_022_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Le plan qui suit. Notez la qualité du SSS de la peau, assez différente du reste du film.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_023.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_023_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Juste pour préciser qu’il n’existe aucun axe dans Paris qui permet cette vue sur l’opéra. :jdicajdirien:</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_024.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_024_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Encore un plan de cette séquence que je trouve magnifique. C’est exactement comme Paris : Des pavés luisants avec un petit brouillard de fond. Ce cadrage est repris plusieurs fois dans le film mais le rendu n’a rien à voir.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_025.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_025_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Les pavés sont 100 % displacement. On a essayé en normal map et tout mais vers la fin du plan, le sol apparaissait beaucoup trop plat.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_026.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_026_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Anecdote intéressante, le temps de rendu de l’AOV des pavés sur ce plan prenait énormement de temps car, étant en displacement ET de biais, les rayons de la caméra faisaient des tests d’intersections sur beaucoup de triangles avant d’en toucher un. Ce n’est pas forcément une bonne tactique d’avoir de gros temps de rendu sur des plans comme ceux-là qui risquent d’exiger beaucoup d’itérations avant d’être validé.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_027.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_027_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce décor a été fait sur plan. On avait énormément de livres au studio sur l’Opéra de Paris et même une petite maquette carton. Ce fut aussi un des candidats pour l’outil de récupération d’instance implicite car nombre d’objets se répètent. J’ajoute qu’il ne fut pas simple du tout à éclairer. Sur des plans rapprochés, on remplaçait les lights hors cadre chacun des lampadaires (4-5 par lampadaire, sans compter les bougies) par une seule light, plus grosse, mais a l’intensité et la couleur globale similaire. Cette méthode de « dégrossissement » du lighting permettait de diminuer le nombre de lights sur un plan (et donc diminuer le temps de rendu et le grain) sans modifier le retour visuel. Donc oui, gros travail sur ce décor.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_031.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_031_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_034.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_034_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Je vous présente mon personnage favori sur ce film : Odette. J’avais très peur que ses vêtements à base de laine ne passent pas ou mal à l’écran. Au final je trouve que ce sont les vêtements les mieux réussi du film. L’écharpe et le petit drape sur les épaules sont faits en displacement pour l’épaisseur de la laine. Ça fait toute la différence.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_035.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_035_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_074.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_074_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>J’ai remarqué un truc sur les longs-métrages : L’attachement des différentes personnes travaillant sur le projet aux personnages du film est réel et souvent révélateur de la profondeur du film. Si sur un projet, aucun personnage ne semble intéresser les gens ou donner envie d’en savoir plus, c’est que quelque chose n’est pas bien passe. Je ne parle pas d’animation, mais de chara-design : Le faciès, l’attitude, la voix et l’histoire du personnage doivent questionner, donner envie que le personnage réussisse (ou perde dans le cas du méchant). C’est assez caractéristique dans les films « commerciaux » ; il faut réussir à développer suffisamment de personnage pour qu’une cible de spectateurs puisse s’identifier. Merante avait aussi une histoire très développée.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_033.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_033_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_062.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_062_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Les plans de nuit sont rares dans les films d’animation. Pourtant, une grande partie de Ballerina se passe la nuit ce qui donne des effets super intéressants. L’éclairage du visage d’Odette par la lampe (blanche et froide vous aurez remarqué) de la grande méchante, ainsi que l’alternance classique bleu marin/orange cache une décision plus rationnelle : À l’origine, énormément de plans devait se dérouler dans les rues de Paris. Une des premières décisions fut de s’arranger pour que ces plans se passent de nuit de manière à diminuer le nombre de personnage secondaires. C’est encore plus tard que presque tous les plans de Paris disparurent au profit de plans dans la cour intérieure.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_036.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_036_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>L’éclairage des escaliers se révèle toujours assez compliqué. En effet, il faut beaucoup de lumières éclairant différentes parties distinctes, mais le <em>path tracer</em> a souvent du mal à deviner quelle lumière éclaire quelle partie, ce qui amène facilement du grain.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_037.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_037_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce plan fut assez compliqué à faire en raison du nombre de miroir et d’AOV nécessaire a la recomposition de l’image. En effet, quand on a une réflexion pure (un miroir) il faut trouver un moyen de propager les AOV dans la réflexion pour pouvoir les sortir séparément. Ensuite, il faut recompositer chacun des miroirs pour finalement les intégrer au plan. Bon, le problème vient du fait qu’il fallait aussi fournir une Z de qualité pour la version stéréo. Il fallait donc aussi propager la Z.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_038.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_038_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce plan fut mon plan de test pour les outils de projection en matte painting. J’avoue ne plus me rappeler du tout pourquoi la projection était nécessaire mais que j’étais trop fier quand mes petits calculs me rendaient une projection « pixel-perfect » du rendu dans Nuke !</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_039.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_039_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Le directeur de l’Opéra fut le premier adulte en lookdev. Il a été utilisé pour par mal d’expérimentation concernant le rendu des visages et en particulier le nez qui devait avoir des bords bien définis. L’origine remonte a une décision de rig qui avait demande au modeling de diminuer la complexité des maillages des visages, cassant ainsi les bordures du nez. Je pense qu’on aurait pu faire différemment, mais je n’avais pas mon mot à dire. Bref, donc : À la charge du rendu d’afficher quelque chose de convaincant. On est naturellement parti sur des normales mais le problème du <em>normal mapping</em> basse fréquence c’est qu’il commence à devenir bizarre en gros plan, quand l’axe de la caméra devient tangent à la surface (en faisant apparaitre une sorte de liseré sur la couche de réflexion). J’ai donc dû me pencher sur un peu de math pour proposer un moyen de switcher du normal map au displacement suivant les plans. Pour être honnête, je ne suis pas sûr que le displacement fut utilise sur beaucoup de plans.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_040.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_040_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Il a eu un truc de vraiment problématique avec les intérieurs de l’Opéra de Paris et en particulier ce plan : Tout est plat et répétitif. Je me rappelle d’un couloir tellement basique que le DA était assis près du superviseur ligthing pendant plusieurs jours pour réussir a faire un truc « regardable ». Au final, la réalisation et l’animation des personnages prends le dessus et on y attache peu d’importance mais oui, éclairer des murs plats ce n’est pas la joie.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_041.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_041_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_064.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_064_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Cette pièce est le premier « gros » intérieur qui a été préparé pour le rendu. Il apparait en effet sur beaucoup de plans du teaser. Lui aussi était dur à aborder car si on enlève les parquets, il y a peu de zones vraiment intéressantes en termes d’éclairage. Notez aussi que tout l’éclairage est diffus et il y a peu d’éclairage direct. Anecdote intéressante : Un grand miroir se situe au centre de la pièce mais posait pas mal de soucis autant techniques que narratifs. Au final, un grand drap a été mis dessus ni vu ni connu.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_043.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_043_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ici, la manche de Victor est en gros plan. Le lighting a donc choisi d’appliquer du displacement pour ajouter du détail et de la nuance dans la forme. Mais comme le rig n’était pas recentrable, les vertices de la géométrie vibraient légèrement. En soi, ce n’est pas trop problématique quand les vertices sont éloignés les uns des autres. Mais quand on displace, il y a un vertice tous les deux/trois pixels, du-coups le flickering commence à se voir (sous la forme d’un léger « bourdonnement » de la manche). Comment régler ce souci comme un vrai pro ? On prend la scène d’anim, on décale le personnage d’une distance particulière en vu de le rapprocher du centre (2000 en x par exemple), on ré-exporte l’alembic, on met à jour l’alembic dans Guerilla, puis on décale le personnage de 2000 en x dans l’autre sens. :aupoil:</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_044.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_044_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce plan séquence fut surement le plus compliqué du film. Il a pris plus d’un mois a un graphiste senior à plein temps pour en venir à bout. Chaque personnage était présent deux à trois fois dans la scène et le layout les a faits s’alterner pour donner l’impression d’une continuation. L’éclairage était un cauchemar (extérieur, intérieur puis extérieur) du-coup beaucoup de choses ont été séparé ce qui est très risqué car cela entraine souvent de la mauvaise intégration et une difficulté à garder un éclairage cohérent (c’est souvent le cas sur les plans « sur-composités »). Et pourtant, j’avoue ne pas lui trouver de défauts. Franchement le boulot est impeccable de bout en bout.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_057.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_057_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Regardez les variations de positionnement des volets. C’est à ça qu’a servi le travail que je vous exposais plus haut avec l’histoire de la porte du wagon. Vous allez me dire que tout le monde s’en fout mais tous les objets ont bénéficié d’un travail de cadrage (on parle souvent de « set-dressing ») de la part du layout et je pense vraiment que ça rend l’image plus naturelle.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_059.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_059_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_060.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_060_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_061.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_061_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Cette séquence fut une des premières à être éclaire en utilisant le principe des shot groups, par un seul graphiste. L’ensemble est hyper homogène.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_063.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_063_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Hahaha ! Je me rappelle bien cette séquence : L’échelle du projet était de 1 unité = 10 cm. C’est peut-être peu commode mais ça résolvait pas mal de soucis. C’était un bon compromis. Le FX guy avait mal configuré son échelle de décimation. Du-coup, le premier export des volumétriques de ce plan était monstrueusement énorme, genre un triangle par pixel ! Mais le pire c’est qu’on avait mis en place un système qui appliquait une subdivision de 1 a tous les mesh :IFuckTheWorld: . <a class="media-link" href="https://www.fevrierdorian.com/blog/public/gif/atomic_bomb.gif">Resultat</a>.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_065.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_065_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Le toit de l’opéra était un des assets les plus massifs en termes de travail pour les textures. Les instances implicites ont eu un gros impact sur le quotidien des graphistes travaillant sur cet asset.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_067.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_067_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>L’atelier fut le plan de test ultime pour la builder. Il y a des objets partout, dans toutes les positions. Si ça build correctement, tout le film devrait marcher (pas vrai ? :siffle: ).</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_070.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_069_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_070_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Dans le bar breton, un des drapeaux fait référence à l’endroit où ce film a été fabriqué. Saurez-vous trouver lequel?</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_072.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_072_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Un plan pour lequel je me serai beaucoup battu, mais qui aura eu raison de moi. Je ne sais pas si vous avez déjà fait des soirées (nuits ?) à Paris mais la réflexion des éclairages publiques sur les pavés (très sombres) est très présent, quand bien même il n’a pas plu. Sur ce plan la réflexion des pavés était trop plate, car la normal map semblait devenir neutre après quelques mètres, donnant un effet tout lisse. Malgré mes tentatives pour redonner un peu de consistance au sol, la réflexion a été très atténuée pour pouvoir livrer à temps. Au final il passe très bien dans le film. J’ai juste un blocage personnel dessus.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_079.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_075_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_079_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>OK, j’avoue, ce projet a développé en moi un fétichisme pour les vieux parquets bien lustrés… :pasClasse:</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_080.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_080_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Pour faire valider les diamants de la couronne de ce personnage, les lookdev a dû honteusement tricher en augmentant l’intensité de ces derniers aux points qu’ils créaient de la lumière. Path tracer oblige, on se retrouvait avec des points blancs sur les plans ou ce personnage apparaissait. On a mis un peu de temps à trouver, mais des petits points blancs dans un plan (appelés <em>fireflies</em>) sont souvent dû à un shader qui renvoi une haute valeur.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_084.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_084_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Comme bien souvent avec les « trucs à plume », la poule est un asset qui a demande beaucoup de travail, avec du Yeti et quelques morceaux de shader écris pour l’occasion. Un des running gag original du film consistait à la faire revenir plusieurs fois a l’écran tout au long du film.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_085.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_085_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Ce plan est très différent des autres en termes de colorimétrie. On est beaucoup plus sur des teintes Pixar/Illumination. Au passage, le personnage de la mère de Félicie fut la favorite d’une partie de l’équipe pendant longtemps mais le fait qu’elle apparaisse qu’une seule fois (sur un plan fait vers la fin de la production), n’a, je pense, pas permis aux différentes personnes intervenants dessus d’y passer le temps nécessaire.</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_086.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_086_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Tu passes une prod à régler les soucis de hairs des personnages, les uns après les autres. Au bout d’un moment tout marche, tu penses que les problèmes de hair c’est fini, tu as déjà fêté ça il y a deux mois et BAM ! Tu as un nouveau plan qui tombe un peu avant la fin du projet. Avec au programme, un nouveau perso, visible uniquement sur ce plan, en gros plan avec les cils et les sourcils qui flickent !</p>
<p style="text-align: center;"><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_088.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_088_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/post_mortem_ballerina_comment_096.jpg"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_03_27_post_mortem_ballerina/commentaire_plan/.post_mortem_ballerina_comment_096_m.jpg" style="margin: 0px auto; display: table; width: 560px; height: 236px;" /></a>Je vais finir ce commentaire avec deux plans et un petit mot concernant l’animation. On l’entend souvent, l’animation est le truc le plus important et c’est vrai : Si les personnages ne sont pas « vivants », c’est terminé. Le lighting et le compo n’y pourront pas grand-chose. Le <em>chara-design</em> de Ballerina c’est pas le plus simple à aborder. Pour une raison qui m’échappe (je ne m’occupais pas du département anim), je trouve l’animation sur le projet inégal, mais il faut avouer que certains plans sont de belles réussites. Le plan du dessus est le tout dernier d’une séquence qui monte en puissance ou Félicie, malgré n’avoir plus aucune chance de devenir ballerine enfile ses chaussons, commence quelques pas puis fait des gestes de plus en plus complexe pour finir sur une pirouette plein plan le regard vers le dos de la caméra (Paris) avec deux sentiments en même temps sur son visage. Un sentiment clair, c’est bien pour du cartoon. Mais ce qui rend un personnage en 3d humain c’est en grande partie la manière dont il exprime (ou tente de cacher) l’ambivalence de ses sentiments. Ce sont des attitudes qu’on retrouve fréquemment dans le film. Disney excellait dans sa capacité à le faire en 2d et peu de films y arrivent vraiment. Je trouve que Ballerina s’en sort très bien là-dedans.</p>
<h3>Conclusion</h3>
<p>Il est bien évident que tout ceci est un effort collectif, nous n’étions jamais seuls à faire des choix et c’est sûrement ce qui a permis au projet d’aboutir. Je n’ai pas nommé les personnes, mais il me semble important de rappeler que c’est pourtant avec de l’humain que tout se joue, du haut de la hiérarchie jusqu’au graphiste parfois derrière des tableaux à vérifier que l’intégralité des retakes des plans ont été faites (et pour qui je peux vous garantir que ce n’est pas la tasse de café). Si personne ne le veut, le film ne sort pas, c’est aussi simple que ça.</p>
<p>Je ne parle pas d’aller se tailler les veines à faire des heures supplémentaires pendants des mois pour le plaisir de montrer qu’on souffre à la tâche mais au contraire d’une volonté farouche que tout ce passe pour le mieux à tous les niveaux et sur la longueur. Je n’ai dû faire qu’une vingtaine d’heures supplémentaires (pour finir et peaufiner le builder si ne me souvient bien car « Pas d’builder : Pas d’projet… »). Le fait de voir qu’il y a une volonté générale de réussite du projet et de bienveillance mutuel (OK je m’enflamme peut-être un peu sur le dernier mais quand même c’est l’idée) pousse les gens à fournir l’effort supplémentaire nécessaire à la sortie d’images propre et livrées dans les temps. La peur de se faire virer n’est pas déterminante, chacun sait qu’une fois le projet fini on passe (presque tous) à la porte. À partir de là, ce qui compte pour chacun c’est de faire un travail dont il est fier. À quoi bon livrer des images, sensé divertir les gens qui les regarde, faites dans la tension et dont tous le monde garde un gout amer ? À mes yeux, et malgré un double démarrage difficile, Ballerina semble également avoir réussi sur ce terrain et pour un premier long-métrage, c’est la classe ! :laClasse:</p>
<p>À bientôt !</p>
<p>Dorian</p>
<p style="text-align: center;">:marioCours:</p>Faire un override pour supprimer un shader dans Guerillaurn:md5:1826ba5e2f7dc3130d6ad2a0ff0fb4022017-06-04T23:11:00+02:002017-06-05T00:47:40+02:00NarannScript et codeguerillaluaoverridescript<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_tn.png" style="float: left; margin: 0 1em 1em 0;" />Si vous assignez un shader (de volume par exemple) il peut être utile de pouvoir le désassigner, plus loin dans le rendergraph.</p>
<p>Il me semble que c’était possible en 1.3 mais que ce ne soit plus possible en 1.4. :reflexionIntense:</p>
<p>Je vous propose donc une petite méthode pour désassigner un shader. :sauteJoie:</p> <p>Mais expliquons un peu le souci. :gne2:</p>
<p>Faites une petite scène « sphère et plan » puis faite un override d’assignation de shader mais videz le nom du shader :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_003.png" style="margin: 0 auto; display: table;" /></p>
<p>Puis connectez l’override à la branche principale. Comme vous pouvez le constater, l’assignation reste faite en bout de graph :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_001.png" style="margin: 0 auto; display: table;" /></p>
<p style="text-align: center;"><em>Bon sang, quand j’override par « rien du tout » Guerilla garde la valeur de l’override original. </em> :gne:</p>
<p>Et Guerilla semble sciemment considérer que vous avez fais une erreur :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_002.png" style="margin: 0 auto; display: table;" /></p>
<p>On va résoudre ça. :enerve: Supprimez l’assignation puis créez un nœud de Script (Ctrl+Espace, « scri », Entrée):</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_004.png" style="margin: 0 auto; display: table;" /></p>
<p>Connectez le dans le graph à la place de votre assignation précédente :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_005.png" style="margin: 0 auto; display: table;" /></p>
<p>Regardez ses attributs. Le script arrive avec un petit exemple pour illustrer son comportement. Mais nous n’allons pas en avoir besoin. Supprimez les deux propriétés (en cliquant sur les croix en haut à droite), puis cliques sur le bouton « Edit »:</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_006.png" style="margin: 0 auto; display: table;" /></p>
<p>Sans vous soucier des commentaires regardez ce que vous avez :</p>
<pre>
<code>if Input then
Output = duplicate (Input)
Output["variable."..ColorName] = CustomShaderColor
end
</code></pre>
<p>Je vous explique rapidement : Ce script duplique la table (c’est la <a href="http://lua-users.org/wiki/TablesTutorial" hreflang="en">structure de données</a> en <a href="https://fr.wikipedia.org/wiki/Lua" hreflang="fr">lua</a>) <em>Input</em> en <em>Output</em>, modifie l’entrée « variable.DiffuseColor » (car il récupère la valeur de l’attribut « ColorName » que nous avons supprimé précédemment) pour lui mettre la valeur de l’attribut « CustomShaderColor » que nous avons, lui aussi, supprimé (c’était la couleur rouge). :tuComprendRien:</p>
<p>On va utiliser ce mécanisme pour venir supprimer l’assignation du shader. Mais reste la question : Quel est le nom de l’attribut à modifier ? :reflexionIntense:</p>
<p>Pour cela rien de plus simple : Ouvrez la console (menu « View|Show/Hide console (Alt+2) »), sélectionnez votre sphère puis faites Shift+D. Ceci va afficher, dans la console, la liste de tous les attributs ainsi que leur valeur telles qu’elles seraient envoyées au rendu. Cherchez « shader »:</p>
<pre>
<code>shade.shadebothsides: 0
shade.textureapproximation: "glossy"
shade.texturemaxsize: 0
shader.displacement: ""
shader.surface: "Surface"
shader.volume: ""
shape.cached: 1
shape.combineprocedural: 0
shape.compression: 0</code></pre>
<p>Vous l’avez ! « shader.surface » (ou « shader.volume » ou même « shader.displacement » si vous souhaitez supprimer le shader de displacement).</p>
<p>Modifiez le script pour supprimer l’assignation :</p>
<pre>
<code>if Input then
Output = duplicate (Input)
Output["shader.surface"] = ""
end
</code></pre>
<p>Sauvez Ctrl+S puis vérifiez par vous même :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_06_14_supprimer_override_guerilla/supprimer_override_007.png" style="margin: 0 auto; display: table;" /></p>
<p>Comme vous pouvez le voir, le shader est désassigné. :laClasse:</p>
<p>En espérant que ça en débloque certains.</p>
<p>À bientôt !</p>
<p>Dorian</p>
<p style="text-align: center;">:marioCours:</p>Personnaliser ses AOV dans Guerillaurn:md5:c4b7ef687147cc53a32e497dc6c447462017-05-28T18:20:00+02:002017-06-01T10:56:11+02:00NarannInfographie 3D - Boulotaovguerillarendu<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_tn.png" style="float: left; margin: 0 1em 1em 0;" />Ça fait un moment que je n’ai pas fais de tutoriel. En voici un tout petit principalement à destination des étudiants utilisant ou voulant (les biens inspirés :hehe: ) utiliser Guerilla pour leur projet de fin d’année.</p>
<p>L’idée étant de faire un tuto pour sortir un AOV personnalisé assignant une couleur suivant les objets. Nous allons ici utiliser de simples couleurs (rouge et bleu dans le cas d’un masque) mais sachez que vous pouvez remplacer cette couleur par une texture, de l’occlusion ou pleins d’autres choses.</p>
<p>En avant ! :enerve:</p> <p>Ouvrez Guerilla. La première chose à faire c’est une petite scène de test. Un plan, une sphère c’est parfait :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_001.png" style="margin: 0 auto; display: table;" /></p>
<p style="text-align: center;">Avec ça, Votre projet de fin d’étude semble bien partis. Encore un peu de boulot et Pixar pleurera devant vos rendus. :gniarkgniark:</p>
<p>Ouvrez le <em>rendergraph</em> par défaut, glissez-déposer la sphère et le plan depuis la <em>Node List</em> pour créer un <em>path</em> puis créez un <em>material override</em> (Ctrl+Espace dans le <em>rendergraph</em>, tapez « mat », puis Entrer). Enfin connectez-moi tout ça sous cette forme :</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_002.png" style="margin: 0 auto; display: table;" /></p>
<p>Je traduis le graph ci-dessus : L’objet <em>Sphere</em> va se faire <em>overrider</em> un paramètre par le nœud <em>MaterialOverride</em>. Cette opération est ensuite fusionnée aux modifications de la branche principale via un nœud union. Il en va de même pour l’objet <em>Plane</em>. :zinzin:</p>
<p>Ensuite, on clique sur <em>MaterialOverride</em>, on tape le nom de l’<em>override</em> que l’on souhaite créer. Ici (par exemple) « MyMask1 » de type <em>Color</em>. On assigne la couleur rouge. On fait de même pour le <em>MaterialOverride</em> du <em>Plane</em> mais de couleur bleu :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_003.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/.guerilla_custom_aov_003_m.png" style="margin: 0 auto; display: table;" /></a></p>
<p>Information intéressante à cette étape : Si vous cliquez sur le petit « M » à droite, vous pourrez sélectionner un sous-shader, notamment <em>Texture</em>, <em>Occlusion</em> et <a href="http://guerillarender.com/doc/1.4/Library_Attributes_Cloud.html" hreflang="en">Cloud</a>. Si vous êtes joueur et que vous souhaitez rendre des attributs présents dans vos alembic vous pouvez regarder du côté de <em>PrimVar</em> :hehe: ).</p>
<p>Maintenant nous avons des <em>overrides</em> sur des objets. Il faut pouvoir les rendre ! :grenadelauncher:</p>
<p>Créez un nouvel AOV (Cliquez sur le + à cote de l’AOV de <em>Beauty</em>). Renommez-le comme vous le voulez (je l’ai appelé « MyMask1 » mais en fait ce n’est pas important ici):</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_004.png" style="margin: 0 auto; display: table;" /></p>
<p>Cliquez dessus puis, dans le champ <em>Shader Color</em>, mettez « MyMask1 » (c’est là qu’il faut mettre le même nom que les noms des <em>overrides</em> créés précédemment):</p>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_005.png" style="margin: 0 auto; display: table;" /></p>
<p>Faites un rendu (Ctrl+R) puis sélectionnez l’AOV « MyMask1 » (dans le menu déroulant en bas à gauche de la <em>RenderView</em>) :</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov_006.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/.guerilla_custom_aov_006_m.png" style="margin: 0 auto; display: table;" /></a></p>
<p>Et une petite image finale pour avoir une vision d’ensemble. :popcorn:</p>
<p><a class="media-link" href="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/guerilla_custom_aov.png"><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_27_aov_personalise_guerilla/.guerilla_custom_aov_m.png" style="margin: 0 auto; display: table;" /></a></p>
<p>En espérant que ça vous mette le pied à l’étrier, n’hésitez pas à creuser un peu et à expérimenter. :joue:</p>
<p>À bientôt!</p>
<p>Dorian</p>
<p style="text-align: center;">:marioCours:</p>Lister les channels d'un fichier OpenVDB avec Guerillaurn:md5:8b3610fc9eca64d91706d89c8a81839c2017-05-20T18:56:00+02:002017-05-25T12:31:27+02:00NarannInfographie 3D - Boulotchannelsguerillaopenvdb<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_13_openvdb_channel_guerilla/2017_05_13_openvdb_channel_guerilla_tn.png" style="float: left; margin: 0 1em 1em 0;" />Si vous utilisez Guerilla et que vous devez rendre des fichiers OpenVDB, vous devez connaitre les noms des <em>channels</em> afin de les utiliser dans vos shaders de volumétrique.</p>
<p>Il y a plusieurs façons d’introspecter un fichier OpenVDB (plugin Maya, ligne de commande officielle, etc.) mais toute ne sont pas forcement disponible sur votre machine.</p>
<p>Je vous propose une petite méthode qui s’appuie sur les informations que Guerilla donne quand il rend. :aupoil: )</p> <ul>
<li>Ouvrez Guerilla</li>
<li>Importez votre fichier .vdb en référence (<em>Create</em>/<em>Create Reference</em>)</li>
<li>Sélectionnez le nœud <em>Preferences</em></li>
<li>Dépliez <em>Rendering</em>/<em>Logs & Diagnostics</em></li>
<li>Mettez <em>Verbosity</em> à « Diagnostics »</li>
<li>Activez <em>Diagnostics Shapes</em></li>
<li>Ouvrez la console (<em>View</em>/<em>Show/Hide console</em> ou Alt+2)</li>
<li>Videz le contenu du log via bouton droit de souris <em>Clear</em></li>
<li>Faites un rendu (Ctrl+R)</li>
</ul>
<p><img alt="" class="media" src="https://www.fevrierdorian.com/blog/public/billets/2017_05_13_openvdb_channel_guerilla/2017_05_13_openvdb_channel_guerilla_001.png" style="margin: 0 auto; display: table;" /></p>
<p>Vous devriez obtenir un retour de la forme suivante:</p>
<pre>
<code>Starting render: 1 jobs
05/12/2017 15:26:38 SHAP DIA: loaded shape 'C:\Users\narann\Downloads\fire.vdb\fire.vdb' 'fire.RenderGeometry'
05/12/2017 15:26:38 SHAP DIA: Voxel shape
05/12/2017 15:26:38 SHAP DIA: density - 1 float(s) - 4458790 voxels
05/12/2017 15:26:38 SHAP DIA: temperature - 1 float(s) - 4139727 voxels
Render RenderPass RenderPass: 1.08s
Total render: 1.08s</code></pre>
<p>On peut voir que ce .vdb (disponible <a href="http://www.openvdb.org/download/" hreflang="en">sur le site officiel</a>) contient deux <em>channels</em>: <em>density</em> et <em>temperature</em>.</p>
<p>Si vous relancez le rendu, vous remarquerez que ça ne réaffichera pas. C’est dû au fait que le cache Guerilla ne recharge pas ce qu’il a déjà en mémoire (pas bête la guêpe :siffle: ).</p>
<p>Il faut donc faire un <em>Clear cache</em> avant de relancer le rendu.</p>
<p>A bientôt!</p>
<p>Dorian</p>
<p style="text-align: center;">:marioCours:</p>