一.简介
二.灯光模型
1.环境光(Ambient Light)
环境光(Ambient Light):这种灯光将被其他所有表面反射且被用在照亮整个场景
2.漫射光(Diffuse Light)
漫反射(Diffuse Reflection):这种灯光按照特殊方向传播,当它照射到一个表面,它将在所有方向上均匀反射
3.镜面光(Specular Light)
镜面反射(Specular Reflection):这种灯光按照特殊方向传播,当它照射到一个表面,它会严格按照一个方向传播
镜面光默认是关闭的,要使用镜面光必须设置
//开启镜面光反射计算 Device->SetRenderState(D3DRS_SPECULARENABLE,true);
三.灯光颜色
每一种灯光模型都是通过颜色结构体(D3DXCOLOR)或者颜色类(D3DCOLORVALUE)来绘制的
D3DXCOLOR redAmbient(1.0f, 0.0f, 0.0f, 1.0f); D3DXCOLOR blueDiffuse(0.0f, 0.0f, 1.0f, 1.0f); D3DXCOLOR whiteSpecular(1.0f, 1.0f, 1.0f, 1.0f);
四.灯光材质
材质允许我们定义物体表面对各种颜色光的反射比例
//材质用结构体D3DMATERIAL9
typedef struct D3DMATERIAL9{
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Ambient;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Emissive;
float Power;
}D3DMATERIAL9,*LPD3DMATERIAL9;
- Diffuse
//指定材质对漫射光的反射率
- Ambient
//指定材质对环境光的反射率
- Specular
//指定材质对镜面光的反射率
- Emissive
//用于增强物体的亮度
- Power
//指定镜面高光点的锐度(sharpness)
//只反射红光 D3DMATERIAL9 red; ::ZeroMemory(&red,sizeof(red)); red.Diffuse=D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); red.Ambient=D3DXCOLOR(1.0f,0,0f,0.0f,1.0f); red.Specular=D3DXCOLOR(1.0f,0.0f,0.0f,1.0f); red.Emissive=D3DXCOLOR(0.0f,0.0f,0.0f,1.0f); red.Power=5.0f; Device->SetMaterial(&red);
// 全局材质 D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p) { D3DMATERIAL9 mtrl; mtrl.Ambient = a; mtrl.Diffuse = d; mtrl.Specular = s; mtrl.Emissive = e; mtrl.Power = p; return mtrl; } namespace d3d { ... D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p); 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); const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 8.0f); } // IDirect3DDevice9::SetMaterial(CONST D3DMATERIAL9* pMaterial) D3DMATERIAL9 blueMaterial; Device->SetMaterial(&blueMaterial); drawSphere();
五.顶点法线
面法线(face normal)是描述多边形表面方向的一个向量
顶点法线能够确定灯光照射到物体表面的角度
//在顶点结构中添加法线分量 struct Vertex { float _x, _y, _z; float _nx, _ny, _nz; static const DWORD FVF; } const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
// 通过三角形的三个顶点计算三角形的面法线 void ComputeNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1, D3DXVECTOR3* p2, D3DXVECTOR3* out) { D3DXVECTOR3 u = *p1 - *p0; D3DXVECTOR3 v = *p2 - *p0; D3DXVec3Cross(out, &u, &v); D3DXVec3Normalize(out, out); } Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
六.光源
1.点光源(Point lights)
该光源在世界坐标系中有固定的位置,并向所有的方向发射光线
2.方向光(Directional lights)
该光源没有位置信息,所发射的光线相互平行地沿某一特定方向传播
3.聚光灯(Spot lights)
这种类型的光源和手电筒类似,没有位置信息,其发射的光线呈锥形(conical shape)沿着特定方向传播.
该锥形有两个角度,一个是内部锥形,一个是外部锥形
4.D3DLIGHT9(光源类)
//光源用结构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;
- Type
//表示光源类型:D3DLIGHT_POINT,D3DLIGHT_SPOT,D3DLIGHT_DIRECTIONAL
- Diffuse
//表示该光源所发出的漫射光的颜色
- Specular
//表示该光源所发出的镜面光的颜色
- Ambient
//表示该光源所发出的环境光的颜色
- Position
//表示用于描述光源在世界坐标系中位置的向量
- Direction
//表示一个描述光在世界坐标系
- Range
//表示最大光程,对于方向光无意义
- Falloff
//表示仅用于聚光灯,表示光强(intensity)
- Attenuation0
//Attenuation012表示光强随距离衰减的方式,仅用于点光源和聚光灯
- Theta
//表示仅用于聚光灯,指定内部锥形的弧度
- Phi
//表示仅用于聚光灯,指定了外部锥形的弧度
//创建一个方向光源,沿着x轴正方向照射白色灯光 namespace d3d { ... D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color); D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color); D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color); } D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Direction = *direction; return light; } D3DXVECTOR3 dire(1.0f, 0.0f, 0.0f); D3DXCOLOR c = d3d::WHITE; D3DLIGHT9 dirLight = d3d::InitDirectionalLight(&dir, &c); Device->SetLight(0, &light); Device->LightEnable(0, true);
七.例子
1.点光源
#include "d3dUtility.h" // // Globals // IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Objects[4] = {0, 0, 0, 0}; D3DXMATRIX Worlds[4]; D3DMATERIAL9 Mtrls[4]; // // Framework Functions // bool Setup() { // // Create objects // D3DXCreateTeapot(Device, &Objects[0], 0); D3DXCreateSphere(Device, 1.0f, 20, 20, &Objects[1], 0); D3DXCreateTorus(Device, 0.5f, 1.0f, 20, 20, &Objects[2], 0); D3DXCreateCylinder(Device, 0.5f, 0.5f, 2.0f, 20, 20, &Objects[3], 0); D3DXMatrixTranslation(&Worlds[0], 0.0f, 2.0f, 0.0f); D3DXMatrixTranslation(&Worlds[1], 0.0f, -2.0f, 0.0f); D3DXMatrixTranslation(&Worlds[2], -3.0f, 0.0f, 0.0f); D3DXMatrixTranslation(&Worlds[3], 3.0f, 0.0f, 0.0f); // // Setup the object's materials // Mtrls[0] = d3d::RED_MTRL; Mtrls[1] = d3d::BLUE_MTRL; Mtrls[2] = d3d::GREEN_MTRL; Mtrls[3] = d3d::YELLOW_MTRL; // // Setup a point light . Note that the point light is positioned at the origin // D3DXVECTOR3 pos(0.0f, 0.0f, 0.0f); D3DXCOLOR c = d3d::WHITE; D3DLIGHT9 point = d3d::InitPointLight(&pos, &c); // // Set and Enable the light // Device->SetLight(0, &point); Device->LightEnable(0, true); // // Set lighting related render states // Device->SetRenderState(D3DRS_NORMALIZENORMALS,true); Device->SetRenderState(D3DRS_SPECULARENABLE, false); // // Set the projection matrix // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.25f, (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { for (int i = 0; i < 4; i++) d3d::Release<ID3DXMesh*>(Objects[i]); } bool Display(float timeDelta) { if (Device) { // // Update the scene : update camera position // static float angle = (3.0f * D3DX_PI) / 2.0f; static float height = 5.0f; if (::GetAsyncKeyState(VK_LEFT) & 0x8000f) angle -= 0.5f * timeDelta; if (::GetAsyncKeyState(VK_RIGHT) & 0x8000f) angle += 0.5f*timeDelta; if (::GetAsyncKeyState(VK_UP) & 0x8000f) height += 5.0f * timeDelta; if (::GetAsyncKeyState(VK_DOWN) & 0x8000f) height -= 5.0f * timeDelta; D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // // Draw the scene: // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); Device->BeginScene(); for (int i = 0; i < 4; i++) { // set material and world matrix for in Device->SetMaterial(&Mtrls[i]); Device->SetTransform(D3DTS_WORLD, &Worlds[i]); Objects[i]->DrawSubset(0); } Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; }
2.方向光
3.聚光灯
#include "d3dUtility.h" IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; ID3DXMesh* Objects[4] = {0, 0, 0, 0}; D3DXMATRIX Worlds[4]; D3DMATERIAL9 Mtrls[4]; D3DLIGHT9 Spot; bool Setup() { D3DXCreateTeapot(Device, &Objects[0], 0); D3DXCreateSphere(Device, 1.0f, 20, 20, &Objects[1], 0); D3DXCreateTorus(Device, 0.5f, 1.0f, 20, 20, &Objects[2], 0); D3DXCreateCylinder(Device, 0.5f, 0.5f, 2.0f, 20, 20, &Objects[3], 0); D3DXMatrixTranslation(&Worlds[0], 0.0f, 2.0f, 0.0f); D3DXMatrixTranslation(&Worlds[1], 0.0f, -2.0f, 0.0f); D3DXMatrixTranslation(&Worlds[2], -3.0f, 0.0f, 0.0f); D3DXMatrixTranslation(&Worlds[3], 3.0f, 0.0f, 0.0f); D3DXMATRIX Rx; D3DXMatrixRotationX(&Rx, D3DX_PI * 0.5f); Worlds[3] = Rx * Worlds[3]; Mtrls[0] = d3d::RED_MTRL; Mtrls[1] = d3d::BLUE_MTRL; Mtrls[2] = d3d::GREEN_MTRL; Mtrls[3] = d3d::YELLOW_MTRL; for (int i = 0; i < 4; i++) Mtrls[i].Power = 20.0f; D3DXVECTOR3 pos(0.0f, 0.0f, -5.0f); D3DXVECTOR3 dir(0.0f, 0.0f, 1.0f); D3DXCOLOR c = d3d::WHITE; Spot = d3d::InitSpotLight(&pos, &dir, &c); Device->SetLight(0, &Spot); Device->LightEnable(0, true); Device->SetRenderState(D3DRS_NORMALIZENORMALS, true); Device->SetRenderState(D3DRS_SPECULARENABLE, true); D3DXVECTOR3 position(0.0f, 0.0f, -5.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { for (int i = 0; i < 4; i++) d3d::Release<ID3DXMesh*> (Objects[i]); } bool Display(float timeDelta) { if (Device) { static float angle = (3.0f * D3DX_PI) / 2.0f; if (::GetAsyncKeyState(VK_LEFT) & 0x8000f) Spot.Direction.x -= 0.5f * timeDelta; if (::GetAsyncKeyState(VK_RIGHT) & 0x8000f) Spot.Direction.x += 0.5f * timeDelta; if (::GetAsyncKeyState(VK_DOWN) & 0x8000f) Spot.Direction.y -= 0.5f * timeDelta; if (::GetAsyncKeyState(VK_UP) & 0x8000f) Spot.Direction.y += 0.5f * timeDelta; Device->SetLight(0, &Spot); Device->LightEnable(0, true); Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); Device->BeginScene(); for (int i = 0; i < 4; i++) { Device->SetMaterial(&Mtrls[i]); Device->SetTransform(D3DTS_WORLD, &Worlds[i]); Objects[i]->DrawSubset(0); } Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; }