:longBar:
Sommaire:
:longBar:

Ajout de la diffuse

Actuellement, le shader n'a aucune couleur. Il se contente d'additionner les couleurs des deux pointLights (en fait, il se comporte comme si il était blanc). :reflechi:

Pour ajouter une couleur de base (que j'appellerai "diffuse"), il faut déjà ajouter les paramètres de diffusion (Ici, une couleur et un coefficient):

// Diffuse
float3 diffuseColor
<
	string type	= "color";
	string UIName =  "Diffuse Color";
> = {0.07, 0.07, 0.07};
 
float diffuseFactor
<
	string UIName =  "Diffuse Factor";
	string UIWidget = "slider";
	float UIMin = 0.0;
	float UIMax = 1.0;
	float UIStep = 0.001;
> = 1;

cgfx_part3_001.png

Passons au calcul de la diffuse. C'est assez simple. Dans le "program" du Pixel Shader (MainPS()):

//Calcul la valeur de la couleur de la Diffuse
float3 diffuseColorResult = diffuseColor.rgb;	// On la rend de la couleur de nos paramètres
diffuseColorResult *= diffuseFactor;	// Et on multiplie le tout par le coefficient

Maintenant que nous avons calculé la valeur de diffuseColorResult, allons à la ligne de résultat:

float3 result = illumPointLight0 + illumPointLight1;

Et multiplions le tout par notre diffuseColorResult:

float3 result = (illumPointLight0 + illumPointLight1) * diffuseColorResult;

cgfx_part3_002.png

cgfx_part3_003.png

Voila, c'est un peu "bizarre" l'effet (car parfait) mais ne vous inquiétez pas, quand on passera aux textures, ça sera tout de suite plus joli! ^^

cgfx_tuto_004.7z

Maintenant, ajoutons de l'ambiant.

:longBar:

Ajout de l'ambiant

Le principe de l'ambiant, c'est d'ajouter de l'illumination. C'est donc une addition mais uniquement sur l'illumination, pas sur le résultat total.

Si on "ajoutait" au résultat total, ça serait l'équivalent de l'incandescence dans Maya (ou Additional Color dans un shader mia_x). L'effet ne serait pas du tout le même!

C'est tellement simple que vous pourriez le faire vous-même:

// Ambiant
float3 ambiantColor	// On créé l'attribut
<
	string type		= "color";
	string UIName =  "Ambient Color";
> = {0.07, 0.07, 0.07};
float3 result = (illumPointLight0 + illumPointLight1 + ambiantColor) * diffuseColorResult;

cgfx_part3_004.png

cgfx_part3_005.png

Encore une fois, si vous avez des doutes, essayez par vous même d'ajouter l'ambiant au total.. ^^ (Une modif, un save, un reload et on a le résultat direct! Profitez-en pour expérimenter!)

Vous verrez de suite la subtilité. :sourit:

:longBar:

Ajout du falloff

Maintenant nous allons attaquer un effet que je trouve très intéressant (et qui est particulièrement à la mode dans le jeux vidéo): Le falloff

mario-galaxy-hd.jpg

It's meee! Mario! :marioCours:

Que serait une intro sans une image... (tiré de la galerie du thread: Wii emulator can do 720p HD)

Voyez l'effet sur la casquette et le pantalon, ça débouche les contours, et bien c'est ce que nous allons faire! :sourit:

:longBar:
Ajout de la matrice et modification de la strucure

Et c'est maintenant que ça ce complique. Vous vous rappelez comment on à fait notre illumination à partir des deux pointLights? Et bien grossièrement ici, c'est la même chose, sauf que notre pointLight, c'est la "view", la camera... On éclaire par la caméra, mais en négatif... :zinzin:

Nous allons dans un premier temps, ajouter, tout en haut du fichier, une matrice appelée ViewInverse. (Je ne suis pas trop calé sur les différentes matrices de CgFX. Je ne sais donc pas ce qu'elles représentent mathématiquement. Cela dit, j'ai trouvé une doc intéressante sur les matrices utilisées en temps réel: http://code.google.com/intl/fr-FR/a... Cette doc n'est pas spécifique au langage CgFX.):

float4x4 viMatrix : ViewInverse;

Puis on ajoute un paramètre "WorldView" à notre structure vOUT:

struct vOUT
{
	float4 Position	: POSITION;
	float3 PointLight0Vec	: TEXCOORD0;
	float3 PointLight1Vec	: TEXCOORD1;
	float3 WorldNormal	: TEXCOORD2;
	float3 WorldView	: TEXCOORD3;	// ajout d'une variable à la structure
};
:longBar:
Modification du Vexter Shader

Là c'est bcp moins classe: Dans MainVS(), on "copie-colle" le morceau de code que j'ai moi même copié-collé d'un des shaders de NVidia... :nevroz:

OUT.WorldView = normalize(float3(viMatrix[0].w,viMatrix[1].w,viMatrix[2].w) - PositionWorld.xyz);

Je suis incapable d'expliquer ce que ça fait ormis que ça remplit votre "OUT.WorldView" bien comme il faut! :sourit:

Notre WorldView est maintenant remplit par le Vertex Shader: MainVS().

:longBar:
Modification du Pixel Shader

Passons a MainPS(), on normalise notre valeur (comme les autres):

float3 Vn = normalize(IN.WorldView);

Et on s'en sert pour générer le falloff:

//FallOff
	float ndv = dot(Nn,Vn);
dot()... La fonction magique... :hehe:

A ce stade vous pouvez essayer de n'afficher "que" la valeur de ndv dans votre shader pour voir le résultat:

float3 result = ndv;

cgfx_part3_006.png

On y est presque on dirait! :sourit:

:longBar:
Ajout des attributs

On va ajouter deux paramètres:

  • Un pour contrôler la visibilité (opacité) du falloff (Un float de 0 à 1)
  • L'autre pour contrôler "sa compression"

Le tout, calé en dessous de l'ambiant. Ce qui donne, pour les attributs:

// FallOff
float fallOffCompression
<
	string UIName =  "FallOff Compression";
	string UIWidget = "slider";
	float UIMin = 0.0;
	float UIMax = 10.0;
	float UIStep = 0.001;
> = 1.0;
 
float ambiantFallOffFactor
<
	string UIName =  "Ambient FallOff Factor";
	string UIWidget = "slider";
	float UIMin = 0.0;
	float UIMax = 1.0;
	float UIStep = 0.001;
> = 1;

Voyez que j'ai appelé le coefficient: "Ambient FallOff Factor". Vous verrez la relation entre l'Ambiant et le Falloff plus tard...

:longBar:
Retour au Pixel Shader

Maintenant retournons dans notre program MainPS() et on ajoute:

//FallOff
float ndv = dot(Nn,Vn);
float fallOffRamp = pow(ndv, fallOffCompression);

En fait c'est comme si on faisait ndv^fallOffCompression: Si votre fallOffCompression = 2, alors nous auront ndv au carré!

C'est ce fallOffRamp qui va être multiplié au ambiantFallOffFactor. Je vous propose, pour bien voir le résultat de le faire de suite:

float3 result = fallOffRamp * ambiantFallOffFactor;

cgfx_part3_007.png

cgfx_part3_008.png

cgfx_part3_009.png

cgfx_part3_010.png

Amusez vous avec les paramètres, change le "result", bidouillez! Il n'y a que comme ça que je suis arrivé et je vous invite à le faire!

Pour inverser la couleur (pour avoir du blanc sur les contours):

float fallOffRamp = pow(1-ndv, fallOffCompression);

cgfx_part3_011.png

:longBar:
Dilemme de l'ambiant et du falloff

A ce stade nous avons, un falloff dont nous contrôlons "la compression" et l'opacité. L'idée est que ce falloff agisse de la même façon que l'ambiant, à savoir, comme un ajout à l'illumination.

Simple me diriez vous. Il suffit de faire ça:

float3 result = (illumPointLight0 + illumPointLight1 + fallOffRamp * ambiantFallOffFactor) * diffuseColorResult;	// Vous n'oubliez pas quelque chose?

Oui... Et ambiantColor on en fait quoi? :sourit:

Je m'explique: Il nous faut s'arranger pour que les valeurs d'ambiant et de falloff ne fassent plus qu'une. Mais essayez de visualisez ce que nous avons:

  • Une ambiant (ambiantColor), qui est donc juste une couleur.
  • Un falloff (fallOffRamp * ambiantFallOffFactor), dont vous voyez très bien à quoi ça ressemble.

Si nous additionnons bêtement les valeurs, cela donnera quelque chose d'un peu chiant à régler.

Essayez (comme toujours...):

float3 result = ambiantColor + fallOffRamp * ambiantFallOffFactor;

Et jouez avec les paramètres. Vous allez vite vous rendre compte du problème. :reflechi:

De même qui si nous les multiplions, l'ambiant jouera le rôle d'un "simple" coefficient:

float3 result = ambiantColor * fallOffRamp * ambiantFallOffFactor;

Ici, ambiantColor et ambiantFallOffFactor jouent le même role au final... Donc inutile.

Encore une fois, petite prise de tête en perspective... :siffle:

Simplifions un peu: Ce qui serait bien, ça serait que ambiantFallOffFactor soit une sort de "switch" entre l'ambiantColor color et le fallOffRamp:

  • Si ambiantFallOffFactor = 0, alors c'est l'ambiantColor qui à le dessus (ambiantColor*1 et fallOffRamp*0).
  • Si ambiantFallOffFactor = 1, alors c'est la fallOffRamp qui est à fond (ambiantColor*0 et fallOffRamp*1).

Enoncé comme ça, ça doit commencer à vous parler un peu...

J'ai mis pas mal de temps à trouver la combine mais la voici:

//Ambiant
float3 AmbiResult = ambiantColor * (1-ambiantFallOffFactor) + fallOffRamp * ambiantFallOffFactor;

Regardez bien cette ligne (Vous -> :gne: )et comparé là à ce que j'ai dis juste au dessus, ça devrait faire tilte! Une fois qu'on a compris le raisonnement, ça saute aux yeux!

Ca marche! Modifiez et faites vos tests: Le ambiantFallOffFactor fait bien office de "switch".

On y est presque! Le dernier souci c'est concernant la couleur. En effet, rien pour l'instant ne permet de choisir la couleur du falloff...

Il y a plusieurs façons de procéder. La plus simple serait de créer un autre paramètre que vous pouvez appeler fallOffColor et le multiplier (plus haut) à la fallOffRamp.

Je n'ai pas choisi cette option et je vais vous expliquer pourquoi :redface: :

Pour moi, le principe est que le falloff ne fait que régir le comportement de l'ambiant:

  • Si il est désactivé (ambiantFallOffFactor = 0), nous avons une ambiant "de base": Une addition linéaire ambiantColor sur l'illumination.
  • Si il est activé (ambiantFallOffFactor = 0.5), nous avons une ambiant qui se "falloffise", mais qui doit conserver la couleur de l'ambiant...

Et pour faire ça, on multiplie ambiantColor au falloff:

//Ambiant
float3 AmbiResult = ambiantColor * (1-ambiantFallOffFactor) + ambiantColor * fallOffRamp * ambiantFallOffFactor;

Mais dites donc! Ça ne vous rappelle rien? Mais si! Vos anciens cours de math! Nous avons ambiantColor qui est multiplié deux fois... Il faut Factoriser! :baffed:

//Ambiant
float3 AmbiResult = ambiantColor * ((1-ambiantFallOffFactor) + fallOffRamp * ambiantFallOffFactor);
J'avoue, c'est vraiment pour faire chier! Mais c'est tellement rare de pouvoir utiliser ce qu'on c'est cassé le cul à apprendre à l'école que ça fait plaisir! :hehe:

Testez avec:

float3 result = AmbiResult;

En gros, quand l'ambiant est à fond mais que l'ambiantFallOffFactor est à fond aussi, c'est le falloff qui prend le dessus:

cgfx_part3_012.png

cgfx_part3_013.png

Par contre, si l'ambiantFallOffFactor est nul, aucun falloff pour le shader, c'est l'ambiant color qui prend le dessus:

cgfx_part3_014.png

cgfx_part3_015.png

Le tout, avec une belle transition, propre, et colorée!

Et pour finir, on réécrit le "result" en ajoutant AmbiResult au reste de l'illumination:

float3 result = (illumPointLight0 + illumPointLight1 + AmbiResult) * diffuseColorResult;

cgfx_part3_016.png

cgfx_part3_017.png

Vous voyez le petit débouché de lumière en bas à gauche?

Il commence à y avoir un petit effet de matière intéressant :sourit: .

Pour télécharger le shader -> cgfx_tuto_005.7z

:longBar:

Conclusion

Je m'arrête ici pour cette troisième partie. Je sais que le plus intéressant (texture et bump) n'a pas été abordé mais la prochaine partie sera dédiée aux textures :sauteJoie: .

En attendant, n'hésitez pas à laisser un commentaire si vous avez des questions et/ou suggestions.

A bientôt!

Dorian

:marioCours: