谈到光照,涉及到的内容就包括光照模型和光源类型。
一、首先说一下光照模型。
由于现在的计算机的计算能力有限,无法真正实时实现现实中复杂的光照效果,所以在模拟现实光照时,我们不得不简化光照计算,经过对现实光照进行分类,最终抽象出4个光照模型,分别是:环境光、漫反射、镜面反射、自发光。
1、环境光
环境光就是场景中物体表面产生的反射光的统一光照,环境光没有位置和方向,并且值为常量。
在D3D中设置环境光的方式如下:
C#
1
pDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(100, 100, 100));
2、漫反射
漫反射是自然界中最普遍的光照现象,它由光照方向以及顶点法向量计算得到,每个顶点的漫反射光颜色都要单独计算,所以漫反射计算比较耗时,但是这种牺牲时值得的,这能体现物体的三维深度。
3、镜面反射
顾名思义,就是发生在镜面上的光反射现象,这里的镜面就是光滑的物体表面,镜面反射的计算量比漫反射计算量还要大得多,所以在D3D中镜面反射是默认关闭的,设置它的开关状态的方法如下:
C#
1
pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
4、自发光
自发光就是物体自己发出的光,这是通过对物体材质Emissive属性设置来实现的,自发光不会影响到其他物体。
二、光源
光源类型包括:方向光、点光源、聚光灯。
这些光源类型被定义在枚举类型D3DLIGHTTYPE中,定义如下:
C#
1
2
3
4
5
6
7
Typedef enum _D3DLIGHTTYPE
{
D3DLIGHT_POINT=1,//点光源
D3DLIGHT_SPOT=2,//聚光灯
D3DLIGHT_DIRECTIONAL=3,//方向光
D3DLIGHT_FORCE_DWORD=0x7fffffff
} D3DLIGHTTYPE;
1、点光源
点光源具有颜色与位置属性,没有方向。光照强度会随着距光源中心的距离变大衰减。在具体应用中,可以利用点光源来模拟电灯或精灵。在D3D中设置点光源的方式如下:
C#
1
2
3
4
5
6
7
8
9
10
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_POINT;
light.Position = D3DXVECTOR3(1, 1, 1);
light.Range = 10.0f;
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
light.Attenuation0 = 1.0f;//恒定变化
pDevice->SetLight(0, &light);
2、聚光灯
聚光灯具有颜色、方向和位置。聚光灯由内锥与外锥组成,光照强度由内锥到外锥逐渐衰减。在应用中可以模拟探照灯。由于聚光灯计算量比较大,所以尽量少使用。D3D中设置光源方式如下:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_SPOT;
light.Position = D3DXVECTOR3(0, 0, 0);
light.Direction = D3DXVECTOR3(1, 1, 1);
light.Range = 100.0f;
light.Diffuse.r = light.Ambient.r = 0.5f;
light.Diffuse.g = light.Ambient.g = 0.5f;
light.Diffuse.b = light.Ambient.b = 0.5f;
light.Phi = D3DX_PI / 4.0;
light.Theta = D3DX_PI / 8.0f;
light.Falloff = 1.0f;
pDevice->SetLight(1, &light);
3、方向光
方向光具有颜色、方向属性,没有位置。方向光不存在范围,所以,计算量在所以光源中最小。在应用中可以模拟太阳光。在D3D中设置光源的方式如下:
C#
1
2
3
4
5
6
7
8
9
10
D3DLIGHT9 light;
ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
D3DXVECTOR3 dir;
Dir = D3DXVECTOR3(-1, -1, -1);
D3DXVec3Normalize((D3DXVECTOR3*)&light.Direction, &dir);
pDevice->SetLight(2, &light);
这些就是光照的内容,下面来说一下材质。
在光照的计算中,光照和材质是必需的,缺一不可。那什么是材质呢?
材质就是物体的质地,在D3D中的就是物体对光的吸收与反射特性。
在D3D中结构体D3DMATERIAL9表示材质信息,其定义如下:
C#
1
2
3
4
5
6
7
8
Typedef struct D3DMATERIAL9
{
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Ambient;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Emissive;
Float Power;
} D3DMATERIAL9, *LPD3DMATERIAL9;
其中的成员变量Diffuse、Ambient、Specular分别表示物体表面的漫反射光、环境光、镜面反射光的反射系数,Emissive表示物体的自身发光度,Power表示镜面反射指数。
如果用Id、Ia、Is、Ie分别表示漫反射光、环境光、镜面反射光和自发光的亮度,那么物体顶点最终的颜色亮度为:
It = Id + Ia + Is + Ie;
C#
1
HRESULT SetMaterial(CONST D3DMATERIAL *pMatrial);
函数用来设置当前材质。
下面举例来说明物体材质的设置:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
D3DMATERIAL9 mtl;
ZeroMemory(&mtl, sizeof(mtl));
//漫反射光
mtl.Diffuse.r = 0.5f;
mtl.Diffuse.g = 0.5f;
mtl.Diffuse.b = 0.5f;
mtl.Diffuse.a = 1.0f;
//环境光
mtl.Ambient.r = 0.2f;
mtl.Ambient.g = 0.4f;
mtl.Ambient.b = 0.8f;
mtl.Ambient.a = 1.0f;
//镜面反射光
mtl.Specular.r = 1.0f;
mtl.Specular.g = 1.0f;
mtl.Specular.b = 1.0f;
mtl.Specular.a = 1.0f;
mtl.Power = 25.0f;
//自发光
mtl.Emissive.r = 0.3f;
mtl.Emissive.g = 1.0f;
mtl.Emissive.b = 0.6f;
mtl.Emissive.a = 1.0f;
gDevice->SetMaterial(&mtl);
gDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
好,这一讲就到这里,回头看一下,离上次更新已经快一个世纪了(汗颜,不过确实最近忙得要死),不过同样还是希望大家,编程愉快。ZXGoto与大家一起学习进步。
下面的例子是在上一篇中的太阳系项目基础上改的,运行效果如图: