Activer le rapport

Pour activer le rapport de statistique des lights, il faut aller dans Preferences, Rendering, Logs & Diagnostics, mettre Verbosity à « Diagnostics » et cocher Render Statistics :

Explication détaillée

À la fin de votre rendu, vous aurez quelque chose qui ressemble à ça :

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

« Pas mal, non ? C’est français. »

Pas de panique, on va commenter tout ça ! :hehe:

Comme vous vous en doutez, nSmp est le nombre de samples envoyés sur la light. Je ne m’éternise pas. :redface:

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:

TL est le total d’intensité lumineuse (Total Luma) émis par la lampe sans tenir compte de l’occlusion (c.à.d, sans prendre en compte le test d’ombre).

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 par ici).

Quand un rayon arrive sur une surface, le moteur calcul l’illumination de ce que nous allons appeler le shading point (en rouge sur le schéma ci-dessous). Pour cela il va utiliser la normale de la surface du shading point et en extraire un hémisphère (la normale étant la direction du pôle) :

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 shading point, light 1) ainsi que celles « dos au shading point » (c.à.d, qui montrent leurs fesses au shading point, light 3) car elles ne contribueront pas à l’illumination du shading point.

Reste les autres lights, celles qui sont face au shading point : Comment déterminer la light ayant la meilleure contribution ? :petrus:

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.

On pourrait lancer des rayons au hasard sur toutes les lights, mais en pratique, seules quelques-unes contribueraient vraiment à l’illumination du shading point. 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 shading point.

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 shading point, 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 shading point si elle est visible par ce dernier.

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 shading point.

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 shading point, 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 shading point.

Mais l’effet de bord est évident : Si vous avez une light derrière un mur, mais en direction de votre shading point, le moteur privilégiera cette lampe.

C’est ça le 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).

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:

Une fois que vous avez compris ça, vous êtes en mesure d’expliquer la relation entre TL% et OL%.

Première chose : TL% 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 TL% de toutes les lights est 100 % (vous pouvez faire le calcul :siffle: ).

Et enfin : OL% 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.

On a donc OL% / TL% = Ratio d’efficacité d’une light. Exemple dans notre cas sur la light la moins efficace :

>>> 4.0/5.0
0.8  # 80 %

Et cela correspond bien à notre valeur de Eff% (moins les imprécisions). :youplaBoum:

Vous avez donc 20 % de perte (tests de visibilité échoué) pour cette light, sur votre image.

En pratique, la valeur TL n’est pas d’une grande aide, ce sont les valeurs TL%, OL% et Eff% qui sont importantes. Un OL% à 0.0 indique que la light n’amène pas grand-chose à l’image :

  • Si ce OL% à 0.0 est combiné à un TL% élevé, ça veut dire que le path tracer se fait avoir.
  • Si le TL% est également proche de 0.0, l’Eff% 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.

Relation entre separate sampling et shared sampling

Comme vous avez pu le remarquer sur le log d’exemple, les lights sont divisées en deux groupes :

  • Separate lights
  • Shared lights

Sauf quelques exceptions (que nous verrons plus loin), une light est en shared sampling 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 shading point. C’est-à-dire que pour chaque shading point on fera une estimation de la contribution de chaque light du paquet et on en choisira une pour tester sa visibilité au shading point.

Guerilla permet de marquer une light comme separate sampling. 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 shared lights). 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 separate sampling ne soit coché que sur les lights qui apportent quasi systématiquement quelque chose à l’image.

C’est la raison pour laquelle les env lights ont l’attribut separate sampling par défaut.

Le test du mur

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:

Voici la scène :

Un plan, une sphère, deux lights positionnées à 180 l’une de l’autre et un mur sur celle de droite :

Le rendu :

Clairement la light derrière le mur ne contribue pas au rendu, et les statistiques le confirme :

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

On remarque immédiatement l’Eff% de la light derrière le mur à 0. Cette light est inefficace et peut être retirée du rendu sans risque. :bravo:

La raison pour laquelle le TL% 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 shading points 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.

Regardons les temps de rendu. Ma RenderPass 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.

Allons encore plus loin et regardons les light stats de ce « lighting parfait » :

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

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 shading point 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.

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é.

Notez aussi le nombre total de samples lancé avant de converger : Un tiers de moins. Une information confirmée par l’AOV de heat.

Rendu avec les deux lights :

Rendu avec une seule light, à gauche :

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:

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.

Conclusion

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 Eff% à 0 peut être caché sans aucun risque pour vos rendus. :sauteJoie:

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:

À très bientôt !

:marioCours: