XNA Meeting point

Multi language XNA tutorials meeting point

Accueil
English
Français
Español
Search
Archive (EN)
Archive (FR)
Stockage
Physique : tutorial 1
Shaders : tutorial 1
Shaders : tutorial 2
Shaders : tutorial 3
Shaders : tutorial 4
Planètes : Partie I
Publier : partie 1
Archivo (ES)
Lumière diffuse
by Petri Wilhelmsen 

 

Bonjour et bienvenue pour ce second tutorial de ma série sur le programmation de shaders dans XNA. Aujourd'hui, nous allons travailler sur le premier tutorial, afin de mettre en place un éclairage à l'aide d'une équation un peu plus intéressante, en implémentant un éclairage diffus.
 
Lumière diffuse :
 
Voici l'équation de la lumière ambiante :
I = Aintensity * Acolor
// A => Ambiante
 
L'éclairage diffus est écrit selon cette équation, qui ajoute une lumière directionnelle :
I = Aintensity x Acolor + Dintensity x Dcolor x N.L (2.1)
// D => Diffuse
 
Avec cette équation, vous pouvez voir que nous utilisons toujours la lumière ambiante, mais on a besoin de deux autres variables pour décrire la couleur et l'intensité de la lumière diffuse, et deux vecteurs N et L pour décrire la direction de la lumière, L, et la normale à la surface, N.
 
On peut imaginer la lumière diffuse comme une valeur indiquant combien la surface réfléchit la lumière. La lumière qui est réfléchie sera plus forte et plus visible quand l'angle entre la normale N et la direction de la lumière L tend à diminuer.
 

 
Si L et N sont colinéaires, la lumière sera réfléchie au maximum, et si L est orthogonal à N, la lumière réfléchie sera minimum.
 
Pour obtenir l'angle entre L et N, on peut utiliser le produit vectoriel ou le produit scalaire. Cette règle est utilisée pour trouver l'angle entre deux vecteurs donnés et peut être définit comme ceci :
N.L = |N| x |L| x cos(a) 
où |N| est la norme de N, |L| celle de L et a est l'angle entre les deux vecteurs.
 
Implémentation du shader
 
On a besoin de trois variables globales :
 
float4x4    matWorldViewProj;
float4x4    matInverseWorld;
float4      vLightDirection;
 
On a toujours la matrice worldviewprojection du premier tutorial, mais en plus, on utilise la matrice InverseWorld pour calculer une normale correcte en relation avec la matrice world, et une direction de la lumière vLightDirection qui explique quelle est la direction de la lumière.
 
On a aussi besoin de définir la structure OUT pour notre vertex shader, afin de réaliser l'équation correcte de la lumière dans le pixel shader :

struct OUT
{

    float4 Pos: POSITION;
    float3 L:    TEXCOORD0;
    float3 N:    TEXCOORD1;
};
 
Nous avons ici la position Pos, la direction L de la lumière et la normale N stockée dans différents registres. TEXCOORDn peut être utilisé pour n'importe quelles valeurs, et comme nous n'utilisons pas de coordonnées de texture, on peut facilement utiliser ces registres comme stockage pour nos deux vecteurs.
 
Ok, il est temps de passer au vertex shader :

OUT VertexShader( float4 Pos: POSITION, float3 N: NORMAL )
{
    OUT Out = (OUT) 0;
    Out.Pos = mul(Pos, matWorldViewProj);
    Out.L = normalize(vLightDirection);
    Out.N = normalize(mul(matInverseWorld, N));
    return Out;
}
 
Nous prenons la position du fichier model, ainsi que la normale, et nous les donnons au shader. En se basant sur ces données et sur nos variables globales, on peut transformer la position Pos, normaliser la direction de la lumière et transformer ainsi que normaliser la normale à la surface.
 
Ensuite, dans le pixel shader, on prend les valeurs de TEXCOORD0 et on les met dans L, et les valeurs de TEXCOORD1 et on les met dans N. Ces registres sont remplis par le vertex shader. Puis, on implémente l'équation 2.1 dans le pixel shader :
 
float4 PixelShader(float3 L: TEXCOORD0, float3 N: TEXCOORD1) : COLOR
{   
    float Ai = 0.8f;
    float4 Ac = float4(0.075, 0.075, 0.2, 1.0);
    float Di = 1.0f;
    float4 Dc = float4(1.0, 1.0, 1.0, 1.0);
    return Ai * Ac + Di * Dc * saturate(dot(L, N));
}
 
 
Voici la technique pour ce shader :
 
technique DiffuseLight
{
    pass P0
    {
        VertexShader = compile vs_1_1 VertexShader();
        PixelShader = compile ps_1_1 PixelShader();
    }
}
 
 
Ok, ca y est pour la lumière diffuse ! Téléchargez le source et jouez un peu avec, pour le mieux le comprendre :) J'espère que ce début vous montre le pouvoir des shader maintenant, et aussi comment les utiliser dans vos propres applications !
 
NOTE:
Vous pouvez avoir remarqué que je n'ai pas utilisé effect.commitChanges(); dans ce code. Si vous rendez plusieurs objets utilisant ce shader, vous devez l'ajoutez dans la parite pass.Begin(), afin que les changements soient affectés lors de la passe actuelle, et non pas dans celle qui suit. Cela doit être fait si vous ajustez des paramètres à l'intérieur de la passe.