本篇是
創(chuàng)建游戲內(nèi)核(4)的續(xù)篇,其中涉及到矩陣以及坐標(biāo)系統(tǒng)變換的知識(shí)請(qǐng)參閱
DirectX
9的一些數(shù)學(xué)計(jì)算函數(shù):矩陣,坐標(biāo)變換。以及
DirectX
9的坐標(biāo)系統(tǒng)變換。
圖形內(nèi)核
圖形內(nèi)核是游戲內(nèi)核最主要的部分,也是最大和最復(fù)雜的內(nèi)核對(duì)象,下表列出了圖形內(nèi)核中的類(lèi):
圖形內(nèi)核組件
|
類(lèi) |
說(shuō)明 |
GRAPHICS |
處理Direct3D的初始化,啟用狀態(tài)渲染以及設(shè)置紋理,材質(zhì)和光照。 |
TEXTURE |
含有一個(gè)紋理以及一個(gè)用于將紋理的2D部分繪制到顯示器上的函數(shù)。 |
MATERIAL |
含有一個(gè)材質(zhì)的定義 |
LIGHT |
含有一個(gè)光照的定義 |
FONT |
封裝了ID3DXFont對(duì)象 |
VERTEX_BUFFER |
使對(duì)頂點(diǎn)緩沖的處理變得更容易 |
WORLD_POSITION |
操縱世界變換矩陣,使程序員能夠快速定位、縮放和旋轉(zhuǎn)對(duì)象。 |
CAMERA |
包含一個(gè)觀察變換矩陣,可以使用該對(duì)象的接口修改此矩陣。 |
MESH |
包含從一個(gè) .X
文件加載的網(wǎng)格的列表以及這些網(wǎng)格的材質(zhì),MESH類(lèi)要同OBJECT類(lèi)結(jié)合起來(lái)使用。 |
OBJECT |
表示3D世界中的一個(gè)對(duì)象,OBJECT類(lèi)控制了對(duì)象的方位、網(wǎng)格以及動(dòng)態(tài)狀態(tài)。 |
ANIMATION |
包含從一個(gè) .X 文件加載的動(dòng)畫(huà)列表,ANIMATION
類(lèi)要同OBJECT類(lèi)結(jié)合起來(lái)使用。 |
其中GRAPHICS對(duì)象是所有圖形內(nèi)核對(duì)象的基礎(chǔ)。
世界變換和WORLD_POSITION
雖然處理世界變換矩陣并不難,但是用一個(gè)類(lèi)來(lái)處理諸如世界坐標(biāo)、旋轉(zhuǎn)值以及縮放因子等所有細(xì)節(jié),就更簡(jiǎn)單明了。另外,這個(gè)類(lèi)中還加入了公告板技術(shù)。
來(lái)看看WOLRD_POSITION的定義:
/*************************************************************************
PURPOSE:
Defines graphics component for game core.
*************************************************************************/
#ifndef _CORE_GRAPHICS_H_
#define _CORE_GRAPHICS_H_
#define Release_COM(x) if(x) { x->Release(); x = NULL; }
class GRAPHICS;
//================================================================================
// Defines for class GRAPHICS.
//================================================================================
class GRAPHICS
{
protected:
HWND _hwnd; // window handle pointer to parent window
IDirect3D9* _d3d; // pointer to Direct3D
IDirect3DDevice9* _d3d_device; // pointer to Direct3D device
public:
IDirect3D9* Get_Direct3D_COM();
IDirect3DDevice9* Get_Device_COM();
};
//================================================================================
// Defines for class WORLD_POSITION.
//================================================================================
class WORLD_POSITION
{
protected:
BOOL _use_billboard; // flag indicates whether use billboard
float _x_pos, _y_pos, _z_pos; // current position
float _x_rotation, _y_rotation, _z_rotation; // rotation
float _x_scale, _y_scale, _z_scale; // scale value
D3DXMATRIX _mat_world; // world transform matrix
D3DXMATRIX _mat_scale; // scale matrix
D3DXMATRIX _mat_rotation; // rotation matrix
D3DXMATRIX _mat_translation; // translation matrix
D3DXMATRIX* _mat_combine_1; // pointer to combination matrix 1
D3DXMATRIX* _mat_combine_2; // pointer to combination matrix 2
public:
WORLD_POSITION();
D3DXMATRIX* Get_Matrix(GRAPHICS* graphics = NULL);
void Set_Combine_Matrix_1(D3DXMATRIX* matrix = NULL);
void Set_Combine_Matrix_2(D3DXMATRIX* matrix = NULL);
void Copy(WORLD_POSITION* dest_pos);
void Move(float x_pos, float y_pos, float z_pos);
void Move_Rel(float x_add, float y_add, float z_add);
void Rotate(float x_rot, float y_rot, float z_rot);
void Rotate_Rel(float x_add, float y_add, float z_add);
void Scale(float x_scale, float y_scale, float z_scale);
void Scale_Rel(float x_add, float y_add, float z_add);
void Update(GRAPHICS* graphics = NULL);
void Enable_Billboard(BOOL use_billboard = TRUE);
float Get_X_Pos();
float Get_Y_Pos();
float Get_Z_Pos();
float Get_X_Rotation();
float Get_Y_Rotation();
float Get_Z_Rotation();
float Get_X_Scale();
float Get_Y_Scale();
float Get_Z_Scale();
};
#endif
下面是WORLD_POSITION的實(shí)現(xiàn):
/*************************************************************************
PURPOSE:
Defines graphics component for game core.
*************************************************************************/
#include "Core_Global.h"
#include "rmxftmpl.h"
#include "rmxfguid.h"
///////////////////////////////////// Define for class GRAPHICS /////////////////////////////////////
//-------------------------------------------------------------------
// Get pointer to Direct3D.
//-------------------------------------------------------------------
IDirect3D9* GRAPHICS::Get_Direct3D_COM()
{
return _d3d;
}
//-------------------------------------------------------------------
// Get pointer to Direct3D device.
//-------------------------------------------------------------------
IDirect3DDevice9* GRAPHICS::Get_Device_COM()
{
return _d3d_device;
}
///////////////////////////////////// Define for class WORLD_POSITION /////////////////////////////////////
//-------------------------------------------------------------------
// Constrcutor, initialize data member.
//-------------------------------------------------------------------
WORLD_POSITION::WORLD_POSITION()
{
_use_billboard = TRUE;
_mat_combine_1 = _mat_combine_2 = NULL;
Move(0.0, 0.0, 0.0);
Rotate(0.0, 0.0, 0.0);
Scale(1.0, 1.0, 1.0);
Update();
}
//-------------------------------------------------------------------
// Copy world position information to another world position object.
//-------------------------------------------------------------------
void WORLD_POSITION::Copy(WORLD_POSITION* dest_pos)
{
dest_pos->Move(_x_pos, _y_pos, _z_pos);
dest_pos->Rotate(_x_rotation, _y_rotation, _z_rotation);
dest_pos->Scale(_x_scale, _y_scale, _z_scale);
dest_pos->Enable_Billboard(_use_billboard);
}
//-------------------------------------------------------------------
// Move to new world position with specified relative value.
//-------------------------------------------------------------------
void WORLD_POSITION::Move(float x_pos, float y_pos, float z_pos)
{
_x_pos = x_pos;
_y_pos = y_pos;
_z_pos = z_pos;
D3DXMatrixTranslation(&_mat_translation, _x_pos, _y_pos, _z_pos);
}
//-------------------------------------------------------------------
// Move to new world position which is specified by new relative value
// and current position.
//-------------------------------------------------------------------
void WORLD_POSITION::Move_Rel(float x_add, float y_add, float z_add)
{
Move(_x_pos + x_add, _y_pos + y_add, _z_pos + z_add);
}
//-------------------------------------------------------------------
// Rotate around x, y, z, axis with specified degree.
//-------------------------------------------------------------------
void WORLD_POSITION::Rotate(float x_rot, float y_rot, float z_rot)
{
_x_rotation = x_rot;
_y_rotation = y_rot;
_z_rotation = z_rot;
// Builds a matrix with a specified yaw, pitch, and roll.
D3DXMatrixRotationYawPitchRoll(&_mat_rotation, _y_rotation, _x_rotation, _z_rotation);
}
//-------------------------------------------------------------------
// Rotate around x, y, z, axis which is specified with new relative
// degree and current rotation value.
//-------------------------------------------------------------------
void WORLD_POSITION::Rotate_Rel(float x_add, float y_add, float z_add)
{
Rotate(_x_rotation + x_add, _y_rotation + y_add, _z_rotation + z_add);
}
//-------------------------------------------------------------------
// Build scaling matrix.
//-------------------------------------------------------------------
void WORLD_POSITION::Scale(float x_scale, float y_scale, float z_scale)
{
_x_scale = x_scale;
_y_scale = y_scale;
_z_scale = z_scale;
D3DXMatrixScaling(&_mat_scale, x_scale, y_scale, z_scale);
}
//-------------------------------------------------------------------
// Build scaling matrix with specified value and current scaling value.
//-------------------------------------------------------------------
void WORLD_POSITION::Scale_Rel(float x_add, float y_add, float z_add)
{
Scale(_x_scale + x_add, _y_scale + y_add, _z_scale + z_add);
}
//-------------------------------------------------------------------
// Update world tranform matrix.
//-------------------------------------------------------------------
void WORLD_POSITION::Update(GRAPHICS* graphics)
{
D3DXMATRIX mat_view, mat_transposed;
// setup billboarding matrix
if(_use_billboard)
{
if(graphics && graphics->Get_Device_COM())
{
graphics->Get_Device_COM()->GetTransform(D3DTS_VIEW, &mat_view);
D3DXMatrixTranspose(&mat_transposed, &mat_view);
mat_transposed._41 = mat_transposed._42 = mat_transposed._43 = 0.0;
mat_transposed._14 = mat_transposed._24 = mat_transposed._34 = 0.0;
}
else
D3DXMatrixIdentity(&mat_transposed);
}
// combine scaling and rotation matrices first
D3DXMatrixMultiply(&_mat_world, &_mat_scale, &_mat_rotation);
// apply billboard matrix
if(_use_billboard)
D3DXMatrixMultiply(&_mat_world, &_mat_world, &mat_transposed);
// combine with translation matrix
D3DXMatrixMultiply(&_mat_world, &_mat_world, &mat_transposed);
// combine with combined matrices (if any)
if(_mat_combine_1 != NULL)
D3DXMatrixMultiply(&_mat_world, &_mat_world, _mat_combine_1);
if(_mat_combine_2 != NULL)
D3DXMatrixMultiply(&_mat_world, &_mat_world, _mat_combine_2);
}
//-------------------------------------------------------------------
// Enable or disable billboard.
//-------------------------------------------------------------------
void WORLD_POSITION::Enable_Billboard(BOOL use_billboard)
{
_use_billboard = use_billboard;
}
//-------------------------------------------------------------------
// Get current world transform matrix.
//-------------------------------------------------------------------
D3DXMATRIX* WORLD_POSITION::Get_Matrix(GRAPHICS *graphics)
{
Update(graphics);
return &_mat_world;
}
//-------------------------------------------------------------------
// Set combination matrix 1 which will be combined with world matrix.
//-------------------------------------------------------------------
void WORLD_POSITION::Set_Combine_Matrix_1(D3DXMATRIX* matrix)
{
_mat_combine_1 = matrix;
}
//-------------------------------------------------------------------
// Set combination matrix 2 which will be combined with world matrix.
//-------------------------------------------------------------------
void WORLD_POSITION::Set_Combine_Matrix_2(D3DXMATRIX* matrix)
{
_mat_combine_2 = matrix;
}
//-------------------------------------------------------------------
// Get current position's x coordinate.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_X_Pos()
{
return _x_pos;
}
//-------------------------------------------------------------------
// Get current position's y coordinate.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Y_Pos()
{
return _y_pos;
}
//-------------------------------------------------------------------
// Get current position's z coordinate.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Z_Pos()
{
return _z_pos;
}
//-------------------------------------------------------------------
// Get current rotation value which rotate around x axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_X_Rotation()
{
return _x_rotation;
}
//-------------------------------------------------------------------
// Get current rotation value which rotate around y axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Y_Rotation()
{
return _y_rotation;
}
//-------------------------------------------------------------------
// Get current rotation value which rotate around z axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Z_Rotation()
{
return _z_rotation;
}
//-------------------------------------------------------------------
// Get current scale value which around x axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_X_Scale()
{
return _x_scale;
}
//-------------------------------------------------------------------
// Get current scale value which around y axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Y_Scale()
{
return _y_scale;
}
//-------------------------------------------------------------------
// Get current scale value which around z axis.
//-------------------------------------------------------------------
float WORLD_POSITION::Get_Z_Scale()
{
return _z_scale;
}
Update函數(shù)使用內(nèi)含的方位重新創(chuàng)建世界變換矩陣,要考慮的矩陣有公告板矩陣以及兩個(gè)外部矩陣(稱(chēng)之為組合矩陣, combined
matrices)。要設(shè)置兩個(gè)組合矩陣的來(lái)源,使用Set_Combine_Matrix_1和Set_Combine_Matrix_2函數(shù)即可。
Get_Matrix函數(shù)返回當(dāng)前的世界變換矩陣,要確保傳遞給Get_Matrix函數(shù)的是當(dāng)前正在用來(lái)計(jì)算公告板矩陣(由觀察矩陣的轉(zhuǎn)置矩陣計(jì)算得出)的GRAPHICS對(duì)象。
下面的代碼演示了將3D世界中的兩個(gè)對(duì)象進(jìn)行定向的過(guò)程(一個(gè)對(duì)象附加到另一個(gè)對(duì)象之上):
WORLD_POSITION object_pos, object_pos2;
object_pos.Move(10.0, 100.0, -56.0);
object_pos.Rotate(1.571, 0.0, 0.785);
object_pos.Update(); // 計(jì)算更新的矩陣
// 將第2個(gè)對(duì)象同第1個(gè)對(duì)象進(jìn)行合并
object_pos2.Set_Combine_Matrix_1(object_pos.Get_Matrix());
object_pos2.Rotate(0.0, 0.0, 3.14);
object_pos2.Update(); // 使用合并后的矩陣計(jì)算更新的矩陣