Dorian Fevrier's blog - Mot-clé - lightJe 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>