天行健 君子当自强而不息

创建游戏内核(5)


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

posted on 2007-08-29 00:57 lovedday 阅读(429) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论