光照系统用于增强场景的真实感,描述实体的形状和立体感,启用光照系统后,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}} ight )) - 由于在变换过程中,顶点法线有可能不再是规范化的,因此最好将绘制状态设置为在变化完成后规范化所有法线
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
- 效果
点光源
//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(<, 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, <);
pD3DDEV->LightEnable(0, true);
- 效果
聚光灯
//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);
- 效果
Written with StackEdit.