XNA Meeting point

Multi language XNA tutorials meeting point

Accueil
English
Français
Español
Search
Archive (EN)
Archive (FR)
Archivo (ES)
Almacenamiento
Física : tutorial 1
Shaders : tutorial 1
Shaders : tutorial 2
Luz Difusa
by Petri Wilhelmsen 

 

Hola, y bien venidos para el tutorial numero 2 de mi serie sobre la programación de los shaders en XNA. Ahora vamos a trabajar com el tutorial 1 para hacer una ecuación de encendimiento más interesante, implementando la luz difusa.
 
Luz difusa :
 
La luz ambiante utilizaba la ecuación siguiente :
I = Aintensity * Acolor
 
La luz difusa utiliza esta ecuación, pero también utiliza una luz  directional en su ecuación:
I = Aintensity x Acolor + Dintensity x Dcolor x N.L (2.1)
 
Se puede notar que todavía se utiliza la luz ambiante, pero se necesitan dos variables más para describir el color y la intensidad de la luz difusa, y dos vectores N y L para describir la dirección de la luz L comparada a la normal a la superficie N.
 
Se puede imaginar la luz difusa como una valor que indica en qué proporción una superficie refleja la luz. La luz que está reflejada será más fuerte y visible cuando el ángulo entre la Normal N y la direccón de la luz se hace más y más pequeño.
 

 
Si L es paralela con N, la luz será más reflejada, y si L está paralela con la superficie, la luz no será reflejada mucho.
 
Para obtener el ángula entre L y N, se puede utilizar el producto escalar. Esta regla se utiliza para encontrar el ángulo entre dos vectores dados y está definida así :
N.L = |N| x |L| x cos(a)      con |N| la longitud del vector N, |L| la del vector L y cos(a) es el cosine del ángulo entre los dos vectores.
 
Implementación del shader :
 
Necesitamos tres variables globales :
 
float4x4    matWorldViewProj;
float4x4    matInverseWorld;
float4      vLightDirection;
 
Todavía necesitamos la matriz worldviewprojection del tutorial uno, pero también tenemos la matriz matWorld que está utilizada para calcular una normal correcta, relacionada con la matriz world, y una dirección de la luz vLightDirection que explica en que dirección se mueve la luz.
 
También necesitamos definir la estructura OUT para nuestro vertex shader, para hacer la ecuación correcta de la luz en el pixel shader :

struct OUT
{

    float4 Pos: POSITION;
    float3 L:    TEXCOORD0;
    float3 N:    TEXCOORD1;
};
 
Aquí tenemos la posición Pos, la dirección de la luz L y la normal N almacenadas en diferentes registros. Se puede utilizar TEXCOORDn can be used for cualquieras valores, y como todavía no utilizamos ningunas coordenedas de texturas, podemos facilmente utilizar esos registros para almacenar nuestros dos vectores.
 
Ahora es el momento para nuestro 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;
}
 
Tomemos la posición desde el archivo del modelo, y también la normal, y los damos al shader. Con esos y las variables globales, podemos transmormar la posición Pos, normalizar la dirección de la luz y transformar+normalizar la normal de la superficie.
 
Después, en el pixel shader tomemos las valores de TEXCOORD0 y las ponemos en L, y las valores de TEXCOORD1 y las ponemos en N. Estos registros son llenos por vertex shader. Después implementamos la ecuación 2.1 en el 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));
}
 
 
La técnica para este shader es la siguiente :
 
technique DiffuseLight
{
    pass P0
    {
        VertexShader = compile vs_1_1 VertexShader();
        PixelShader = compile ps_1_1 PixelShader();
    }
}
 
 
Ya estamos terminados com la luz difusa ! Ahora pueden cargar el ejemplo y jugar un poco hasta que entienden lo todo, completamente. :) Espero que puden sentir el poder de los shaders ahora y como utilizarlos en sus aplicaciones !
 
Se puede notar que no he utilizado effect.commitChanges(); en el código. Si quieren dibujar muchos objetos utilizando este shader, necesitarán añadir eso en pass.Begin() .