本篇是
创建游戏内核(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(); // 使用合并后的矩阵计算更新的矩阵