一.简介
二.灯光模型
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;
}