Direct3D光照系统

光照系统用于增强场景的真实感,描述实体的形状和立体感,启用光照系统后,Direct3D会根据材质,光源属性等信息自动计算每个顶点的颜色值,使绘制结果更加逼真

1. 光照的类型

  • Direct3D的光照模型中,光源的光由以下三个分量组成
    • 环境光(Ambient),用于模拟未处于光源直射时,照亮物体表面的反射光
    • 散射光(Diffuse),这类光到达物体表面后,将沿各方向均匀反射
    • 镜面光(Specular),这类光沿特定方向传播,到达一个表面后,严格按照另一个方向反射,形成在某个特定范围内可见的高光区域
  • Direct3D的各类光都可用D3DCOLORVALUE或D3DXCOLOR表示,使用D3DXCOLOR表示时,其中alpha值会被忽略

2. 材质

材质用于定义物体表面对各类光的反射比例,由结构D3DMATERIAL9表示

typedef struct D3DMATERIAL9
{
	D3DCOLORVALUE Diffuse;
	D3DCOLORVALUE Ambient;
	D3DCOLORVALUE Specular;
	D3DCOLORVALUE Emissive;
	float power;
}D3DMATERIAL9, *LPD3DMATERIAL9;
//Emissive设置了物体的自发光属性,power指定了高光点的锐度

3. 顶点法线

Direct3D通过顶点法线计算光纤到达表面时的入射角并进一步计算光照,由于一个顶点常常被若干平面共享,因此,常采用计算所属各面法线平均值的方法来计算顶点法线

//顶点顺时针绕序和逆时针绕序所计算出的法线方向相反
void calcNormal(D3DXVECTOR3 *p0,
				D3DXVECTOR3 *p1,
				D3DXVECTOR3 *p2,
				D3DXVECTOR3 result)
{
	D3DXVECTOR3 u = *p1 - *p0;
	D3DXVECTOR3 v = *p2 - *p0;

	D3DXVec3Cross(out, &u, &v);
	D3DXVec3Normalize(out, out);
}
  • 共享顶点的顶点法线
    \(\vec{v_{n}} = \frac{1}{n}\left ( \vec{n_{0}} + \vec{n_{1}} + \cdots + \vec{n_{n}} \right )\)
  • 由于在变换过程中,顶点法线有可能不再是规范化的,因此最好将绘制状态设置为在变化完成后规范化所有法线
Device->SetRenderStaes(D3DRS_NORMALIZENORMALS, true);

4. 光源

Direct3D支持三种类型的光源

  • 点光源(D3DLIGHT_POINT):除了基本的光照信息,只有位置信息,向所有方向均匀发出光线
  • 方向光(D3DLIGHT_DIRECTIONAL):没有位置信息,只有方向信息,发出的光沿该方向平行传播
  • 聚光灯(D3DLIGHT_SPOT):三种光源中最复杂的,与电筒类似,有位置信息,方向信息,还有附加的角度信息,描述光锥的角度
  • D3DLIGHT9结构用于描述光源
typedef struct D3DLIGHT9
{
	D3DLIGHTTYPE Type;
	D3DCOLORVALUE Diffuse;
	D3DCOLORVALUE Specular;
	D3DCOLORVALUE Ambient;
	D3DVECTOR Position;
	D3DVECTOR Direction;
	float Range; //光线传播的最大距离,对方向光无意义
	float Falloff; //聚光灯内锥形到外锥形的光强衰减
	float Attenuation0;
	float Attenuation1;
	float Attenuation2;
	float Theta; //聚光灯内锥形角度
	float Phi; //聚光灯外锥形角度
}D3DLIGHT9, *LPD3DLIGHT;
  • 三个Attenuation参数描述了光强随距离衰减的方式,仅用于点光源和聚光灯,具体计算公式为
    \(attenuation = \frac{1}{A_{0} + A_{1}\cdot D + A_{2} \cdot D^{2}}\)

5. 实例

方向光
//Setup light
	D3DLIGHT9 light1;
	::ZeroMemory(&light1, sizeof(light1));
	light1.Type = D3DLIGHT_DIRECTIONAL;
	light1.Ambient = WHITE * 0.3f;
	light1.Diffuse = RED;
	light1.Specular = WHITE * 0.7f;
	light1.Direction ={ 1.0f, 0.0f, 0.0f };

	pD3DDEV->SetLight(0, &light1);
	pD3DDEV->LightEnable(0, true
  • 效果
    Directional_Light
点光源
//Set Light position
		float posinit = 0.0f;
		D3DXMATRIX position = (&posinit);
		position._11 = 3.0f;
		position._22 = 3.0f;
		position._33 = 3.0f;
		D3DXMATRIX rotate;

		static float y = 0.0f;
		D3DXMatrixRotationY(&rotate, y);
		y += DeltaTime;

		//Set Light
		D3DLIGHT9 lt;
		::ZeroMemory(&lt, sizeof(lt));
		lt.Type = D3DLIGHT_POINT;
		lt.Ambient = WHITE * 0.3f;
		lt.Diffuse = RED;
		lt.Specular = WHITE * 0.7f;
		lt.Range = 100.0f;
		lt.Attenuation0 = 1.0f;
		lt.Attenuation1 = 0.0f;
		lt.Attenuation2 = 0.0f;

		lt.Position = D3DXVECTOR3(position._11 * sinf(y), position._22 , position._33* cosf(y));

		pD3DDEV->SetLight(0, &lt);
		pD3DDEV->LightEnable(0, true);
  • 效果
    Point Light
聚光灯
//Set Light
		D3DLIGHT9 light;
		static float posx = 0.0f;
		static float posy = 0.0f;
		D3DXVECTOR3 dir = D3DXVECTOR3(posx, posy, 1.0f);

		light.Type = D3DLIGHT_SPOT;
		light.Ambient = WHITE * 0.3f;
		light.Diffuse = RED;
		light.Specular = WHITE * 0.7f;
		light.Attenuation0 = 1.0f;
		light.Attenuation1 = 0.0f;
		light.Attenuation2 = 0.0f;
		light.Position = D3DXVECTOR3(0.0f, 0.0f, -3.0f);
		light.Falloff = 5.0f;
		light.Range = 100.0f;
		light.Phi = D3DX_PI / 2.5;
		light.Theta = D3DX_PI / 45;
		if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )
			posx -= 0.5f * DeltaTime;
		if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )
			posx += 0.5f * DeltaTime;
		if( ::GetAsyncKeyState(VK_UP) & 0x8000f )
			posy += 0.5f * DeltaTime;
		if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )
			posy -= 0.5f * DeltaTime;
		light.Direction = dir;

		pD3DDEV->SetLight(0, &light);
		pD3DDEV->LightEnable(0, true);
  • 效果
    Spot Light

Written with StackEdit.

posted @ 2014-10-05 01:08  current  阅读(388)  评论(0编辑  收藏  举报