本篇是
创建游戏内核(7)的续篇,其中涉及到的光照知识请参阅
D3D
中的材质和光照处理。
使用LIGHT进行光照处理
光照同材质一样简单,使用光照可以通过很多方式实现很多效果,基于这个原因,这里将所有同光照有关的一切东西都汇总到一个名为LIGHT的类中,来看看它的定义:
class LIGHT
{
protected:
D3DLIGHT9 _light;
public:
LIGHT();
D3DLIGHT9* Get_Light();
void Set_Type(D3DLIGHTTYPE type);
void Move(float x_pos, float y_pos, float z_pos);
void Move_Rel(float x_pos, float y_pos, float z_pos);
void Get_Pos(float* x_pos, float* y_pos, float* z_pos);
void Point(float x_from, float y_from, float z_from, float x_at, float y_at, float z_at);
void Get_Direction(float* x_dir, float* y_dir, float* z_dir);
void Set_Diffuse_Color(unsigned char red, unsigned char green, unsigned char blue);
void Get_Diffuse_Color(unsigned char* red, unsigned char* green, unsigned char* blue);
void Set_Specular_Color(unsigned char red, unsigned char green, unsigned char blue);
void Get_Specular_Color(unsigned char* red, unsigned char* green, unsigned char* blue);
void Set_Ambient_Color(unsigned char red, unsigned char green, unsigned char blue);
void Get_Ambient_Color(unsigned char* red, unsigned char* green, unsigned char* blue);
void Set_Range(float range);
float Get_Range();
void Set_Falloff(float falloff);
float Get_Falloff();
void Set_Attenuation_0(float attenuation);
float Get_Attenuation_0();
void Set_Attenuation_1(float attenuation);
float Get_Attenuation_1();
void Set_Attenuation_2(float attenuation);
float Get_Attenuation_2();
void Set_Theta(float theta);
float Get_Theta();
void Set_Phi(float phi);
float Get_Phi();
};
接着是类LIGHT的实现:
//---------------------------------------------------------------------------
// Constructor, set light type as point light, place light source at origin,
// and set diffuse color and ambient color as white, set range and attenuation
// for light.
//---------------------------------------------------------------------------
LIGHT::LIGHT()
{
ZeroMemory(&_light, sizeof(D3DLIGHT9));
Set_Type(D3DLIGHT_POINT);
Move(0.0, 0.0, 0.0);
Set_Diffuse_Color(255, 255, 255);
Set_Ambient_Color(255, 255, 255);
Set_Range(1000.0);
Set_Attenuation_0(1.0);
}
//---------------------------------------------------------------------------
// Set light type (D3DLIGHT_POINT, D3DLIGHT_SPOT, D3DLIGHT_DIRECTIONAL).
//---------------------------------------------------------------------------
void LIGHT::Set_Type(D3DLIGHTTYPE type)
{
_light.Type = type;
}
//---------------------------------------------------------------------------
// Move light source to specified position.
//---------------------------------------------------------------------------
void LIGHT::Move(float x_pos, float y_pos, float z_pos)
{
_light.Position.x = x_pos;
_light.Position.y = y_pos;
_light.Position.z = z_pos;
}
//---------------------------------------------------------------------------
// Move light source to specified position which is relative to current position.
//---------------------------------------------------------------------------
void LIGHT::Move_Rel(float x_pos, float y_pos, float z_pos)
{
_light.Position.x += x_pos;
_light.Position.y += y_pos;
_light.Position.z += z_pos;
}
//---------------------------------------------------------------------------
// Get current position.
//---------------------------------------------------------------------------
void LIGHT::Get_Pos(float *x_pos, float *y_pos, float *z_pos)
{
if(x_pos != NULL)
*x_pos = _light.Position.x;
if(y_pos != NULL)
*y_pos = _light.Position.y;
if(z_pos != NULL)
*z_pos = _light.Position.z;
}
//---------------------------------------------------------------------------
// Move light source to specified position and pointer it to specified direction.
//---------------------------------------------------------------------------
void LIGHT::Point(float x_from, float y_from, float z_from, float x_at, float y_at, float z_at)
{
// move the light
Move(x_from, y_from, z_from);
// calculate vator between angles
_light.Direction.x = x_at - x_from;
_light.Direction.y = y_at - y_from;
_light.Direction.z = z_at - z_from;
}
//---------------------------------------------------------------------------
// Get the direction of current light source.
//---------------------------------------------------------------------------
void LIGHT::Get_Direction(float *x_dir, float *y_dir, float *z_dir)
{
if(x_dir != NULL)
*x_dir = _light.Direction.x;
if(y_dir != NULL)
*y_dir = _light.Direction.y;
if(z_dir != NULL)
*z_dir = _light.Direction.z;
}
//---------------------------------------------------------------------------
// Set diffuse color of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Diffuse_Color(unsigned char red, unsigned char green, unsigned char blue)
{
_light.Diffuse.r = red / 255.0f;
_light.Diffuse.g = green / 255.0f;
_light.Diffuse.b = blue / 255.0f;
}
//---------------------------------------------------------------------------
// Get diffuse color of light source.
//---------------------------------------------------------------------------
void LIGHT::Get_Diffuse_Color(unsigned char* red, unsigned char* green, unsigned char* blue)
{
if(red != NULL)
*red = (unsigned char)(255.0f * _light.Diffuse.r);
if(green != NULL)
*green = (unsigned char)(255.0f * _light.Diffuse.g);
if(blue != NULL)
*blue = (unsigned char)(255.0f * _light.Diffuse.b);
}
//---------------------------------------------------------------------------
// Set specular color of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Specular_Color(unsigned char red, unsigned char green, unsigned char blue)
{
_light.Specular.r = red / 255.0f;
_light.Specular.g = green / 255.0f;
_light.Specular.b = blue / 255.0f;
}
//---------------------------------------------------------------------------
// Get specular color of light source.
//---------------------------------------------------------------------------
void LIGHT::Get_Specular_Color(unsigned char* red, unsigned char* green, unsigned char* blue)
{
if(red != NULL)
*red = (unsigned char)(255.0f * _light.Specular.r);
if(green != NULL)
*green = (unsigned char)(255.0f * _light.Specular.g);
if(blue != NULL)
*blue = (unsigned char)(255.0f * _light.Specular.b);
}
//---------------------------------------------------------------------------
// Set ambient color of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Ambient_Color(unsigned char red, unsigned char green, unsigned char blue)
{
_light.Ambient.r = red / 255.0f;
_light.Ambient.g = green / 255.0f;
_light.Ambient.b = blue / 255.0f;
}
//---------------------------------------------------------------------------
// Get ambient color of light source.
//---------------------------------------------------------------------------
void LIGHT::Get_Ambient_Color(unsigned char* red, unsigned char* green, unsigned char* blue)
{
if(red != NULL)
*red = (unsigned char)(255.0f * _light.Ambient.r);
if(green != NULL)
*green = (unsigned char)(255.0f * _light.Ambient.g);
if(blue != NULL)
*blue = (unsigned char)(255.0f * _light.Ambient.b);
}
//---------------------------------------------------------------------------
// Set the range of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Range(float range)
{
_light.Range = range;
}
//---------------------------------------------------------------------------
// Get the range of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Range()
{
return _light.Range;
}
//---------------------------------------------------------------------------
// Set the fallof of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Falloff(float falloff)
{
_light.Falloff = falloff;
}
//---------------------------------------------------------------------------
// Get the fallof of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Falloff()
{
return _light.Falloff;
}
//---------------------------------------------------------------------------
// Set attenuation 0 of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Attenuation_0(float attenuation)
{
_light.Attenuation0 = attenuation;
}
//---------------------------------------------------------------------------
// Get attenuation 0 of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Attenuation_0()
{
return _light.Attenuation0;
}
//---------------------------------------------------------------------------
// Set attenuation 1 of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Attenuation_1(float attenuation)
{
_light.Attenuation1 = attenuation;
}
//---------------------------------------------------------------------------
// Get attenuation 1 of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Attenuation_1()
{
return _light.Attenuation1;
}
//---------------------------------------------------------------------------
// Set attenuation 2 of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Attenuation_2(float attenuation)
{
_light.Attenuation2 = attenuation;
}
//---------------------------------------------------------------------------
// Get attenuation 2 of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Attenuation_2()
{
return _light.Attenuation2;
}
//---------------------------------------------------------------------------
// Set angle thera of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Theta(float theta)
{
_light.Theta = theta;
}
//---------------------------------------------------------------------------
// Get angle thera of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Theta()
{
return _light.Theta;
}
//---------------------------------------------------------------------------
// Set angle phi of light source.
//---------------------------------------------------------------------------
void LIGHT::Set_Phi(float phi)
{
_light.Phi = phi;
}
//---------------------------------------------------------------------------
// Get angle phi of light source.
//---------------------------------------------------------------------------
float LIGHT::Get_Phi()
{
return _light.Phi;
}
//---------------------------------------------------------------------------
// Get light source.
//---------------------------------------------------------------------------
D3DLIGHT9* LIGHT::Get_Light()
{
return &_light;
}
要在光源中使用光照,只需要实例化LIGHT类,然后挑选一种光源类型并设置光源的颜色,将光源置于任何适当的位置,并设置光源的发射方向。
下面给出测试代码:
点击下载源码和工程
/*****************************************************************************
PURPOSE:
Test for class LIGHT.
*****************************************************************************/
#include "Core_Global.h"
#pragma warning(disable : 4996)
//===========================================================================
// Defines class APP which public inherits from class APPLICATION.
//===========================================================================
class APP : public APPLICATION
{
private:
// the Direct3D and device object
IDirect3D9* _d3d;
IDirect3DDevice9* _d3d_device;
IDirect3DVertexBuffer9* _vertex_buffer;
// The 3D vertex format and descriptor
typedef struct
{
float x, y, z; // 3D coordinates
float nx, ny, nz; // normals
D3DCOLOR diffuse; // color
} VERTEX;
#define VERTEX_FVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)
public:
APP();
BOOL Init();
BOOL Shutdown();
BOOL Frame();
};
//-----------------------------------------------------------------------------
// Consturctor, initialize member data.
//-----------------------------------------------------------------------------
APP::APP()
{
_d3d = NULL;
_d3d_device = NULL;
_vertex_buffer = NULL;
}
//-----------------------------------------------------------------------------
// Initialize d3d, d3d device, vertex buffer, texutre; set render state for d3d;
// set perspective matrix and view matrix.
//-----------------------------------------------------------------------------
BOOL APP::Init()
{
D3DPRESENT_PARAMETERS present_param;
D3DDISPLAYMODE display_mode;
D3DXMATRIX mat_proj, mat_view;
LIGHT light;
BYTE* vertex_ptr;
// initialize vertex data
VERTEX verts[] = {
{ -100.0f, 100.0f, -100.0f, 0.0f,0.0f,-1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, 100.0f, -100.0f, 0.0f,0.0f,-1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, -100.0f, -100.0f, 0.0f,0.0f,-1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, -100.0f, -100.0f, 0.0f,0.0f,-1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, 100.0f, -100.0f, 1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, 100.0f, 100.0f, 1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, -100.0f, -100.0f, 1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, -100.0f, 100.0f, 1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, 100.0f, 100.0f, 0.0f,0.0f,1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, 100.0f, 100.0f, 0.0f,0.0f,1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ 100.0f, -100.0f, 100.0f, 0.0f,0.0f,1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, -100.0f, 100.0f, 0.0f,0.0f,1.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, 100.0f, 100.0f, -1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, 100.0f, -100.0f, -1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, -100.0f, 100.0f, -1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) },
{ -100.0f, -100.0f, -100.0f, -1.0f,0.0f,0.0f, D3DCOLOR_RGBA(255,255,255,255) }
};
// do a windowed mode initialization of Direct3D
if((_d3d = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
return FALSE;
// retrieves the current display mode of the adapter
if(FAILED(_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &display_mode)))
return FALSE;
ZeroMemory(&present_param, sizeof(present_param));
// initialize d3d presentation parameter
present_param.Windowed = TRUE;
present_param.SwapEffect = D3DSWAPEFFECT_DISCARD;
present_param.BackBufferFormat = display_mode.Format;
present_param.EnableAutoDepthStencil = TRUE;
present_param.AutoDepthStencilFormat = D3DFMT_D16;
// creates a device to represent the display adapter
if(FAILED(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Get_Hwnd(),
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_param, &_d3d_device)))
return FALSE;
// set render state
// enable d3d lighting
_d3d_device->SetRenderState(D3DRS_LIGHTING, TRUE);
// enable z-buffer
_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
// create and set the projection matrix
// builds a left-handed perspective projection matrix based on a field of view
D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4.0, 1.33333f, 1.0f, 1000.0f);
// sets a single device transformation-related state
_d3d_device->SetTransform(D3DTS_PROJECTION, &mat_proj);
// create and set the view matrix
D3DXMatrixLookAtLH(&mat_view,
&D3DXVECTOR3(0.0, 0.0, -500.0),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 1.0f, 0.0f));
_d3d_device->SetTransform(D3DTS_VIEW, &mat_view);
// create the vertex buffer and set data
_d3d_device->CreateVertexBuffer(sizeof(VERTEX) * 16, 0, VERTEX_FVF, D3DPOOL_DEFAULT, &_vertex_buffer, NULL);
// locks a range of vertex data and obtains a pointer to the vertex buffer memory
_vertex_buffer->Lock(0, 0, (void**)&vertex_ptr, 0);
memcpy(vertex_ptr, verts, sizeof(verts));
// unlocks vertex data
_vertex_buffer->Unlock();
// set light data, color, position, range.
light.Set_Type(D3DLIGHT_POINT);
light.Set_Diffuse_Color(128, 128, 0);
light.Set_Range(1000.0);
light.Set_Attenuation_0(0.5);
light.Move(300.0, 0.0, -600.0);
// set and enable the light
_d3d_device->SetLight(0, light.Get_Light());
_d3d_device->LightEnable(0, TRUE);
return TRUE;
}
//-----------------------------------------------------------------------------
// Release all d3d resource.
//-----------------------------------------------------------------------------
BOOL APP::Shutdown()
{
Release_COM(_vertex_buffer);
Release_COM(_d3d_device);
Release_COM(_d3d);
return TRUE;
}
//-----------------------------------------------------------------------------
// Render a frame.
//-----------------------------------------------------------------------------
BOOL APP::Frame()
{
D3DXMATRIX mat_world;
// clear device back buffer
_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0);
// Begin scene
if(SUCCEEDED(_d3d_device->BeginScene()))
{
// create and set the world transformation matrix
// rotate object along y-axis
D3DXMatrixRotationY(&mat_world, (float) (timeGetTime() / 1000.0));
_d3d_device->SetTransform(D3DTS_WORLD, &mat_world);
// set the vertex stream, shader.
// binds a vertex buffer to a device data stream
_d3d_device->SetStreamSource(0, _vertex_buffer, 0, sizeof(VERTEX));
// set the current vertex stream declation
_d3d_device->SetFVF(VERTEX_FVF);
// draw the vertex buffer
for(short i = 0; i < 4; i++)
_d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);
// end the scene
_d3d_device->EndScene();
}
// present the contents of the next buffer in the sequence of back buffers owned by the device
_d3d_device->Present(NULL, NULL, NULL, NULL);
return TRUE;
}
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
APP app;
return app.Run();
}
运行截图: