本篇是
創建游戲內核(4)的續篇,其中涉及到矩陣以及坐標系統變換的知識請參閱
DirectX
9的一些數學計算函數:矩陣,坐標變換。以及
DirectX
9的坐標系統變換。
圖形內核
圖形內核是游戲內核最主要的部分,也是最大和最復雜的內核對象,下表列出了圖形內核中的類:
圖形內核組件
|
類 |
說明 |
GRAPHICS |
處理Direct3D的初始化,啟用狀態渲染以及設置紋理,材質和光照。 |
TEXTURE |
含有一個紋理以及一個用于將紋理的2D部分繪制到顯示器上的函數。 |
MATERIAL |
含有一個材質的定義 |
LIGHT |
含有一個光照的定義 |
FONT |
封裝了ID3DXFont對象 |
VERTEX_BUFFER |
使對頂點緩沖的處理變得更容易 |
WORLD_POSITION |
操縱世界變換矩陣,使程序員能夠快速定位、縮放和旋轉對象。 |
CAMERA |
包含一個觀察變換矩陣,可以使用該對象的接口修改此矩陣。 |
MESH |
包含從一個 .X
文件加載的網格的列表以及這些網格的材質,MESH類要同OBJECT類結合起來使用。 |
OBJECT |
表示3D世界中的一個對象,OBJECT類控制了對象的方位、網格以及動態狀態。 |
ANIMATION |
包含從一個 .X 文件加載的動畫列表,ANIMATION
類要同OBJECT類結合起來使用。 |
其中GRAPHICS對象是所有圖形內核對象的基礎。
世界變換和WORLD_POSITION
雖然處理世界變換矩陣并不難,但是用一個類來處理諸如世界坐標、旋轉值以及縮放因子等所有細節,就更簡單明了。另外,這個類中還加入了公告板技術。
來看看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的實現:
/*************************************************************************
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函數使用內含的方位重新創建世界變換矩陣,要考慮的矩陣有公告板矩陣以及兩個外部矩陣(稱之為組合矩陣, combined
matrices)。要設置兩個組合矩陣的來源,使用Set_Combine_Matrix_1和Set_Combine_Matrix_2函數即可。
Get_Matrix函數返回當前的世界變換矩陣,要確保傳遞給Get_Matrix函數的是當前正在用來計算公告板矩陣(由觀察矩陣的轉置矩陣計算得出)的GRAPHICS對象。
下面的代碼演示了將3D世界中的兩個對象進行定向的過程(一個對象附加到另一個對象之上):
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(); // 計算更新的矩陣
// 將第2個對象同第1個對象進行合并
object_pos2.Set_Combine_Matrix_1(object_pos.Get_Matrix());
object_pos2.Rotate(0.0, 0.0, 3.14);
object_pos2.Update(); // 使用合并后的矩陣計算更新的矩陣