Dorian Fevrier's blog - Mot-clé - poilJe 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:695d9c73474c33ce3dab043823509c4bDotclearGuerilla, 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>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>