Sommaire:

Avant de commencer je voulais remercier la personne qui m'a fait "découvrir" le principe de la "map de debug": Pierre LOPES.

C'est bête comme tout et je me suis senti idiot de ne pas avoir eu l'idée en premier tellement le principe est simple.

La map de debug

Comme vue dans mon billet précédent, pour pouvoir voir comment se comporte une mipmap, il faut créer des maps différentes pour chaque niveau et des les empaqueter dans une .map mental ray (ce sera l'objet de mon dernier billet la dessus). Voici ma map de debug. En ce qui me concerne, j'ai "écrit" la taille de la map en question sur chaque niveau (je vous conseille vivement de faire ça):

testMapProfil.png

J'ai ainsi:

  • Mon niveau principal, le plus grand: 8192 x 8192
  • Niveau 2: 4096 * 4096
  • Niveau 3: 2048 * 2048
  • Etc...

Mais ne perdons pas de temps et testons cette map!

Vous pouvez la télécharger ici (24mo) au format 7-zip (dsl pour le format mais Winrar, n'a atteint que 68mo... :mechantCrash: ).

Premier test

Pour les paramètres de rendu, on fait simple et vite: J'utilise le preset Production, Anti-aliasing Contrast à 0.05, filtre Mitchel:

map_debug001.png

map_debug002.png

N'oubliez pas de passer en rendu mental ray (Maya software supporte les .map mais pas le mipmaping :sourit: ). map_debug003.png Et un diagnostique du sampling:

map_debug006.png

map_debug003Diagnose.png

Vous l'aurez compris, il y a des options par défaut qui font déjà quelque chose. :hehe:

Ici, ont voit que mental ray à utiliser les niveau en 256*256 et 128*128. Donc mental ray utilise bien la mipmap avec des options de base. L'envois de sample est modéré et un bon compromis.

Vous pourrez le faire remarquer: 256 pixels, c'est peut être un peu léger (nous y reviendrons pour régler tout ça! :hehe: )

Sans le filtrage

Désactivons le filtrage:

map_debug004.png

map_debug005.png

Si nous regardons de plus près nous voyons en effet qu'aucun filtre n'est appliqué sur la texture:

map_debug010.png

map_debug007.png Direct, ça lance beaucoup plus de samples... On peut même voir un effet de "vague" qui montre qu'il y a une sorte de "saturation".

Petite pause sur le diagnose sample dans le cas d'une map de debug

Bon, je m'arrête un peu la dessus car ça mérite quelques précisions. :youplaBoum:

Utiliser le "diagnose samples" est conseillé car il permet de voir "ou les samples se perdent". Je vous ai montré deux exemples ici pour voir le principe. Cependant, il ne faut pas s'y arrêter. En effet, sur la map de debug, chaque niveau à sa propre texture, ses propres couleurs, son propre piquet. Comparer les passes de "diagnose" de différents paramètres entre elles n'a aucun intérêt avec une map de debug. Voici un exemple qui viens appuyer mes dires (j'ai utilisé un paramètre que nous verrons plus tard pour bien distinguer les deux résolutions):

map_debug009.png

map_debug008.png

Nous voyons que la résolution de 2048 à nécessité plus de sample que la résolution 4096 car, encore une fois, chaque niveau à sa propre texture, ses propres couleurs, son propre piquet (rabâche :redface: ).

Je vous invite donc, à diagnostiquer vos samples quand vous êtes en condition réelle mais cette manipulation est inutile voir trompeuse avec une map de debug. :sourit:

Fin de la parenthèse.

On reprend avec les filtres de base de Maya

Passons en Mipmap:

map_debug011.png map_debug012.png

Pour pouvoir faire varier la "vitesse" de changement entre les différents niveaux de la map, il suffit de jouer avec la valeur du filter (dans Effects).

map_debug016.png map_debug017.png Plus vous la diminuer, plus vous atténuez l'effet du filtre (on dit la compression) et plus vous vous rapprochez du niveau "zéro" (full résolution). Un filter à 0 et votre texture est en full résolution, comme si vous étiez en off (logique).

Vous pouvez changer de filtre (Quadratic, Quartic, Gaussian, oubliez le Box...), vous obtiendrez toujours cet espèce de dégradé que vous pourrez "contrôler" grâce a la valeur du filter (dans Effects).

Ça c'est pour les filters de "base" (vous verrez plus tard que ce n'est pas aussi simple).

Je vous présente brièvement le dernier (j'aurai l'occasion d'y revenir plus en détail): Le filtre Elliptique

Le filtre Elliptique

C'est quoi ça? o_O

C'est un filtre un peu spécial de mental ray qui offre l'avantage d'avoir un excellent piquet sur la texture et diminue fortement le flou sur celle ci (comparé à l'utilisation d'autres filtres). Avant, il fallait bidouiller pour l'avoir (nous verrons ça plus tard :sourit: ). Maintenant, rien de plus simple:

Vous passez en Mipmap:

map_debug011.png

Puis dans le frame mental ray, vous activez "Advanced Elliptical Filtering":

map_debug013.png

Dans sa grande bonté (sarcasmes inside), Maya va automatiquement vous cocher les deux cases suivantes ("Override Global Auto-Conversion Settings" et "Convert File To Optimized Format").

Décochez la première suffira. Mais assurez vous surtout que la case "use optimized texture (auto-conversion)" est décoché dans "Preference/Rendering":

mentalRayPref001.png

Revenons-en à notre filtre elliptique. En fait, l'utilisation de ce filtre n'est efficace que dans le cas d'une map pyramidale (petit rappel ici :sourit: ), d'où cette "gentille" façon de vous forcer la main des fois que vous serriez trop con pour faire vos maps tout seul... :baffed:

Le paramètre Anti-Aliasing Level est un peu comme la valeur du filter pour les autres filtres (mais en sens inverse). Il correspond (grosso modo, nous expliquerons mieux ça plus tard) au nombre de pixel de la texture (texels) qui seront utilisé par pixel. 8 est une bonne valeur. Plus vous la diminuez plus vous avancez dans les différents niveaux de la map (et donc une faible résolution). Testez par vous même: mentalRayPref002.png PS: Sur la documentation officielle (à la fin) une option est donné pour ajouter des paramètres (qui sont au final les paramètres du node mental ray mib_texture_filter_lookup):

addAttr -longName "miEllipticalBilinear" -at bool -defaultValue 1 file1; 
addAttr -longName "miEllipticalEccMax" -at "float" -defaultValue 4.0 -minValue 0.001 -maxValue 40.0 file1; 
addAttr -longName "miEllipticalDiscR" -at "float" -defaultValue 0.3 -minValue 0.001 -maxValue 1.0 file1; 
addAttr -longName "miEllipticalCircleR" -at "float" -defaultValue 0.8 -minValue 0.001 -maxValue 1.0 file1;

Je reviendrais sur ces options plus tard :sourit: .

Arf! On voit la jonction entre les différents niveaux! C'est tout pourris!

Héhé! :hehe: Vous êtes tombé dans le panneau. En effet, bien que ça puisse sembler surprenant, ce filtre est l'un des plus précis de tous. En effet, Les autres filtres font soit de l'aliasing (Off, Box) soit du flou (Mipmap, Quadratic, Quartic, Gaussian). Voici une image avec les différents filtres activés. mentalRayFilters001.png

On remarque les similitudes entre Quadratic, Quartic et Gaussian. Ils ont aussi cette tendance à finir en "gris" (l'effet "jeux vidéo"). Comparé au filtre Elliptique qui va beaucoup plus loin, et beaucoup plus précis. Après, ce n'est peut être pas le plus joli esthétiquement parlant mais c'est un autre débat. Il peut vraiment servir dans certains cas et le fait de savoir qu'il existe pourra vous aider.

A l'attaque de mental ray, le vrai, pas l'autre!

Jusqu'à présent, tout ce qu'on a pu voir était "Maya thinked" et, comme tout ce qui est "Maya thinked", tout est caché pour pas traumatiser l'artiste en pleine folie créatrice... Nous, techniciens de base, on n'est pas trop susceptible vis-avis de ce genre de chose (si ont pouvais (re)faire de la 3D en console, on s'en plaindrait presque pas :baffed: ) et ce qui nous intéresse ici c'est justement de comprendre ce qui ce passe... :hehe:

Les filtres mental ray

Mental ray dispose, par défaut, de deux filtres de texture.

Le filtrage Pyramidale

Je vais être franc, je n'ai jamais réussi à rendre de manière identique ce que me donne ce filtres de texture avec des rendus de filtre de type Maya (mipmap, quadratic, etc...). Je me demande si c'est possible en fait. ces derniers ont l'air de fonctionner dans mental ray comme avec Maya Software et donnent des résultats identiques. Je soupçonne que "mental ray for Maya" ait l'équivalent de ses filtres codé dans le plugins mais inutilisable en temps que node indépendant.

Pour revenir au filtre pyramidale, j'ai beaucoup de mal à comprendre la documentation (que je trouve presque contradictoire).

Je vous laisse juger:

http://download.autodesk.com/us/maya/2010help/mr/manual/node23.html << Doc mental ray

http://download.autodesk.com/us/maya/2010help/Nodes/mentalrayTexture.html << Doc du node Maya

mentalrayTextureSetup001.png

mentalrayTexturePanel001.png

Si je devais résumé de ce que j'en comprend, c'est que:

  • Si votre map est une texture "normal" (non .map), il converti la texture en map pyramidale (tout ça dans la mémoire, ce qui nécessite environs 30% de mémoire supplémentaire) avant d'y utiliser sont filtre mipmap (pour determiner la couleur de chaque pixel).
  • Si votre map est déja "memory mapped", il ne la convertie pas et utilise directement le filtre mipmap.

Si c'est réellement ça, c'est assez mal énoncé... :zinzin:

Concernant la valeur du "filter size" du node mentalrayTexture (on va faire simple ce coup ci), c'est exactement le même principe que la valeur du filter du node de file. mentalrayTextureFilter001.png D'après mes tests, il me semble que cette méthode offre la "courbe de changement" la plus douce.

En effet:

Maya filter Box, 0.5: mentalRayFilterCurve001.png Maya filter Quadratic 0.5: mentalRayFilterCurve003.png Maya filter Quartic 0.5: mentalRayFilterCurve004.png Maya filter Gaussian 0.5: mentalRayFilterCurve005.png Quadratic, Quartic et Gaussian se ressemble énormément... Et même Box en fait... Ormis la précision, la "courbe de changement" est identique...

Maya filter Mipmap 0.5: mentalRayFilterCurve002.png Filtre Pyramidale 1.0 (mentalrayTexture): mentalRayFilterCurve006.png Mipmap (de Maya) et le filtre (Pyramidale de la mentalrayTexture) se ressemble beaucoup mais je n'ai pas réussi à trouver un bon rapport pour les faire coïncider... (Si quelqu'un à déjà réussi, je serai ravis qu'il me fasse partager sa trouvaille).

Je pense que nous avons fait le tour du filtre pyramidale de mental ray, passons au suivant! :sourit:

Le filtre Elliptique (Le Retour!)

Ici nous allons voir "comment que c'est qu'on faisait avant que le bien aimé Autodesk ne nous fasse une checkbox: Elliptical Filtering"... :enerve:

Nous avons vu comment faire "simple-mais-on-comprend-rien" (Plus haut). Maintenant nous allons voir comment faire "compliqué-et-ptete-que-si-t'est-pas-trop-con-tu-va-capter-un-truc" (Avant de venir spammer ma boite mail que je suis un sale petit branleur médisant, sachez que je n'ai pas réellement compris comment il fonctionnait, donc "ironie inside" :hehe: ).

Voici comment "monter" notre shader:

map_debug015.png

map_debug014.png

Notez le coté indigeste du truc! ^^ (Et aussi les attributs qui étaient caché par Maya et ajoutable via un "addAttr", cf plus haut).

La doc est ici:

http://download.autodesk.com/us/maya/2010help/mr/manual/node24.html << Doc mental ray

http://download.autodesk.com/us/maya/2010help/mr/shaders/node6.html#mi_shader__mib_texture_filter_lookup << Doc du node Maya

Et maintenant, l'explication. Accrochez vous car:

  • D'une je ne suis pas sûr de moi
  • De deux c'est assez complexe à imaginer...

J'ai donc fais quelques shema pour tenter d'expliquer tout ça:

shemaProjection01_normal.png

Le framebuffer est une zone mémoire ou sont stocké les couleurs (RVBA) des pixels à la queue leu leu tout le monde s'éclaaaaate!.... Ici, nous nous concentrons sur les méthodes utilisés pour déterminer la couleur d'un seul pixel (suivant les filtres utilisés).

Pour vous faire une idée simple, on a un plan avec un material surface shader avec une texture dessus.

Cas de filter sur Off

shemaProjection01_filterOff.png

En désactivant le filter, ce seront les samples "classiques" qui détermineront la couleur du pixel.

C'est un petit peut plus complexe que ça mais dans l'idée:

  • Le moteur lance des samples depuis la camera dans le pixel.
  • Ces samples se "cognent" à un pixel d'une texture (texel).
  • Chaque sample renvoit la couleur de se texel au moteur.
  • Le moteur fait la moyenne des couleurs des samples en fonction du filtre de rendu des samples utilisés (Pour simplifier l'explication, on prend le cas d'un filtre de rendu de type "box" à 1x1 qui fait, pour chaque pixel, la moyenne de la couleur des samples).
  • La valeur RVBA de la couleur résultante est placé dans le pixel du framebuffer.
  • On passe au pixel suivant.

Le problème de cette méthode (nous l'avons vue dans le billet précédent) est qu'elle créé beaucoups d'aliasing et est donc très sensible au mouvement.

Ce n'est pas mon habitude mais je trouve que ce shema est très parlant. Il est tiré du livre "mental ray Handbooks Vol. 1 : Rendering with mental ray" (lien Amazon):

texture_sampling_locationOff.jpg

Nous voyons que les informations récupérées sont indépendantes de la distance (la camera étant supposé être situé en bas du schéma) ce qui fait qu'au moindre mouvement, les informations récupérées sont totalement différentes.

Cas de filter sur mipmap (Box, Mipmap, Quadratic, Quartic, Gaussian)

shemaProjection01_filterMipmap.png

Comme expliqué dans le dessin, l'idée est que le moteur va descende dans les niveaux de la mipmap jusqu'à avoir un texel suffisamment grand pour englober toute le pixel. Il suffit donc de récupérer la couleur de se textel.

Voici l'idée (Ici un pixel qui cible un plan texturé):

projectionMipmap01.png

Non

projectionMipmap02.png

Non

projectionMipmap03.png

Non

projectionMipmap04.png

Non

projectionMipmap05.png

Non

projectionMipmap06.png

Ok! :banaeyouhou:

Et le schema de ce qui est récupéré dans le pixel:

texture_sampling_locationMipmap.jpg

Ici, plus les points sont éloignés, plus les zones récupérées pour l'approximation sont grandes.

Optimisation et explications plus précises

Bon, dans les faits c'est très couteux de faire ça. Les gars de mental image, plutot que de calculer à chaque fois si un seul texel rentre dans le pixel, ont décidé de faire "moins complexe" (uniquement en terme de calcul parce que j'ai mis un peu de temps avant de capter ^^).

En gros, l'idée est de calculer un "facteur de compression" qui servira "d'index" pour se déplacer entre les différents niveaux de la mipmap (1=niveau0, 0.5=niveau1, 0.25=niveau2, etc...). Pour calculer ce facteur, voici la méthode (accrochez vous, ça va aller très vite):

  • Le pixel (du framebuffer) projette un rectangle sur la texture (pour alléger l'algo, il projette en fait un carré).
  • On récupère la taille (en texel) d'un des cotés du carré (qui a été projeté dans l'espace de la texture: UV)
  • On fait l'inverse de cette valeur (inv(x) = 1/x)

Ça y est, nous avons notre facteur de compression :baffed: .

Pour comprendre un peu mieux "le coup de l'inverse", je vais prendre un exemple: Si notre carré projeté avait fait 4 pixels de coté, le facteur de compression aurait été 1/4, autrement dit, il aurait fallu déscendre de 4 niveaux pour récupérer la valeur du pixel.

Imaginez la mipmap comme un building: Tout en haut est la map la plus grande (le niveau0). Et plus on descend plus on avance dans les niveau des maps. Mais dans la mesure ou le facteur de compression est un chiffre à virgule, il se peut qu'il soit entre deux niveaux de la mipmap. Ni précisément sur l'un, ni précisément sur l'autre.

Si c'est le cas, le moteur récupère les deux texels (juste en haut et juste en bas). Ceux ci sont (saucisson haha trop bonne celle là! :hehe:), dans un premier temps, interpolés de manière bilinéaire (pas flouté, ce n'est pas pareille, nous le verrons plus bas). Les valeurs de couleurs du pixel de chaque niveau respectif sont ensuite interpolés de manière linéaire. (En gros de chez gros, il fait la moyenne. Encore une fois, la doc est votre amis).

Malgré le coté indigeste de mes explications foireuses modestes :baffed: , gardez mon exemple précédent à l'esprit: Grosso modo, il va chercher le texel de la taille de mon pixel.

Comme vous pouvez vous en douter, cette méthode à la fâcheuse tendance à "flouter rapidement" (voir plus haut). Imaginez le cas d'un plan quasi-horizontal par rapport à la caméra (comme le schéma mais en plus prononcé). La distance physique (comprenez "dans l'espace 3D"), sur le plan, qu'il peut y avoir entre le bas du pixel et le haut peut être importante et le moteur doit descendre "profondément" dans la mipmap pour avoir un texel qui recouvre tout le pixel. C'est ce qui nous donne des pixels complètement gris dans le cas d'un damier noir et blanc répétitif. On peut cepandant faire varier la taille du filter pour tenter de grappiller un peu (pas trop sinon c'est l'aliasing assuré). Cette technique est surement le meilleur rapport qualité/vitesse.

Il y a un exemple que je trouve très parlant dans la doc officiel:

If the pixel has a projected size of four texels in texture space, then one texel is compressed to 1/4 in the focal plane.

Comprenez: Si un pixel (framebuffer) à une taille projeté (sur le plan) de quatre texels, et bien un texel est "compressé à 1/4" dans ce pixel(et il faudra descendre de 4 niveau dans la mipmap pour obtenir sa couleur).

Cas de filter elliptique

Pour le filtre elliptic, je vais devoir passer à un schema 3D:

shemaProjection01_filterElliptic.png

Soyez indulgent, ce n'est pas facile de représenter ça. Ormis le gros cercle blanc dont je vais expliquer la présence, nous avons tout les éléments déja présents dans les schemas 2D:

  • Le framebuffer (en rouge et la plaque transparente)
  • Le plan et sa texture
  • Les rayons de projection (en bleu)

Une fois encore, n'oubliez pas l'echelle (même si elle n'est pas bien retranscrite sur mon schéma, c'est justment pour ça que je me permet de faire un rappel): On cherche à savoir comment est calculé un pixel. Dans un cas plus "réel", la camera serait beaucoup plus loin, et le plan et sa texture aussi).

Alors, comment ça marche. :sourit:

En fait, un cercle ("ellipse" serait plus aproprié) est projeté dans le pixel du framebuffer:

shemaProjection02_filterElliptic.png

Une fois ce cercle projeté:

  • On mesure son rayon minimum (minor radius) dans "l'espace 3D" (ici, le rayon minimum sera quasiment horizontal).
  • On compte le nombre de texel que traverse le minor radius
  • Si celui ci est plus élevé que la valeur de maxminor (Anti-aliasing Level dans l'UI Maya thinked, 8 par défaut), on "avance" d'un niveau dans la mipmap puis on recommence jusqu'à ce que ce soit le cas.

Si vous avez bien compris, vous devriez être en mesure de comprendre pourquoi, ducoup, la coupure est aussi "net" entre les différents niveaux de la mipmap avec le filtre elliptic. map_debug018.png Vous comprendrez aussi le dernier schema:

texture_sampling_locationElliptical.jpg

Nous avons fini pour l'explication des différents filtres mental ray. (ouf)

N'hésitez pas à laisser un commentaire si vous ne comprennez pas des choses, si je n'ai pas été assez clair quelque part ou si, tout simplement, je me suis planté... :sourit:

A très bientôt pour la dernière partie qui expliquera comment fabriquer la map de debug utilisé durant ses exercices.

Dorian