【译】XNA Shader 程序设计(二)

XNA Shader 程序设计

教程2 - 漫反射


 

大家好,今天我们将在教程一的基础上继续学习,在光照算式中加上漫反射光。

 

漫反射光

 

环境光计算等式为:

I = Aintensity * Acolor

 

漫反射基于这个等式,添加了一道有方向的光线:

I = Aintensity x Acolor + Dintensity x Dcolor x N.L (2.1)

 

通过计算式,你可以看到我们仍然使用了环境光,但添加了两个变量,分别表示漫反射光的光强和颜色,还添加了两个向量NLL表示光照方向,N表示表面法线。

 

我们可以认为漫反射表现了一个表面如何反射光线。法线方向N和光线方向L的夹角越小,表面反射的光就越强。

 


 

LN平行,反射光最强,当L与物体表面平行,反射光最弱。

 

我们可以通过计算向量的点积(或叫数量积)来得到LN的夹角。这条计算向量夹角的法则定义如下:N.L = |N| x |L| x cos(a)|N|是向量N的长度,|L|是向量L的长度,cos(a)表示两向量的夹角。

 

实现shader

我们需要三个全局变量

 

float4x4    matWorldViewProj;
float4x4    matInverseWorld;
float4      vLightDirection;

 

我们仍然需要教程一中介绍的worldviewprojection矩阵,同时需要添加InverseWorld矩阵来变换法线,添加vLightDirection表示光线方向。

 

我们仍需为顶点着色器定义OUT结构体,从而把数据传给像素着色器:
struct OUT 

    float4 Pos: POSITION; 
    float3 L:    TEXCOORD0; 
    float3 N:    TEXCOORD1; 
};

 

我们把位置Pos,光线方向L,法线N存在不同的寄存器中。TEXCOORDn可以用来表示任意值,在我们没有使用贴图的情况下,我们用它来存储向量。

 

OK,下面是顶点着色器:
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; 
}

 

我们从模型文件中获得顶点和法线的数据然后传递给shader,然后变换位置坐标,归一化光线方向,变换并归一化物体表面的法线。

 

然后,在像素着色器中,把TEXCOORD0的值给LTEXCOORD1的值给N,寄存器的值来自顶点着色器。下面在像素着色器中实现算式2.1

 

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)); 
}

 

 

下面是这个shadertechnique

technique DiffuseLight 

    pass P0 
    { 
        VertexShader = compile vs_1_1 VertexShader(); 
        PixelShader = compile ps_1_1 PixelShader(); 
    } 
}

 

 

OK,这就是漫反射!下载代码调试一下吧。

 

Download: Executable + Source

 

posted @ 2009-04-23 23:54  柒笑侠  阅读(642)  评论(0编辑  收藏  举报