1.光照的组成
为了增强所绘场景的真实感,我们可以为场景增加光照,使用光照时,我们无需自行指定顶点的颜色值,依据光源类型,材质,以及物体表面相对于光源的朝向,计算出每个顶点的颜色值,
光照由以下三种类型光组成,
环境光(Ambient Light)
这种类型的光经其它表面反射到物体表面,并照亮整个场景,例如,物体的一些部份被一定程度的照亮,但物体并没有处于光源的直接照射下,物体之所以会被照亮,是由于其它物体对光的反射,
漫射光(Diffuse Light)
这种类型的光沿着特定的方向传播,当它到达一些表面时,将沿着各个方向反射,由于漫射光沿所有方向均匀反射,无论从哪个方面观察,,表面亮度都是相同的,采用这种模形时,无须考虑观察者的位置,仅需考虑光传播的方向以及表面的朝向,
镜面光(Specular Light)
这种类型的光沿特定方向传播,当此类型光到达一个表面时,将严格地沿着另一个方向反射,从而形成只能在一定角度内才能观察到的高亮度照射,
每种光的结构都可以用结构D3DCOLORVALUE或是D3DXCOLOR来表示,描述光线的颜色时,D3DXCOLOR类中的Alpha值都将被忽略
2.材质
在现实世界中,我们观察到的物体的颜色是由该物体所反射的光的颜色决定的,例如,一个纯红色的球体,反射了全部的红色入射光,并吸收了所以非红色的光,所以该球体表现为红色,D3D通过定义物体的材质(materials)来模拟这种现像,材质允许我们定义物体表面上对种种颜色光的反射比例,
材质用结构D3DMATERIAL9表示
typedef struct D3DMATERIAL9
{
D3DCOLORVALUE Diffuse; //指定材质对漫射光的反射率
D3DCOLORVALUE Ambient; //指定材质对环境光的反射率
D3DCOLORVALUE Specular;//指定材质对镜面光的反射率
D3DCOLORVALUE Emissive;//用于增强物体的亮度,使之看起起来可以自己发光
float Power; //指定镜面高光点的锐度,值越大,高光点的锐度越大
}D3DMATERIAL9,*LPD3DMATERIAL9;
例如,假如有一个红色的球体,我们想将该球体的材质的属性定义只反射红色光,而吸走所有其它颜色的光,
D3DMATERIAL9 red;
ZeroMemory(&red,sizeof(red));
red.Diffuse = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Ambient = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Specular = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Emissive = D3DXCOLOR(0.0f,0.0f,0.0f,1.0f); //no emission
red.Power = 5.0f
如果用一个只能发出蓝色的光,来照射一个红色的球体,该物体无法被照亮,当一个物体吸收了所有光时,便呈现了黑色, 反之如果一个物体能够100%地反射红色光,绿色光,和蓝色光,它将呈成为白色
顶点结构中不含有材质属性,但我们必须对当前材质进行设定,下面这个函数可以用来对当前材质进行设定: IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9 *pMaterial)
3.顶点法线
1.面法线
2.顶点法线
4.光源
1.点光源
2.方向光
3.聚光灯
typedef struct D3DLIGHT9
{
D3DLIGHTTYPE Type; //光源类型
D3DCOLORVALUE Diffuse; //该光源所发出的漫射光的颜色
D3DCOLORVALUE Specular; //该光源所发出的镜面光的颜色
D3DCOLORVALUE Ambient; //该光源所发出的环境光的颜色
D3DVECTOR Position; //用于描述光源在世界坐标系中位置的向量,对于方向光,该参数无意义
D3DVECTOR Direction; //描述光在世界坐标系中传播方向的向量,对于点光源,该参数无意义
float Range; //光在消亡前,所能达到的最大光程,该值的最大取值为,根号FLT_MAX
float Falloff; //该类型仅用于聚光灯,该参数定义了光强从内锥到到外锥形的衰减方式,一般设1.0f
float Attenuation0; //定义了光强随距离衰减的方式,0表示常量
float Attenuation1; // 这个表示线性
float Attenuation2; // 这个表示2次距离衰减系数,attenuation = 1/(a0+a1*D+a2*D*D)
float Theta; //仅用于聚光灯,指定了内部锥形圆锥角,单位为弧度
float Phi; //仅用于聚光灯,指定了外部锥形的圆锥角,单位为弧度
}D3DLIGHT9,*LPD3DLIGHT;
光源初始化完毕之后,我们需要在D3D所维护的一个光源内部列表中对所要使用的光源进行注册
g_pDeive->SetLight(0,&ligth);
g_pDevice->LightEnable(0,true);
下面代码简单示例
(1)启用光照
(2)为每个物体创建一种材质,并在绘制相应物体前应用设置该材质
(3)创建一种或多种光源,,设置并启用
(4)启用所有其余的光照状态,

为了增强所绘场景的真实感,我们可以为场景增加光照,使用光照时,我们无需自行指定顶点的颜色值,依据光源类型,材质,以及物体表面相对于光源的朝向,计算出每个顶点的颜色值,
光照由以下三种类型光组成,
环境光(Ambient Light)
这种类型的光经其它表面反射到物体表面,并照亮整个场景,例如,物体的一些部份被一定程度的照亮,但物体并没有处于光源的直接照射下,物体之所以会被照亮,是由于其它物体对光的反射,
漫射光(Diffuse Light)
这种类型的光沿着特定的方向传播,当它到达一些表面时,将沿着各个方向反射,由于漫射光沿所有方向均匀反射,无论从哪个方面观察,,表面亮度都是相同的,采用这种模形时,无须考虑观察者的位置,仅需考虑光传播的方向以及表面的朝向,
镜面光(Specular Light)
这种类型的光沿特定方向传播,当此类型光到达一个表面时,将严格地沿着另一个方向反射,从而形成只能在一定角度内才能观察到的高亮度照射,
每种光的结构都可以用结构D3DCOLORVALUE或是D3DXCOLOR来表示,描述光线的颜色时,D3DXCOLOR类中的Alpha值都将被忽略
2.材质
在现实世界中,我们观察到的物体的颜色是由该物体所反射的光的颜色决定的,例如,一个纯红色的球体,反射了全部的红色入射光,并吸收了所以非红色的光,所以该球体表现为红色,D3D通过定义物体的材质(materials)来模拟这种现像,材质允许我们定义物体表面上对种种颜色光的反射比例,
材质用结构D3DMATERIAL9表示
typedef struct D3DMATERIAL9
{
D3DCOLORVALUE Diffuse; //指定材质对漫射光的反射率
D3DCOLORVALUE Ambient; //指定材质对环境光的反射率
D3DCOLORVALUE Specular;//指定材质对镜面光的反射率
D3DCOLORVALUE Emissive;//用于增强物体的亮度,使之看起起来可以自己发光
float Power; //指定镜面高光点的锐度,值越大,高光点的锐度越大
}D3DMATERIAL9,*LPD3DMATERIAL9;
例如,假如有一个红色的球体,我们想将该球体的材质的属性定义只反射红色光,而吸走所有其它颜色的光,
D3DMATERIAL9 red;
ZeroMemory(&red,sizeof(red));
red.Diffuse = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Ambient = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Specular = D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); //red
red.Emissive = D3DXCOLOR(0.0f,0.0f,0.0f,1.0f); //no emission
red.Power = 5.0f
如果用一个只能发出蓝色的光,来照射一个红色的球体,该物体无法被照亮,当一个物体吸收了所有光时,便呈现了黑色, 反之如果一个物体能够100%地反射红色光,绿色光,和蓝色光,它将呈成为白色
顶点结构中不含有材质属性,但我们必须对当前材质进行设定,下面这个函数可以用来对当前材质进行设定: IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9 *pMaterial)
3.顶点法线
1.面法线
2.顶点法线
4.光源
1.点光源
2.方向光
3.聚光灯
typedef struct D3DLIGHT9
{
D3DLIGHTTYPE Type; //光源类型
D3DCOLORVALUE Diffuse; //该光源所发出的漫射光的颜色
D3DCOLORVALUE Specular; //该光源所发出的镜面光的颜色
D3DCOLORVALUE Ambient; //该光源所发出的环境光的颜色
D3DVECTOR Position; //用于描述光源在世界坐标系中位置的向量,对于方向光,该参数无意义
D3DVECTOR Direction; //描述光在世界坐标系中传播方向的向量,对于点光源,该参数无意义
float Range; //光在消亡前,所能达到的最大光程,该值的最大取值为,根号FLT_MAX
float Falloff; //该类型仅用于聚光灯,该参数定义了光强从内锥到到外锥形的衰减方式,一般设1.0f
float Attenuation0; //定义了光强随距离衰减的方式,0表示常量
float Attenuation1; // 这个表示线性
float Attenuation2; // 这个表示2次距离衰减系数,attenuation = 1/(a0+a1*D+a2*D*D)
float Theta; //仅用于聚光灯,指定了内部锥形圆锥角,单位为弧度
float Phi; //仅用于聚光灯,指定了外部锥形的圆锥角,单位为弧度
}D3DLIGHT9,*LPD3DLIGHT;
光源初始化完毕之后,我们需要在D3D所维护的一个光源内部列表中对所要使用的光源进行注册
g_pDeive->SetLight(0,&ligth);
g_pDevice->LightEnable(0,true);
下面代码简单示例
(1)启用光照
(2)为每个物体创建一种材质,并在绘制相应物体前应用设置该材质
(3)创建一种或多种光源,,设置并启用
(4)启用所有其余的光照状态,
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
IDirect3D9 *g_pD3d = NULL;
IDirect3DDevice9 *g_pDevice= NULL;
IDirect3DVertexBuffer9 *g_pbuf = NULL;
struct Vertex{
float x,y,z;
float _nx,_ny,_nz;
Vertex(){}
Vertex(float x,float y,float z,float nx,float ny,float nz)
{
this->x = x;
this->y = y;
this->z = z;
this->_nx = nx;
this->_ny = ny;
this->_nz = nz;
}
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
#define WHITE D3DCOLOR_XRGB(255,255,255)
#define BLACK D3DCOLOR_XRGB(0,0,0)
#define RED D3DCOLOR_XRGB(255,0,0)
#define BLUE D3DCOLOR_XRGB(0,0,255)
#define GREEN D3DCOLOR_XRGB(0,255,0)
#define _WHITE D3DCOLORVALUE()
D3DMATERIAL9 InitMtrl(D3DXCOLOR a, //Ambient
D3DXCOLOR d, //Diffuse
D3DXCOLOR s, //Specular
D3DXCOLOR e, //Emissive
float p) //Power
{
D3DMATERIAL9 mtrl;
mtrl.Ambient = a;
mtrl.Diffuse = d;
mtrl.Emissive = e;
mtrl.Specular = s;
mtrl.Power = p;
return mtrl;
}
const D3DMATERIAL9 WHITE_MTRL = InitMtrl(WHITE , WHITE , WHITE , BLACK , 8.0f);
const D3DMATERIAL9 RED_MTRL = InitMtrl(RED , RED , RED , BLACK , 8.0f);
const D3DMATERIAL9 GREEN_MTRL = InitMtrl(GREEN , GREEN , GREEN , BLACK , 8.0f);
const D3DMATERIAL9 BLUE_MTRL = InitMtrl(BLUE , BLUE , BLUE , BLACK , 8.0f);
//方向光
D3DLIGHT9 InitDirectLight(D3DXVECTOR3 *dir,D3DXCOLOR* clr)
{
D3DLIGHT9 light;
ZeroMemory(&light,sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = *clr * 0.4f;
light.Diffuse = *clr;
light.Direction = *dir;
light.Specular = *clr * 0.6f;
return light;
}
bool InitObject()
{
g_pDevice->SetRenderState(D3DRS_LIGHTING,true);
g_pDevice->CreateVertexBuffer(
12 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::FVF,
D3DPOOL_MANAGED,
&g_pbuf,
0);
Vertex *v;
g_pbuf->Lock(0,0,(void**)&v,0);
//front face
v[0] = Vertex(-1.0f , 0.0f , -1.0f , 0.0f , 0.707f , -0.707f);
v[1] = Vertex( 0.0f , 1.0f , 0.0f , 0.0f , 0.707f , -0.707f);
v[2] = Vertex( 1.0f , 0.0f , -1.0f , 0.0f , 0.707f , -0.707f);
//left face
v[3] = Vertex(-1.0f , 0.0f , 1.0f , -0.707f , 0.707f , 0.0f);
v[4] = Vertex( 0.0f , 1.0f , 0.0f , -0.707f , 0.707f , 0.0f);
v[5] = Vertex(-1.0f , 0.0f , -1.0f , -0.707f , 0.707f , 0.0f);
//right face
v[6] = Vertex( 1.0f , 0.0f , -1.0f , 0.707f , 0.707f , 0.0f);
v[7] = Vertex( 0.0f , 1.0f , 0.0f , 0.707f , 0.707f , 0.0f);
v[8] = Vertex( 1.0f , 0.0f , 1.0f , 0.707f , 0.707f , 0.0f);
//back face
v[9] = Vertex( 1.0f , 0.0f , 1.0f , 0.0f , 0.707f , 0.707f);
v[10] = Vertex( 0.0f , 1.0f , 0.0f , 0.0f , 0.707f , 0.707f);
v[11] = Vertex(-1.0f , 0.0f , 1.0f , 0.0f , 0.707f , 0.707f);
g_pbuf->Unlock();
//材质
D3DMATERIAL9 mtrl;
mtrl = InitMtrl(WHITE,WHITE,WHITE,BLACK,5.0f);
g_pDevice->SetMaterial(&mtrl);
//光源
D3DLIGHT9 light;
D3DXVECTOR3 dir(1.0f,0.0f,0.0f);
D3DXCOLOR clr = D3DCOLOR_XRGB(210,255,25);
ZeroMemory(&light,sizeof(light));
light = InitDirectLight(&dir,&clr);
g_pDevice->SetLight(0,&light);
g_pDevice->LightEnable(0,true);
g_pDevice->SetRenderState(D3DRS_NORMALIZENORMALS,true);
g_pDevice->SetRenderState(D3DRS_SPECULARENABLE,true);
D3DXVECTOR3 pos(2.0f,2.0f,-1.0f);
D3DXVECTOR3 tar(0.0f,0.0f,0.0f);
D3DXVECTOR3 up( 0.0f,1.0f,0.0f);
D3DXMATRIX _v;
D3DXMatrixLookAtLH(&_v,&pos,&tar,&up);
g_pDevice->SetTransform(D3DTS_VIEW,&_v);
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj,D3DX_PI * 0.5f,
float(800)/float(600),
0.20f,100.0f);
g_pDevice->SetTransform(D3DTS_PROJECTION,&proj);
return true;
}
bool Initd3d(HWND hwnd)
{
g_pD3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DDISPLAYMODE displaymode;
ZeroMemory(&displaymode,sizeof(displaymode));
g_pD3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&displaymode);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(d3dpp));
d3dpp.BackBufferHeight = 600;
d3dpp.BackBufferWidth = 800;
d3dpp.hDeviceWindow = hwnd;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
// d3dpp.BackBufferFormat = D3DFMT_A8B8G8R8;
g_pD3d->CreateDevice(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp,
&g_pDevice);
return true;
}
void RenderScene()
{
g_pDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0xffffffff,1.0f,0);
g_pDevice->BeginScene();
g_pDevice->SetFVF(Vertex::FVF);
g_pDevice->SetStreamSource(0,g_pbuf,0,sizeof(Vertex));
g_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,4);
g_pDevice->EndScene();
g_pDevice->Present(0,0,0,0);
}
void Shutdown()
{
if(g_pD3d)
{
g_pD3d->Release();
}
if(g_pDevice)
{
g_pDevice->Release();
}
if(g_pbuf)
{
g_pbuf->Release();
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Light");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclassex = {0};
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WndProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclassex.lpszMenuName = NULL;
wndclassex.lpszClassName = szAppName;
wndclassex.hIconSm = wndclassex.hIcon;
if (!RegisterClassEx (&wndclassex))
{
MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,
szAppName,
TEXT ("WindowTitle"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL);
//////////////////////////////////////////////////////////////////////////
Initd3d(hwnd);
InitObject();
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
while (msg.message!=WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
else
{
RenderScene();
}
}
Shutdown();
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
return (0);
}
return DefWindowProc (hwnd, message, wParam, lParam);
}