17. 增加对硬件光照的支持

该游戏项目一开始先创建名为light.h、material.h的两个文件。

light.h头文件用于创建灯源结构,该结构用于创建Direct3D中的灯源对象。以某种方式实现该结构,这样也可将其用于OpenGL或其他渲染系统。光源结构模仿了Direct3D中的D3DLIGHT结构,所以它们是完全兼容的。

light.h

#ifndef _UGP_LIGHT_H_
#define _UGP_LIGHT_H_

struct stLight
{
stLight()
{
type
= 0;
posX
= 0, posY = 0, posZ = 0;
dirX
= 0, dirY = 0, dirZ = 0;
ambientR
= ambientG = ambientB = ambientA = 1;
diffuseR
= diffuseG = diffuseB = diffuseA = 1;
specularR
= specularG = specularB = specularA = 0;
range
= 0;
falloff
= 0;
attenuation0
= 0;
attenuation1
= 0;
attenuation2
= 0;
theta
= 0;
phi
= 0;
}

int type;
float posX, posY, posZ;
float dirX, dirY, dirZ;
float ambientR, ambientG, ambientB, ambientA;
float diffuseR, diffuseG, diffuseB, diffuseA;
float specularR, specularG, specularB, specularA;
float range;
float falloff;
float attenuation0;
float attenuation1;
float attenuation2;
float theta;
float phi;
};

#endif

  material.h

// ========================================================================
//§ material.h 文件
//§
//§ 【描述】:定义材质结构:stMaterial
//§
// ========================================================================

#ifndef _UGP_MATERIAL_H_
#define _UGP_MATERIAL_H_

struct stMaterial
{
stMaterial()
{
emissiveR
= emissiveG = emissiveB = emissiveA = 0;
ambientR
= ambientG = ambientB = ambientA = 1;
diffuseR
= diffuseG = diffuseB = diffuseA = 1;
specularR
= specularG = specularB = specularA = 0;
power
= 0;
}

float emissiveR, emissiveG, emissiveB, emissiveA;
float ambientR, ambientG, ambientB, ambientA;
float diffuseR, diffuseG, diffuseB, diffuseA;
float specularR, specularG, specularB, specularA;
float power;
};

#endif

  

    Direct3D渲染系统需要一种创建光源和材质的方法。这可以通过为渲染系统添加三个新函数来实现。第一个函数是SetMaterial(),它的参数包括材质(stMaterial)对象,并将其施加到渲染设备上。第二个新函数是SetLight(),它的参数包括灯源对象、灯源索引(因为Direct3D和OpenGL由多达8个的硬件光源,所以索引值可以是0~7),并且调用必须的Direct3D函数用于在硬件中创建和注册光源。最后一个新函数是DisalbeLight(),它以想要关闭灯源的索引为参数。给出了新增加的CD3DRenderer和CRenderInterface类。

class CRenderInterface
{
// ...The beginning of the class functions...

// 设置材质
virtual void SetMaterial(stMaterial *mat) = 0;

// 设置并启用光源
virtual void SetLight(stLight *light, int index) = 0;

// 关闭光源
virtual void DisableLight(int index) = 0;

// ...The rest of the class's functions...
};


class CD3DRenderer : public CRenderInterface
{
// ...The beginning of the class functions...

// 设置材质
void SetMaterial(stMaterial *mat);

// 设置并启用光源
void SetLight(stLight *light, int index);

// 关闭光源
void DisableLight(int index);

// ...The rest of the class's functions...
};

  D3DRenderer.cpp源文件实现了三个和Direct3D打交道的函数。SetMaterial()函数使用材质结构中的信息创建Direct3D材质对象,并调用Direct3D设备函数SetMaterial()将该对象直接发送给Direct3D。这同样使用于SetLight()函数。SetLight()函数的参数包括光源结构,该函数使用该参数设置D3DLIGHT9对象,并将其直接发送给Direct3D。DisableLight()函数的参数包括光源索引,它将关闭注册在该索引上的所有光源。给出了这些函数的源代码。

// 设置材质
void CD3DRenderer::SetMaterial(stMaterial *mat)
{
if(!mat || !m_Device) return;

D3DMATERIAL9 m
= { mat->diffuseR, mat->diffuseG,
mat
->diffuseB, mat->diffuseA,
mat
->ambientR, mat->ambientG,
mat
->ambientB, mat->ambientA,
mat
->specularR, mat->specularG,
mat
->specularB, mat->specularA,
mat
->emissiveR, mat->emissiveG,
mat
->emissiveB, mat->emissiveA,
mat
->power
};

m_Device
->SetMaterial(&m);
}



// 设置并启用光源
void CD3DRenderer::SetLight(stLight *light, int index)
{
if(!light || !m_Device || index < 0) return;

D3DLIGHT9 l;

l.Ambient.a
= light->ambientA;
l.Ambient.r
= light->ambientR;
l.Ambient.g
= light->ambientG;
l.Ambient.b
= light->ambientB;
l.Attenuation0
= light->attenuation0;
l.Attenuation1
= light->attenuation1;
l.Attenuation2
= light->attenuation2;
l.Diffuse.a
= light->diffuseA;
l.Diffuse.r
= light->diffuseR;
l.Diffuse.g
= light->diffuseG;
l.Diffuse.b
= light->diffuseB;
l.Direction.x
= light->dirX;
l.Direction.y
= light->dirY;
l.Direction.z
= light->dirZ;
l.Falloff
= light->falloff;
l.Phi
= light->phi;
l.Position.x
= light->posX;
l.Position.y
= light->posY;
l.Position.z
= light->posZ;
l.Range
= light->range;
l.Specular.a
= light->specularA;
l.Specular.r
= light->specularR;
l.Specular.g
= light->specularG;
l.Specular.b
= light->specularB;
l.Theta
= light->theta;


if(light->type == LIGHT_POINT) l.Type = D3DLIGHT_POINT;
else if (light->type == LIGHT_SPOT) l.Type = D3DLIGHT_SPOT;
else l.Type = D3DLIGHT_DIRECTIONAL;

m_Device
->SetLight(index, &l);
m_Device
->LightEnable(index, TRUE);
}


// 关闭光源
void CD3DRenderer::DisableLight(int index)
{
if(!m_Device) return;

m_Device
->LightEnable(index, FALSE);
}

  

还需要在“defines.h”头文件里加入这几行代码:

// Light type defines. 
// 光源类型
#define LIGHT_POINT 1      // 点光源
#define LIGHT_DIRECTIONAL 2  // 方向光
#define LIGHT_SPOT 3      // 聚光灯

  


原文地址:https://www.cnblogs.com/kex1n/p/2148687.html