CgFX - Des shaders temps réel dans le viewport Maya! - Part 1
Par Narann le lundi, 26 avril 2010, 23:43 - Script et code - Lien permanent
Lors d'un ancien post, je vous parlais des textures dds. Je pensais que ce format résolvait tout les problèmes de plantage dûs à l'affichage mais ce n'a pas été complètement le cas. En effet, même si les plantages étaient mineurs, il restaient présents lors de l'ouverture-fermeture récurrentes des scènes. J'ai donc commencé à chercher d'autres solutions. Je me suis tourné vers les hardwares shaders (elle m'intriguait depuis longtemps cette connexion) et je viens de découvrir le langage CgFX. Après quelques galères, j'ai réussi à faire ce que je voulais dans Maya et, comme vous le savez, je ne peux pas m'empêcher de frimer partager (modestement en fait) mes découvertes sur le sujet, tellement (encore une fois) ce genre d'informations manque sur le net et (d'une certaine façon) fait défaut à l'infographie 3D française. :mechantCrash:
Bon alors Cg c'est quoi?
Cg ça veut dire "C for Graphics". C'est un langage haut niveau (ne traduisez pas par "langage de noobs" ça reste du C et c'est déjà bien balèze pour le scripteur que je suis). Je ne vais pas vous recopier wikipedia, la page est ici. Grosso modo, c'est un langage qui permet de programmer des vertex shaders (skinning pour les jeux vidéo par exemple) et des pixel shaders (la représentation visuel de l'objet).
C'est pour les jeux vidéos ton truc... A quoi ça sert dans notre métier?
C'est une bonne question. A priori, il n'est pas particulièrement utile d'avoir un rendu viewport de qualité quand nous travaillons. Et pourtant. Il peut arriver, dans certains projets que le retour viewport ait besoin d'une qualité minimum:
- Pour faciliter une validation par un réal'.
- Pour permettre aux animateurs de mieux travailler.
- Car, si combiné aux textures .dds (cf ancien billet qui en parle), les shaders CgFX peuvent utiliser pas mal de textures sans trop saturer la mémoire (et donc, diminuer les plantages). Ça demande une certaine préparation (un pipeline qui charge les .dds quand on en a besoin et passe en .map au moment du rendu) mais ça se fait (je l'ai fait sur une production qui à duré un an et demi sans aucun souci).
Pour se la péter devant ses clients/employeurs, ou pas... Personnellement, je trouve qu'un playblast bien propre, ça fait toujours plus sérieux, mais ce n'est que mon avis...- Éviter de bricoler avec les shaders pour "mieux voir" ce qui ce passe dans ce p*tain de viewport. :nevroz:
Pour "vendre" leur langage, Nvidia a fait un jolie paper qui fait un rapide tour de ce qu'il est possible de faire avec CgFX. Il vaut le détour car il est très orienté "Computer graphics" avec des exemples d'application Maya et 3Ds Max.
Petit exemple
Un exemple rapide trouvé sur youtube:
C'est quand même plus classe dans une démo que ce qu'on à l'habitude de voir non? :laClasse:
Par quoi on commence?
En effet, le plus dur, c'est de commencer, pour la petite histoire, j'ai fait simple: "Google is your friend"... Au fil de mes recherche je suis donc tombé sur la page de Brandon Newton qui proposait un tutorial sur les CgFX shader dans Maya (Le site n'est plus disponible...).
J'ai donc commencé à tripatouiller le shader qu'il proposait pour en tirer ce que j'en voulais. J'ai viré tout ce que je n'avais pas besoin pour l'instant en me promettant d'y revenir (Normal map, spéculaire, glow...) pour ne laisser plus qu'un seul paramètre, la texture... Son shader ne gérant pas la transparence, j'ai du l'ajouter moi même, ce qui n'a pas été évident, ceci étant ma première expérience en "shading langage" (heureusement que j'avais regardé l'OpenGL sinon je n'y serais jamais arrivé, comme quoi, tout est lié :hehe: ).
Ça été facile?
Non ' J'ai méchamment galéré (c'est aussi la raison de ce billet) et je suis passé par plusieurs techniques avant de réussir à avoir un alpha convenable. Je me suis beaucoup aidé du GenericBRDF shader de Brice Vandemoortele que je vous encourage très fortement à télécharger, utiliser, regarder, kiffer!). Il y a pas mal de façons d'obtenir les mêmes choses et chacune ayant ses spécificités. :redface:
Avant de commencer...
...je tiens à vous dire que les informations que vous allez lire sont top secret et nullement référencés dans un quelconque registre des services de renseignement américain ne sont que le fruit de mes investigations personnelles mêlées à mes (maigres) connaissances en temps réel... Elles sont donc à prendre avec précaution. Si vous y trouvez une erreur, je vous invite à laisser un commentaire avec une explication que je puisse moi même comprendre et modifier mon billet en conséquent. :sourit:
Lets go! Théorie now! :marioCours:
Bon, les hardware shaders dans Maya c'est quoi? Et bien ce que vous voyez tous simplement! :hehe: En effet, dans votre viewport Maya, ce que vous voyez c'est une représentation des informations de votre scène.
Il y a plusieurs éléments mais le plus important est le scenegraph. Ce terme n'a pas de définition précise mais, quand on en parle, il s'agit généralement de l'architecture (l'organisation) des données dans la mémoire (Définition Wikipedia). C'est à partir de ces informations (position des points, uvs, lumières) que vous pouvez "représenter" votre scène dans n'importe quelle façon (dans un logiciel de rendu par exemple). Ainsi, votre shader à plusieurs représentations (Viewport, Maya Software, Mental Ray).
Au même titre que l'on peut, dans un shading group, forcer l'utilisation d'un shader mental ray d'un certain type alors qu'on utilise un type tout autre dans Maya Software:
Dans le cas ci dessus, si vous rendez le shader avec mental ray vous aurez un mia_material_x, et si vous le rendez avec Maya Software, vous aurez un rampShader
Il est possible (dans certains shaders) de forcer l'utilisation d'un harware shader dans le viewport:
Pédalage...
:reflechi: Une explication, mais ce n'est que mon interprétation: Pour la plupart des shaders (ceux de base, du genre Lambert), il y a leur version Maya software, Mental Ray, et Hardware. Je suppose que la version Maya Software et la version Hardware sont codées en dur dans l'application. La version Mental Ray étant chargée depuis la dll:
base.dll
Sans que l'utilisateur est à s'en soucier. A l'époque (lors de l'intégration de Mental Ray), l'idée était qu'on puisse rendre ses scènes faites pour Maya Software en Mental Ray sans avoir à retravailler ses shaders. Il en résulte une intégration "transparente" pour l'utilisateur final.
EDIT: Je viens de compiler lambertShader.cpp et je dois dire que je suis troublé... J'ai un feedback de la couleur et la transparence dans le viewport pourtant il n'y a pas une seule ligne dans le code qui parle d'OpenGL (ou n'importe quoi relatif à l'affichage hardware). J'en conclus donc une chose (moi et mes conclusions foireuses :seSentCon: ): C'est Maya qui gère ça en interne... Traduisez, ça sent le caca.... Ainsi, Maya ne ferait pas la différence entre Hardware Shader et Software Shader (Raytrace en moins)... J'avoue ne pas tout comprendre mais il semble qu'historiquement (encore une fois...) Alias (à l'époque) souhaitait proposer une API qui permette de développer des shaders sans se soucier de son affichage (et inversement). Tout cela doit donc se passer dans le "core" de Maya. Si c'est réellement ça, c'est typiquement le genre de truc que je peux pas supporter... Mais je sais aussi qu'on peut dériver les classes donc je suppose qu'il est possible de dériver la composante hardware de son shader et de faire mumuse avec OpenGL (ou OpenMGL :baffed: ). Je vais donc m'arrêter ici afin d'éviter de m'enfoncer dans des interprétations dignent d'un scripteur qui se prend pour un développeur...
Reprenons
Comme vous l'avez vu ci dessus, on peut facilement distinguer le shader Maya Software (connecté au "Surface material") et le shader Mental Ray. J'ai souvent vu des infographistes (moi le premier) utiliser bricoler les shader Maya Sofware pour "overrider" l'affichage, dans le viewport, des shaders Mental Ray (qui sont souvent vert ou rouge, pas très bandant...). L'idée de cette manipulation est, vous l'aurez compris, de pouvoir afficher dans le viewport un shader indépendamment du shader rendu (souvent, pour mettre une textures, car quand on présente une scène de rendu avec que des mia, c'est pas la joie pour celui qui la regarde votre viewport).
C'est le même principe que je vous propose de regarder aujourd'hui mais au lieu de bidouiller les shaders Maya Software, nous allons coder un CgFX Shader (et prendre quelques bonnes habitudes).
Let's go 2 - Le vrai!
Nous allons, dans un premier temps activer le plugin qui nous permettra d'ouvrir des fichiers CgFX:
Il suffira maintenant d'aller chercher notre fichier .cgfx pour havoir un hardware shader qu'il ne nous restera plus qu'a connecter ici:
Le site de Vailias n'étant plus disponible, je vous invite à aller sur le site de Nvidia qui propose pas mal de shaders HLSL et CgFX et de prendre le "blinn bump reflect" qui fait des choses intéressantes:
Téléchargez la version CgFX, dézippez la et allez chercher le fichier .cgfx. Vous aurez à relinker les trois textures dds (voir mon ancien billet pour des explications sur ce format de fichier):
Note au utilisateurs de carte graphique ATI Radeon, passez par ici si vous voulez que tout fonctionne.
Pour l'instant, ça ne rend pas grand chose dans le viewport, vous en conviendrez... :seSentCon: En effet, il faut configurer deux trois choses.
Sélectionnez votre cgfxShader:
Note: L'interface n'est pas terrible. En effet, les shaders CgFX de Nvidia n'utilisent pas les fonctions d'interfaçage que peut prendre Maya (un vrai widget de couleur plutôt que trois valeurs à entrer à la main. Nous verrons plus tard comment les utiliser).
Vous remarquez un champ vide, celui de la lampe. Créez une pointLight et copiez collez son nom:
Hop! C'est déjà mieux. Vous pouvez tourner autour (Ouah! Ça reflète avec du bump et tout!) et commencer à modifier les paramètres pour vous amuser (on fait comme on peut... :hihi: )
Bon, c'est super cool mais comment on en fait un nous même?
Ouverture et analyse du shader
Et bien pour le savoir, allez ouvrir "blinn_bump_reflect.cgfx" avec un éditeur de texte. Je vous conseille Notepad++, passez le en langage C:
Bam! :aupoil: Là il va falloir analyser un peut... Avant de commencer, vous devez être conscient de la différence entre les Vertex Shaders et les Pixels Shaders (cf le billet de Shadow qui explique bien ces différences)
Si vous regardez bien, vous verrez que le code est décomposé comme suit:
Déclarations des variables globales, divisées en deux parties:
- Les unchangeables (Matrices du monde...).
Exemple:
[c] float4x4 wMatrix : World;
- Les modifiables (Couleurs, valeurs, textures, etc...).
Exemple:
[c] // Ambient Light float3 gAmbiColor < string UIName = "Ambient Light"; string UIWidget = "Color"; > = {0.07f,0.07f,0.07f};
Ensuite viennent les Data Structures (deux en fait):
- Une pour les entrées (appdata), qui permet de savoir ce que nous allons avoir besoin pour faire notre shader. C'est un peut notre point de départ, les informations de la géométrie en brut.
Exemple:
[c] struct vIN { float4 Position : POSITION; half4 Color : COLOR0; half2 TexCoord : TEXCOORD0; };
- Une pour les sorties (vertexOutput), qui nous permet de savoir qu'est ce qu'on à besoin "en sortie" du shader... L'idée est de "remplir" cette structure de A à Z.
Exemple:
[c] struct vOUT { float4 Position : POSITION; half4 Color : COLOR0; half2 TexCoord : TEXCOORD0; };
Deux programmes (std_dp_VS et blinn_PS). Ce sont eux nos shaders:
- VS pour Vertex Shader qui "compute" la géométrie (position des vertex, uv, etc...). C'est le premier "Program" qui est exécuté. On lui donne la structure d'entrée (appdata) et il renvoie la structure de sortie (vertexOutput) remplie.
Exemple:
[c] vOUT MainVS(vIN IN) { vOUT OUT; // On remplit notre OUT: position ,uvs OUT.Position = mul(wvpMatrix, IN.Position); OUT.TexCoord.xy = IN.TexCoord; OUT.Color = IN.Color; return OUT; }
- PS pour Pixel Shader qui "compute" chaque pixel en fonction du vertex. Il renvoie une couleur mais nécessite la structure de sortie (vertexOutput, calculé par le Vertex Shader) en argument pour pouvoir justement, calculer cette couleur.
Exemple:
[c] float4 MainPS(vOUT IN) { half4 diffuse = tex2D(colorSampler, IN.TexCoord.xy).rgba; //Notre diffuse utilise la texture return float4(diffuse.rgb, 1.0); }
Les exemples que j'ai donnés sont volontairement plus simples que le CgFX de Nvidia. Mais vous pouvez aisément retrouver leur équivalent. Toutefois, n'essayez pas de tout comprendre, c'est des maths purs, notre but est de savoir comment ça fonctionne, pas de savoir comment calculer du SSS en temps réel. Personnellement, quand j'ai un CgFX à faire, j'isole des morceaux de code bout à bout (lambert, color, reflect, etc...) pour rester le plus simple possible. :sourit:
Et on finit par la dernière "chose": Les program "technique". Un program technique permet, comme son nom l'indique, d'utiliser plusieurs techniques pour calculer son shader. Vous pouvez ensuite demander à Maya (ou votre logiciel) d'utiliser une de ses technique. Ce shader ayant qu'une seul technique (Main) Maya n'en propose qu'une seule:
Mais rien n'empêche d'en faire d'autres:
- Surface shader
- Illumination
- Illum+Textures
- Illum+Textures+Bump
- etc...
C'est, je crois, une des spécificités du langage CgFX qui le rend particulièrement modulable.
Mais avançons un peu. Chaque technique peut avoir plusieurs "passes" (un peut comme le compositing). Un exemple d'utilisation des "pass" dans les shaders peut être pour les calculs de la relfection/refraction de l'eau dans les jeux vidéos: Une première passe calcule tout, sans l'eau. Une seconde copie le frambuffer, applique des déformations et le tout est superposé.
Dans notre cas, nous n'utilisons qu'une seule pass.
S'en suit plusieurs choses (qui sont les "options" de rendu). Par exemple, "CullFaceEnable = false;" active le backface culling pour le rendu de ce shader. Il est très intéressant de pouvoir contrôler ces paramètres mais nous n'allons pas nous y attarder (Un shader CgFX peut fonctionner sans).
Les choses indispensables sont cependant les deux "Programs":
- VertexProgram: Indique ou est notre Vertex Shader. "compile vp40" indique qu'il faut utiliser le profile de compilation vp40 (pour ceux que ça interesse: Quelques explications ici) et le dernier, c'est la fonction à compiler...
- FragmentProgram: Tout pareille ici mais pour le Pixel Shader.
Ouf! Nous avons fait le tour et allons être capable de commencer à concevoir notre propre shader CgFX!
Prenez le temps de bien saisir tout ça, la suite dans le prochain billet. :laClasse:
A bientôt!
Dorian
Commentaires
Merci pour ton tit passage ;)
:-)
Super billet! génial pour tous les maya user francophones :D