Notes concernant Guerilla 2

Adaptive sampling

Avant d’aller plus loin, vous devez prendre connaissance de la documentation :

Guerilla note RenderPass adaptative sampling

Utilisez toujours une AOV de Heat et Confidence pour vérifier comment votre sampling se comporte.

AOV de Heat

Pour une description de cette AOV, nous allons considérer les valeurs d’adaptive sampling 256/0.03/16.

Guerilla note adaptative heat aov

Rouge

Guerilla note adaptative heat aov red

Ce sont les pixels atteignant le nombre maximum de samples (c.à.d. 256). Servez-vous-en pour identifier les zones de votre rendu qui ne peuvent atteindre le seuil voulu (threshold), vous pourriez avoir du grain. À vous de décider si une augmentation du nombre de sample est nécessaire.

Vert

Guerilla note adaptative heat aov green

Ce sont les valeurs de sampling minimum et maximum normalisées (de 0.0 à 1.0) :

Cela permet de visualiser la distribution des samples dans l’image.

Bleu

Guerilla note adaptative heat aov picker

Ce channel vous permet de déterminer le nombre exact (absolu) de sample projeté sur un pixel donné (169 sur l’image ci-dessus).

AOV de Confidence

Guerilla note adaptative confidence

Cet AOV de « confiance » affiche la quantité de bruit estimé par le moteur :

Shadow terminator

L’attribut Shadow terminator est dans Attributes, Raytracing et est à 0 par défaut (désactivé).

Une valeur par défaut comprise entre 0.25 et 0.5 élimine la plupart des artéfacts.

Ne montez pas trop cette valeur au risque d’avoir certains sommets qui « attrapent » la lumière (e.g. dans un trou subdivisé).

Les caustiques sont activés par défaut

Les caustiques sont les rayons suivant le chemin : Camera -> Rebond diffus -> Surface glossy ou spéculaire.

Par défaut, Guerilla 2 ne prends pas en compte les caustiques lors du rendu, mais la définition par défaut de ce qui est considéré comme caustique est défini dans Sharp Caustics :

Sur une RenderPass, dans la section Caustics, Caustics Types est sur Sharp Caustics par défaut, ce qui veut dire que les rayons suivants le chemin Camera -> Rebond diffus -> Spéculaire ne seront pas rendus.

C’est une bonne chose, car ce chemin est la source de rayons à forte quantité d’énergie qui entraine un « mouchetage » de vos rendus (fireflies).

En revanche, cela implique que les caustiques glossy (c.à.d. les rayons suivants le chemin : Camera -> Rebond diffus -> Glossy) seront tracés, ce qui peut amener un subtil mouchetage dans les rendus aux conditions d’éclairage difficiles.

Il n’est pas rare que la contribution de ces caustiques n’apporte rien d’autre à l’image qu’un subtil grain. Si c’est le cas, mettez Caustics Type à Glossy Caustics ou All Caustics pour les supprimer.

Guerilla note RenderPass caustics types

Supprimez la contribution des rayons secondaires de Velvet

Le Surface2 est composé d’une couche Velvet permettant de simuler l’illumination des micros-fibres (e.g. pour les vêtements). Par définition, ce calcul d’illumination dépend de la position de la caméra.

Le problème est que la contribution du velvet est utilisé pour les rayons secondaire, même si vous mettez Caustics Type sur All Caustics. Suivant votre éclairage et vos matériaux, vous risquez de voir apparaitre du bruit dans l’illumination indirecte (notamment le SSS) et les reflets, le velvet propageant les samples de haute intensité.

La plupart du temps, ce que vous souhaitez obtenir est un effet visuel subtile sur vos vêtements, qui n’impacte pas les rayons secondaires.

Mettez VelvetDepth à 0 de sorte que le velvet ne soit visible que depuis les rayons de caméra.

Avant d’utiliser la couche Velvet, je vous encourage à essayer d’utiliser Diffuse Roughness combiné à une augmentation légère augmentation de la Diffuse Color. Suivant l’effet que vous souhaitez obtenir, ces paramètres peuvent se révéler suffisant, tout en évitant d’augmenter la complexité du shader.

Diffuse bounces et Light Max

Dans la liste suivante, j’utilise la notation Diffuse bounces/Light Max, donc 2/1 veut dire 2 Diffuse bounces et Light Max à 1.

L’utilisation de Light Max combiné à celle des Portals augmente les temps de rendu. Ne combinez pas les deux.

Light Max est couteux, ne l’utilisez pas si les lumières sont suffisamment larges pour que les rayons puissent les trouver facilement. Réciproquement, privilégiez l’utilisation de quelques lumières larges plutôt que beaucoup de petites.

Du point de vue de la variance, il est toujours plus efficace d’utiliser une source large de lumière plutôt que plusieurs petites. Si vos lumières ne sont pas directement visibles depuis la caméra, désactivez-les et créez-en une seule, les englobants et ayant la même couleur et intensité. Vous pouvez ensuite alterner entre le groupe des petites lumières et ce « proxy » qui les représente. Dans le cas d’un décor, proposer un proxy à des groupes de petites lumière permet au graphiste de gagner du temps lors de l’éclairage au plan.

Faire du lookdev avec de l’adaptatif

Je suggère de toujours faire deux types de tournettes de lookdev :

Si possible, évitez d’envoyer un lookdev en validation si vous n’avez aucune idée de la complexité de son shader.

Les poils

Préférez beaucoup de poils opaques plutôt que peu de poils transparents. Les poils transparents rendent leurs ombres difficiles à anticiper une fois dans les plans, car vous atteignez rapidement le Max Depth du moteur.

Prune VS Visibility

Quand vous êtes au plan, préférez l’utilisation de l’attribut Pruned pour supprimer les objets du rendu.

Dans une hiérarchie, l’attribut Hidden peut être surchargé au niveau d’un enfant. Pruned stop la traversée de sa hiérarchie immédiatement.

Exemple, dans la hiérarchie suivante :

Root
 '-> Enfant

Root peut avoir Hidden à True, mais Enfant peut avoir Hidden à False surchargé dans un RenderGraph. Si c’est le cas, Enfant sera visible au rendu.

Cela permet au RenderGraph de réafficher n’importe quel nœud qui a été mis en Hidden par un RenderGraph précédent.

À l’inverse, si Root à Pruned à True, la traversée de la hiérarchie s’arrête immédiatement, et Enfant ne pourra jamais être visible et n’est pas envoyé au moteur.

La documentation est ici.

Sur des grosses hiérarchies, Pruner certains nœuds permet d’optimiser le temps entre le moment ou on clique sur Render et le démarrage du rendu.

Faire du débogage rapidement

Ceci désactive toutes les subdivisions et diminue les appels aux textures en prenant la plus petite mipmap possible.

La génération automatique des textures

Par défaut, Guerilla génère des fichiers .tex dans un dossier .guerilla pour chaque texture qu’il trouve. Ceci peut devenir un problème quand votre pipeline grossi.

Pour désactiver cela, allez dans Preferences, Texture Manager, et désactivez Auto Build Texture.

La documentation est ici.

Les logs

Allez dans Preferences, Rendering, Logs & Diagnostics puis passez la Verbosity à Diagnostics :

Guerilla note log activer les diagnostics

La documentation est ici.

La distribution des samples

Guerilla affiche des informations permettant d’évaluer rapidement l’usage de l’adaptative dans vos rendus :

Silver:
                  Primary rays : 695M
         Average samples/pixel : 753.840464
          Median samples/pixel : 916.480000
                       [0-204] : 12.4% 114K/922K
                     [204-409] : 8.1% 74.9K/922K
                     [409-614] : 10.2% 93.6K/922K
                     [614-819] : 14.1% 131K/922K
                    [819-1024] : 55.2% 510K/922K
               Shot rays/batch : 497.398 2.67G/5.37M
             Shadow rays/batch : 918.959 4.93G/5.37M

Ici on voit que 55 % des pixels ont demandé entre 819 et 1024 samples. Avant même de regarder une AOV dédiée, vous avez une idée de la distribution des samples.

On peut illustrer la chose avec un graphique. En prenant la valeur de samples du milieu (102 pour [0-204], 306 pour [204-409], etc.) et en mettant ces chiffres dans un numbers.plot :

102 12.4
306 8.1
511 10.2
716 14.1
921 55.2

Puis avec cette commande :

$ gnuplot -e "set terminal png; set style data linespoints; set border linewidth 1.5; set xlabel 'Samples par pixel'; set ylabel 'Pourcentage des pixels';set xrange [0:1024]; set yrange [0:100]; plot 'numbers.plot';" > out.png

On obtient ce graphique approximatif qui illustre cette distribution des samples :

Guerilla note log distribution des samples graph plot

Encore une fois, on remarque qu’ici, les pixels coûteux en samples représentent la moitié des pixels de l’image.

Lister les attributs de shape

La case Diagnostic Shape permet de lister les attributes de chaque shape envoyé au moteur. Pour un fichier Alembic d’animation, on aurait :

02/25/2021 19:50:17 385M [08] SHAP DIA: loaded shape '/chemin/vers/mon/fichier.abc' '/node/nodeShape.RenderGeometry'
02/25/2021 19:50:17 385M [08] SHAP DIA: P float3[286] min=(-50.629753,3.517493,4.852751) max=(-50.393837,3.630370,5.088417)
02/25/2021 19:50:17 385M [08] SHAP DIA: P2 float3[286] min=(-50.424358,3.517493,4.852391) max=(-50.188423,3.630370,5.088114)
02/25/2021 19:50:17 385M [08] SHAP DIA: N float3[286] min=(-0.971818,-0.996817,-0.964958) max=(0.928156,0.999970,0.969747)
02/25/2021 19:50:17 385M [08] SHAP DIA: st float2[286] min=(0.034514,-1.971024) max=(0.973398,-1.034953)
02/25/2021 19:50:17 385M [08] SHAP DIA: dP avg=(0.205598,0.000000,-0.000384) min=(0.204475,0.000000,-0.001563) max=(0.206905,0.000000,0.000866)

Notez que cela fonctionne pour les particules et les channels des fichiers OpenVDB.

Dans le cas d’un système de particule exporté depuis Maya on obtient :

02/25/2021 19:51:04 204M [03] SHAP DIA: loaded shape '/chemin/vers/mon/fichier.abc' '/nParticle1/nParticleShape1.RenderGeometry'
02/25/2021 19:51:04 204M [03] SHAP DIA: P float3[33] min=(-0.592114,-0.050974,-0.386162) max=(0.619097,0.635682,0.457532)
02/25/2021 19:51:04 204M [03] SHAP DIA: P2 float3[33] min=(-0.592114,-0.050974,-0.386162) max=(0.619097,0.635682,0.457532)
02/25/2021 19:51:04 204M [03] SHAP DIA: float12 float1[33] min=(0.000000) max=(32.000000)
02/25/2021 19:51:04 204M [03] SHAP DIA: color2 float3[33] min=(-2.304702,-1.120984,-2.014977) max=(2.083903,2.404513,1.995705)
02/25/2021 19:51:04 204M [03] SHAP DIA: dP avg=(0.000000,0.000000,0.000000) min=(0.000000,0.000000,0.000000) max=(0.000000,0.000000,0.000000)

Il est intéressant de noter que la taille du tableau est 33, ce qui veut dire qu’il y a 33 particules. Si on le compare aux valeurs de min et max de float12, on peut en déduire que float12 correspond aux valeurs d’id des particules

Il peut arriver que ces lignes affichent no deform motion blur. Dans ce cas, P2 et dP ne sont pas présents. Cela veut dire qu’il n’y a pas de déformation de shape dans l’intervalle échantillonné, mais ça ne veut pas dire qu’il n’y en a pas ailleurs dans le fichier.

Ces messages ne sont affichés que lors de la mise de la shape en cache. Cela veut dire qu’il faut vider le cache pour les afficher de nouveau :

Guerilla clear cache button

Les portails

Les portails restent une option intéressante, mais leur coût en temps de rendu augmente avec leur nombre.

Voici une scène très simple composée d’une boite fermée avec une ouverture sur le côté et un SkyLight :

Guerilla note test portal scene

Guerilla note test portal render

Paramètres :

Samples10 000
Adaptive Threshold0.1
Adaptive Min Samples16
Sampling ModeProgressive
Résolution1280 × 720

Cette scène très simple a été rendue dans différente configurations. D’abords sans portails, puis un portail :

Guerilla note test portal 1

Puis 9 :

Guerilla note test portal 9

Puis 18 :

Guerilla note test portal 18

Je cherchais à déterminer si l’utilisation de plusieurs portails avait un impact sur le temps de rendu.

Temps de rendu Configuration
4m57sSans portails
1m40s1 portail
1m57s9 portails
2m16s18 portails

En mettant ces chiffres dans un numbers.plot :

0 297
1 100
9 117
18 136

Puis avec cette commande :

$ gnuplot -e "set terminal png; set style data linespoints; set xlabel 'Nombre de portails'; set ylabel 'Temps (sec)';set xrange [-2:20]; set yrange [90:305]; plot 'numbers.plot';" > out.png

On obtient ce magnifique graphique :

Guerilla note test portal temps de rendu graph plot

On a donc un gain important au premier portail (l’éclairage étant prédisposé à leur utilisation) qui diminue de façon linéaire. Il est donc important de ne pas en abuser.

Évaluation des procédurales

Les procédurales mises dans les RenderGraphs ont un comportement particulier qu’il est nécessaire de comprendre si on souhaite s’éviter de nombreuses confusions, notamment sur ce qui a trait à « l’Evaluation Order ». Pour rappel l’évaluation d’un nœud dans les RenderGraphs se fait grossièrement de la sorte :

Ce rappel étant fait, prenons un exemple et imaginons la hiérarchie suivante :

Root           (Transform)
'- sol         (Transform)
   '- solShape (Mesh)

Si vous souhaitez que solShape soit le scalp de votre procédurale, votre RenderGraph sera composé d’un nœud de type Path pointant vers solShape connecté à l’entrée scalp d’un nœud de type Procedural (nommé myProc sur le schéma ci-dessous) dont la sortie est connectée au reste du RenderGraph :

                 .------------.
                 | Procedural |
                 |   myProc   |
.----------.     |            |
|   Path   |     O Parent     |
| solShape |     O hairs      |
|          |     O instances  |
|   Output O-----O scalp      |
'----------'     |     Output O--.
                 '------------'   \

Ce qu’il faut comprendre ici c’est qu’à l’inverse du fonctionnement habituel d’un RenderGraph, les nœuds vers lesquelles pointe le nœud de type Path (ici, solShape) ne sont pas directement passés à la procédurale. Au lieu de ça, ces nœuds sont mis dans un set avec le nom/asset_id de la procédurale. Ici nous aurions un set scalp:myProc dans lequel sera mis solShape.

Ce mécanisme de set est utilisé pour tout ce qui est connecté aux entrées de la procédurale :

Plusieurs primitives du scene graph peuvent donc être dans le set scalp:myProc (e.g. si le nœud de Path est une expression régulière).

Ce set est visible en haut à gauche quand vous sélectionnez un nœud passant dans le graph (ici, solShape) :

Guerilla note test link set

Voilà pour la première partie de l’évaluation : Les nœuds en entrées de la procédurale sont assignés un set de sorte à pouvoir être récupéré rapidement plus tard.

La seconde partie de l’évaluation est plus simple : Guerilla va chercher tous les nœuds de procédurale connectés, de quelque façon que ce soit, à la sortie (l’Output) d’un RenderGraph. Chaque procédurale ainsi trouvée est ajoutée au scene graph (c.à.d, mis dans la scène de rendu) soit :

À ce stade, le moteur contient des nœuds de procédurale avec les informations pour générer leur contenu, mais rien n’est encore généré. C’est la raison pour laquelle vous ne pouvez pas instancier le contenu d’une procédurale (e.g. un buisson procédural instancié plusieurs fois). Vous pouvez instancier un nœud de procédurale (e.g. en utilisant une expression régulière dans le Path connecté à son attribut Parent), mais pas son contenu. Ce n’est qu’une fois que le rendu commence que le contenu de la procédurale est généré.

La boite englobante utilisée par défaut est celle du (ou des) scalp(s), ce qui n’est pas toujours optimal (vous pouvez désactiver l’attribut Load On Demand de la procédurale pour y remédier).

Isolation des procédurales depuis un RenderGraph de lookdev préfixé

Vous utilisez peut-être l’attribut User Prefix de vos RenderGraph pour assigner vos lookdev. Imaginons une scène comme celle-ci :

toto_001:Root        (Transform)
 '- toto_001:Mesh    (Transform)
   '- toto_001:Scalp (Primitive)
toto_002:Root        (Transform)
 '- toto_002:Mesh    (Transform)
   '- toto_002:Scalp (Primitive)

Un RenderGraph avec un User Prefix à toto_ appliquera son lookdev au contenu de toto_001:Root et toto_002:Root.

Cela peut poser des problèmes avec l’assignation des procédurales. Imaginons le graph d’assignation suivant :

Guerilla RenderGraph d’assignation des procédurales au lookdev

Description :

Le résultat de l’évaluation est visible dans le Live SceneGraph :

Guerilla live SceneGraph avec procédurales sous chaque Root

Toutefois, au rendu moment du rendu, vous constaterez que chaque procédurale génère ses poils sur deux scalps (toto_001:Scalp et toto_002:Scalp) :

04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: computing hair implantation on scalp toto_001:Root|toto_001:Mesh|toto_001:Scalp..
04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: computing hair implantation on scalp toto_002:Root|toto_002:Mesh|toto_002:Scalp..
04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: generating hairs for toto_001:Root|toto_001:Mesh|toto_001:Scalp..
04/16/2022 10:43:46 313M [03] PROC LOG: toto_001:Root|toto_000:Fur: generating hairs for toto_002:Root|toto_002:Mesh|toto_002:Scalp..
...
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: computing hair implantation on scalp toto_001:Root|toto_001:Mesh|toto_001:Scalp..
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: computing hair implantation on scalp toto_002:Root|toto_002:Mesh|toto_002:Scalp..
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: generating hairs for toto_001:Root|toto_001:Mesh|toto_001:Scalp..
04/16/2022 10:43:46 315M [06] PROC LOG: toto_002:Root|toto_000:Fur: generating hairs for toto_002:Root|toto_002:Mesh|toto_002:Scalp..

Vous avez donc 4 systèmes de poils, générés les un sur les autres. Vous pouvez facilement le constater en ajoutant de la transparence aux poils et en visualisant leur alpha, chaque poil est en fait doublé : Avec une opacité à 0.25, votre poil aura une opacité à 0.4375, car il y a en fait deux poils.

Et si vous ajoutez une troisième hiérarchie toto_003:Root, vous aurez 9 systèmes de poils (3×3), et cela continue de façon exponentielle.

Description du comportement de l’envoi des procédurales au moteur

Pour comprendre pourquoi nous avons ce comportement, il faut comprendre comment les procédurales sont envoyées au moteur.

Au moment du rendu, Guerilla passe la procédurale au moteur, non pas avec des liens directs vers les surfaces de scalps à utiliser, mais avec des noms de sets. Ces sets sont supposés contenir les shapes de scalps.

MaProcédurale[scalp="set_de_scalps", (autres paramètres)]

"set_de_scalps"=Set[toto_001:Root|toto_001:Mesh|toto_001:Scalp,
                    toto_002:Root|toto_002:Mesh|toto_002:Scalp]

Une façon de s’en rendre compte consiste à sélectionner une des procédurales dans la vue Live SceneGraph et de faire Shift+D. Ce raccourci liste les attributs envoyés au moteur, ainsi que leur valeur respective. Dans notre cas, on peut y trouver :

...
proceduraluser.hairsset: "hairs:10_lookdev_test|test_000:Fur_$(identifier.assetid)"
proceduraluser.instances: {}
proceduraluser.instancesset: "instances:10_lookdev_test|test_000:Fur_$(identifier.assetid)"
proceduraluser.interpolationmethod: "Shepard"
proceduraluser.scalp: {}
proceduraluser.scalpset: "scalp:10_lookdev_test|test_000:Fur_$(identifier.assetid)"
...

On voit clairement que les scalps utilisés sont en fait issus d’un set, généré au moment du rendu : scalp:10_lookdev_test|test_000:Fur_$(identifier.assetid). Notez la présence de l’expression $(identifier.assetid) dont la valeur est simplement celle de l’attribut Asset Id.

Guerilla Attribut Asset Id vide sous toto_001:Root

Dans notre cas, comme ni toto_001:Root, ni toto_002:Root n’ont de valeur d’Asset Id, le nom du set de scalps se retrouve être le même pour les deux : scalp:10_lookdev_test|test_000:Fur_.

Encore une fois, ce set est généré dynamiquement, au moment du rendu, en fonction de ce qui est présent au moment de l’assignation du RenderGraph. Dit autrement :

D’où le fait que chaque procédurale génère des poils sur son scalp, ainsi que celui de l’autre.

Solution

Comme vous vous en doutez, il faut agir sur le set généré au moment, à savoir l’Asset Id. En effet, si on met les valeurs suivantes :

Le problème disparaît. Le nom de chaque set est généré avec ses propres scalps depuis l’expression scalp:10_lookdev_test|test_000:Fur_$(identifier.assetid) :

Les procédurales sont donc générées sur leur scalp respectif. Pour reprendre la démonstration précédente :

Le log confirme que seul deux systèmes de poils sont générés.

04/16/2022 14:36:55 370M [02] PROC LOG: toto_001:Root|toto_000:Fur: computing hair implantation on scalp toto_001:Root|toto_001:Mesh|toto_001:Scalp..
04/16/2022 14:36:55 370M [02] PROC LOG: toto_001:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 14:36:55 370M [02] PROC LOG: toto_001:Root|toto_000:Fur: generating hairs for toto_001:Root|toto_001:Mesh|toto_001:Scalp..
...
04/16/2022 14:36:55 370M [05] PROC LOG: toto_002:Root|toto_000:Fur: computing hair implantation on scalp toto_002:Root|toto_002:Mesh|toto_002:Scalp..
04/16/2022 14:36:55 370M [05] PROC LOG: toto_002:Root|toto_000:Fur: 400 hairs implanted
04/16/2022 14:36:55 370M [05] PROC LOG: toto_002:Root|toto_000:Fur: generating hairs for toto_002:Root|toto_002:Mesh|toto_002:Scalp..

Vous pouvez vérifier la transparence : Avec une opacité à 0.25, votre poil aura une opacité à 0.25, car il y a en fait un seul poil.

Trace sets par défaut

Voici la liste des trace sets par défaut de Guerilla (2.1).

Lights

Les lumières semblent avoir deux traces sets par défaut :

Surface2

Hair

Volume

Volume2

Eye2

Configurer ACES dans Guerilla 2.3

Faire pointer la variable d’environnement OCIO sur le fichier config.ocio voulu.

Désactiver Use Project Gamma dans Preferences/Project Settings/OCIO :

Guerilla OCIO Use Project Gamma

Passer sa Render View à ACES Views/sRGB :

Guerilla OCIO ACES sRGB Render View

Passez l’attribut Gamma de vos textures à Input - Generic - sRGB - Texture :

Guerilla OCIO Texture Gamma

La logique de déduction du rôle utilisé quand l’attribut Gamma laissé vide est disponible dans la section Textures de la documentation officielle.

Passer le Gamma de vos HDR d’Environment Map sur Utility - Linear - sRGB (Guerilla semble utiliser le role texture_paint par défaut) :

Guerilla OCIO Env Map Gamma

Optionnel : Dans ses RenderPass, passer la valeur de Clamp Pre Filter de 10 à 16 pour profiter de la plage dynamique de la LUT d’affichage de ACES :

Guerilla ACES Clamp Pre Filter

Grossièrement, cela donne :

Texture sRGB vers ACES en rendu Guerilla

Color picker

Dans OpenColorIO, le role color_picking sert à définir l’espace dans lequel sont affiché les couleurs (voir documentation). Il ne sert donc qu’à l’affichage. La documentation de Guerilla semble aller dans ce sens.

Guerilla OCIO Color Picker Role

La question de l’interprétation des valeurs pické semble être une zone grise de OpenColorIO, chaque logiciel semblant interpréter les valeurs différemment.

Correspondances couleurs sRGB/Rec.709 vers ACEScg

Voici un tableau de correspondances de quelques couleurs sRGB/Rec.709 vers ACEScg :

CouleursRGB/Rec.709ACEScg
RougeVertBleuRougeVertBleu
Rouge pur1.00.00.00.6131160.0701970.020619
Vert pur0.01.00.00.339510.9163550.10958
Bleu pur0.00.01.00.0473750.0134490.869801
Jaune1.01.00.00.9526260.9865520.130199
Cyan0.01.01.00.3868850.9298040.979381
Gris neutre0.50.50.50.1844750.1844750.184475

Isoler l’éclairage d’une volumétrique

Un défi qui revient souvent en rendu est de calculer une volumétrique. Si la volumétrique est mise tel-quel dans la scène. Elle récupère les trace sets par défaut. Elle se retrouve donc dans l’illumination indirecte de la scène, mais utilise également toutes les lights de la scène pour se calculer.

L’objectif est donc double :

Du fait de cette isolation, la volumétrique sera forcément moins intégrée à l’éclairage courant, mais son coût de rendu sera grandement diminué. À vous de voir.

Supprimer la volumétrique des trace sets par défaut

Par défaut, Guerilla assigne certains trace sets à tous les objets de la scène :

Guerilla Default Link Set

Passer la volumétrique dans ces trace set, pour les en supprimer :

-All,-Diffuse,-Reflection,-Refraction,-Lights,-Shadows

Si vous sélectionnez votre volumétrique et que vous allez dans Lighting/Set, le champ doit être vide :

Guerilla Empty Link Set

Si vous rendez, la volumétrique ne doit ni s’afficher, ni apparaître dans une contribution indirecte.

À ce stade, la volumétrique est isolée : Elle ne reçoit ni ne participe à aucune contribution.

Assigner les volumétriques dans leur propre trace sets

Nous allons maintenant mettre les volumétriques dans des trace set dédiées. Dans notre exemple, nous allons simplement reprendre les noms des trace sets par défaut, en les suffixant par _VOL :

All_VOL,Diffuse_VOL,Reflection_VOL,Refraction_VOL,Lights_VOL,Shadows_VOL

Cela ne doit pas impacter le rendu. Si c’est le cas, ça veut dire que ces trace sets existaient déjà avant. Une fois encore, vérifiez en sélectionnant la volumétrique et allez dans Lighting/Set, le champ doit être vide :

Guerilla Volume Isolated Link Set

Éclairer les trace sets de la volumétrique

Maintenant, créez une light (une env light avec une HDR, par exemple).

Modifier les trace sets utilisés pour l’éclairage et les ombres de cette light :

Guerilla Volume Isolated Light Set

En faisant ça, votre light n’éclairera que ce qu’il y a dans le trace set Lights_VOL (en l’occurrence, votre volumétrique), et n’utilisera que ce qu’il y a dans le trace set Shadows_VOL pour tracer les ombres (une fois encore, uniquement votre volumétrique).

Définir le trace set à utiliser pour la diffuse de la volumétrique

La dernière étape consiste à définir, dans le shader de volumétrique, le nom du trace set utilisé pour tracer les rayons indirects de votre volumétrique. Pour cela, dans votre shader de volumétrique, allez dans Advanced et modifiez Trace Set pour lui donner la valeur Diffuse_VOL :

Guerilla Volume Isolated Shader Trace Set

À titre d’information, la définition de la documentation pour ce paramètre :

Trace Set est le trace set d’objets utilisé pour tracer les rayons d’indirects du volume. Il n’a pas d’effet si Ray Depth est nulle.

Notez que par défaut, les volumes ne créent pas d’indirect, car l’attribut Volume Bounces d’une RenderPass est 0.

À cette étape, nous avons isolé la volumétrique dans un lighting dédié.

Description des effets

Quand un rayon part de la caméra, il pénètre dans la volumétrique.

Au bout d’une certaine distance (dépendante de Step Size), il fait un sampling du shader de volumétrique à cette position :

Avec ça, on a notre sample de volumétrique. On continue d’avancer le rayon suivant Step Size et on recommence.

Autre cas : Le rayon tombe sur une surface non volumétrique de la scène ; le sol, le mur, etc. Il calcule l’illumination comme n’importe quelle surface puis va envoyer des rayons aux alentours pour tracer les contributions secondaires ; lights, shadows, diffuse, reflection, etc.

Avec notre mise en place, il ne tracera jamais la volumétrique, car ce dernier a été retiré de tous les trace sets par défaut ; Diffuse, Shadows, etc.

Limitations

Si cela permet de diminuer les temps de rendu, isoler totalement la volumétrique d’un lighting produit rarement un effet convaincant. Il est souvent nécessaire de réintégrer la volumétrique dans l’éclairage de la scène. Chaque modification augmentera le temps de rendu.

Par exemple, avec notre mise en place, la volumétrique ne créera pas d’ombres au sol, sur les murs, etc. Pour cela, il faut la remettre dans le trace set Shadows.

Inversement, les objets ne créeront pas d’ombres portées sur dans la volumétrique, ce qui est parfois l’effet voulu.

On peut ajouter le trace set par défaut Shadows au Shadow Set de l’env light, de sorte que tous les objets soient aussi pris en compte dans les ombres, mais ça n’est pas parfait.

Dans le cas des personnages et de certains props (panneaux), c’est ce qu’on veut, mais dans d’autres cela contrecarre l’éclairage HDR lui-même ; si on ajoute les sols où les murs, par exemple, l’HDR ne sera jamais atteinte. Et votre volumétrique sera énormément occludée.

Le but d’une HDR est de simuler l’éclairage global. Si votre volumétrique est éclairée de la sorte, et que vous remettez tous les objets dans les ombres, vous couperez une partie de l’éclairage de l’HDR.

Vous pouvez donc, à l’inverse, ajouter quelques objets et les personnages principaux (sans leurs poils, par exemple) à Shadows_VOL, de sorte qu’ils fassent partie des ombres de la volumétrique.

En faisant cela, vous réintégrerez les ombres des objets et personnages aux alentours à la volumétrique. L’avantage est que le temps de tracing d’une occlusion est relativement rapide et l’apport visuel est important, car il « ancre » les ombres des objets dans la volumétrique, un peu comme une simple ombre portée « ancre » un objet dans une scène.

Bake2D

Extension des bords (edge extend)

Guerilla ne permet pas de faire du edge extend. Vous devez passer par un autre logiciel pour le faire (par exemple, Nuke via le nœud EdgeExtend).

Privilégiez des valeurs de Samples et Adaptive Min Samples élevées pour éviter les problèmes d’aliasing lors de l’unpremult de vos textures bakées. Par exemple, dans le cas d’un bake d’occlusion, il vaut mieux avoir un Samples/Adaptive Min Samples à 256 et une valeur de Samples dans l’occlusion de 4 à 16 plutôt que l’inverse.

Influence du Pixel Filter

Par défaut, la render pass Bake2D arrive avec un Pixel Filter en Mitchel, ce qui ne donne pas de bons résultats dans les bakes d’occlusion. Passez le Pixel Filter en Box avec un X Width et un Y Width à 1. Ceci permet d’éviter des problèmes de filtrage, en particulier sur les ambiante occlusions :

Guerilla comparaison du pixel filter en bake d’occlusion

À gauche le Pixel Filter à Mitchel (par défaut), à droite en Box.

L’occlusion et la position de la caméra

Quand on fait un bake d’une ambiante occlusion dans Guerilla, il peut apparaître des artefacts, comme si le cone angle était à une valeur faible. Ce problème semble augmenter avec le nombre de samples d’occlusion :

Guerilla bake d’occlusion bug

Il est fort probable que votre caméra soit trop loin du modèle que vous souhaitez baker. Si vous rapprochez votre caméra (ou que vous la placez carrément au centre du monde), le problème disparaît :

Guerilla bake d’occlusion propre

Motion Blur

Le Motion Blur Density à Parametric à 0.5, 0.5, 0.0 est identique à Trapeze 0.5.

Dernière mise à jour : sam. 16 avril 2022