DirectX 入门[04] 创建和使用光照

来源:互联网 发布:eia数据 api 编辑:程序博客网 时间:2024/05/14 12:42

原文在MS DirectX的帮助文档中:
        DirectX Graphics ->Direct3D 9 ->Tutorials and Samples->Tutorials->Direct3D Tutorials
        ->Tutorial 4: Creating and Using Lights

        翻译本文主要为了记录自己的学习过程, 并希望能结交一些学习DirectX的朋友. 由于该指南是在前三个指南的基础上编写的, 之前阅读后没有及时把内容翻译下来, 以后陆续补上.

        由于英文水平很菜有些语句翻译不准确, 各位看了见谅, 如果有错误和不足之处欢迎指出.   (翻译中有些语句我已经省去, 并加入了一些注释, 为了养成一些习惯我对代码进行了一点点地修改.)

 

正文:

        Direct3D光照使3D对象的真实感大大增加。当使用光照,场景中每一个几何对象将根据其位置和使用的光照类型被照亮。本例子介绍光照和材质两个话题。

代码路径:
(SDK root)/Samples/C++/Direct3D/Tutorials/Tut04_Lights
步骤1 -- 初始化场景中的几何体
       使用光照其中一个要求是每一个平面必须具有法线。因此,光照程序中使用与以往不同的顶点结构类型。新定义的顶点结构具有3D坐标和平面法线。平面法线用于Direct3D内部的光照计算。
struct CUSTOMVERTEX
{
    D3DXVECTOR3 position;  //3D顶点坐标向量
    D3DXVECTOR3 normal;    //顶点所在平面的法线向量
};
//自定义自由顶点格式(FVF)
#define D3DFVF_CUSTOMVERTEX     (D3DFVF_XYZ | D3DFVF_NORMAL)
 
       定义了正确的顶点格式后,光照例子程序调用应用程序定义用于创建圆筒的函数InitGeometry。首先需要创建顶点缓冲存储存储圆筒的顶点。
//创建顶点缓冲, g_pVB为顶点缓冲的接口指针 IDirect3DVertexBuffer9*
If(FAILED(g_pd3dDevice->CreateVertexBuffer(50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX),
D3DPOOL_DEFAULT, &g_pVB, NULL) )
    return E_FAIL;
 
下一步需要用圆筒的顶点数据填充顶点缓冲,注意以下代码,对每一个顶点计算其坐标与法线向量。
 
CUSTOMVERTEX* pVertices;
if( FAILED(g_pVB->Lock(0, 0, (void**)&pVertices, 0) ) )
        return E_FAIL;
    
     //sin(x+y) = sin(x)*cos(y) + cos(x)*sin(y);
     //cos(x+y) = cos(x)*cos(y) - sin(x)*sin(y);
    FLOAT fDelta = (FLOAT)(2*D3DX_PI/(50-1));
    FLOAT fDeltaSin = sinf(fDelta);
    FLOAT fDeltaCos = cosf(fDelta);
    FLOAT fSin = 0.0f;
    FLOAT fCos = 1.0f;
    FLOAT fTmpSin = 0.0f;
    for(DWORD i=0; i<49; i++)
    {
       pVertices[i<<1].position = D3DXVECTOR3(fSin, -1.0f, fCos);
       pVertices[i<<1].normal = D3DXVECTOR3(fSin, 0.0f, fCos);
       pVertices[(i<<1)+1].position = D3DXVECTOR3(fSin, 1.0f, fCos);
       pVertices[(i<<1)+1].normal = D3DXVECTOR3(fSin, 0.0f, fCos);
       fTmpSin = fSin;
       fSin = fSin * fDeltaCos + fCos * fDeltaSin;
       fCos = fCos * fDeltaCos - fTmpSin * fDeltaSin;
    }
    //防止出现累计误差
    pVertices[98].position = D3DXVECTOR3(fSin, -1.0f, fCos);
    pVertices[98].normal = D3DXVECTOR3(fSin, 0.0f, fCos);
    pVertices[99].position = D3DXVECTOR3(0.0f, 1.0f, 1.0f);
    pVertices[99].normal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
       使用圆筒坐标填充顶点缓冲后,即可使用它进行渲染。但是,在渲染圆筒之前首先要设定场景中的材质与光源。
 
步骤二 --- 设置材质与光源
       在Direct3D中使用光照,你需要创建一个或多个光源。要决定几何物体反射的颜色,你需要创建用于渲染几何物体的材质。渲染场景之前,光照程序调用设置材质和方向光源的函数SetupLights。
 
创建材质:
       材质规定几何物体表面受到光照时反射的颜色。下段代码使用D3DMATERIAL9结构创建一个黄色的材质。
D3DMATERIAL9 material;
ZeroMemory(&material, sizeof( D3DMATERIAL9));
    material.Diffuse.r = material.Ambient.r = 1.0f;
    material.Diffuse.g = material.Ambient.g = 1.0f;
    material.Diffuse.b = material.Ambient.b = 0.0f;
    material.Diffuse.a = material.Ambient.a = 1.0f;
g_pd3dDevice->SetMaterial( &material );
将材质的漫反射色和环境色设置为黄色。调用SetMaterial函数将该材质用于Direct3D设备的场景渲染。SetMaterial函数仅接受待设置材质的地址作为参数。调用该函数后,每一个图元使用刚设定的材质进行渲染,直到下一次调用SetMaterial指定不同的材质。(因此,如果场景中包含多个不同材质的几何体时,需要将几何体按材质归类后进行渲染。)
 
创建光源:
       Direct3D中具有三种可用的光源类型:
l         点光源
l         方向光源
l         聚光灯
此例子三创建一个方向光源(光线方向一致),改代码使得光源方向随时间不断调整。
下一段代码使用D3DLIGHT9结构创建一个方向光源。
D3DXVECTOR3   vecDir;
D3DLIGHT9     light;
ZeroMemory(&light, sizeof(D3DLIGHT9));
light.Type = D3DLIGHT_DIRECTIONAL;     //光源类型:方向光源
light.Diffuse.r = 1.0f;     //设置光源漫反射色为白色。R, G, B取值[0.0f,1.0f]
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
//设置光源方向
vecDir = D3DXVECTOR3( cosf(timeGetTime()/360.0f),
0.0f,
sinf(timeGetTime()/360.0f) );
//归一化方向向量
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
light.Range = 1000.0f;          //设置光源能照射到的最远距离
调用D3DXVec3Normalize归一化指定光源方向的向量。
光照范围指定该方向光源光照能影响的最远距离。此成员不影响方向光源。
下面的代码调用SetLight设置光源。
g_pd3dDevice->SetLight(0, TRUE);
SetLight函数的第一个参数指定光源索引,(注意:如果该索引相关光源已存在,调用该函数将用新的光源覆盖原有的光源。)第二个参数指定定义该光源的结构指针。
下面代码开启0号光源。
g_pd3dDevice->LightEnable(0, TRUE);
LightEnable函数第一个参数指定光源索引,第二个参数指定开启光源(TRUE)或关闭光源(FALSE)。
下面代码调用Direct3D设备接口的SetRenderState方法开启光照计算。
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
SetRenderState函数第一个参数为需要改变设备状态变量,第二个参数设置该状态的值。
最后再次调用SetRenderState开启环境光(环境光使场景中每一个物体接受相同环境光照)。
g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0x00202020);
上面的代码为场景设置灰色的环境光。
 
原创粉丝点击