Direct3D 10教程6:光照

来源:互联网 发布:精通java设计模式 编辑:程序博客网 时间:2024/05/21 15:08

概览

在前面的教程中,因为所有物体都是以相同的方式被光照亮,因此还不够真实。本教程将介绍简单的光照概念以及如何施加光照,这个技术将使用Lambert光照模型。

这个教程的会在前一个示例的基础上包含一个光源,光源链接在轨道运行的立方体上,光照的效果可以在中央立方体表面上看到。

程序截图

源代码

(SDK root)\Samples\C++\Direct3D10\Tutorials\Tutorial06

光照

在本教程中将介绍最简单的光照类型:Lambert光照。Lambert光照具有相同的光照强度而不考虑离开光源的距离。当光照射到表面时,反射光的强度根据光在表面上的入射角大小进行计算。当光线垂直射向表面,反射回所有光照,具有最大的光强。当入射角变大时,光的强度也会减弱。

要计算表面的光照强度,必须计算光照方向和表面法线之间的夹角。法线定义为垂直于平面的一个矢量,角度的计算只需使用一个简单的点乘即可,返回的结果是光照方向矢量在法线上的投影长度。入射角越大,投影长度越短,这样,我们就有一个正确的方法调整漫反射光照。

Lambert光照

本教程使用的光源接近于单向光,表示光源的矢量决定了光线的方向。因为这是一个近似,所以物体的位置无关紧要,我们认为光照方向都是一样的。这种光源的一个例子就是太阳,在一个场景中,太阳光总是被认为是同一方向的。

另一种类型的光源是点光源,从光源中心发出光线;还有一种是聚光灯,它发出的光线具有方向性但又不是均匀照射所有物体。

初始化光照

在本教程中,我们使用两个光源。一个静止放置在立方体的上后方,另一个绕着它旋转。

因为光照是由shader进行计算的,所以必须首先声明变量然后将它们与technique绑定。在本例中,我们只需光照方向和颜色值。第一个光源为灰色不移动,第二个是一个沿轨道绕行的红色光源。


1
2
3
4
5
6
7
8
9
10
11
// Setup our lighting parameters
D3DXVECTOR4 vLightDirs[2] =
{
    D3DXVECTOR4( -0.577f, 0.577f, -0.577f, 1.0f ),
    D3DXVECTOR4( 0.0f, 0.0f, -1.0f, 1.0f ),
};
D3DXVECTOR4 vLightColors[2] =
{
    D3DXVECTOR4( 0.5f, 0.5f, 0.5f, 0.0f ),
    D3DXVECTOR4( 0.5f, 0.0f, 0.0f, 0.0f )
};

第二个光源还像上一个教程中的立方体那样旋转,施加的矩阵会改变光照方向,让光照总是朝向中心。注意,D3DXVec3Transform方法用来在矢量上乘以矩阵。在前面的教程中,我们只是将变换矩阵乘进世界矩阵中,然后传递到shader用于变换;但本例中基于简化的考虑,我们在CPU中对光源进行世界变换。


1
2
3
4
5
//rotate the second light around the origin
D3DXMATRIX mRotate;
D3DXVECTOR4 vOutDir;
D3DXMatrixRotationY( &mRotate, -2.0f*t );
D3DXVec3Transform( &vLightDirs[1], (D3DXVECTOR3*)&vLightDirs[1], &mRotate );

光照方向和颜色都传递到shader中,对应的变量被调用并设置,参数被传递。


1
2
3
4
5
//
// Update lighting variables
//
g_pLightDirVariable->SetFloatVectorArray( (float*)vLightDirs, 0, 2 );
g_pLightColorVariable->SetFloatVectorArray( (float*)vLightColors, 0, 2 );

在像素着色器中绘制光照

设置了所有数据我们就可以计算每一个像素的lambert光照因子了,使用的是上面提到过的点乘规则。

有了点乘结果后,就可以将这个结果乘以光照颜色计算光照的影响了。这个值被传递到saturate方法,这个方法将结果限定在[0, 1]区间。最后,两个光源的效果会相加获得最终的像素颜色。

物体表面材质并没有考虑在光照计算中,表面的最终颜色只包含光照颜色。


1
2
3
4
5
6
7
8
9
10
11
12
13
//
// Pixel Shader
//
float4 PS( PS_INPUT input) : SV_Target
{
    float4 finalColor = 0;
    //do NdotL lighting for 2 lights
    for(inti=0; i<2; i++)
    {
        finalColor += saturate( dot( (float3)vLightDir[i],input.Norm) * vLightColor[i] );
    }
    returnfinalColor;
}

经过像素着色器的处理,像素的颜色就被光照调制,你可以在中央立方体表面看到光照效果。因为本例中同一表面的法线方向相同,所以同一表面的光照强度相同。漫反射(Diffuse)光照是一个非常简单容易的光照模型,你可以使用更复杂的光照模型实现更加真实的效果。

0 0