网页功能: 加入收藏 设为首页 网站搜索  
自己写游戏引擎(01)
发表日期:2007-03-28作者:[转贴] 出处:  

写了几个月的游戏引擎,有一些想法需要总结结一下,也想和同我水平差不多的朋友,或者比我水平还要菜的cn们分享一下,高手莫笑~~
这里的想法是,尽量和大家分享我的过程,我写的东西很烂(我的确这样觉得),我会在文中写下来我觉得还存在问题的地方,需要改进的地方,或者还没有想到很好解决的地方;希望同大家相互讨论,也非常欢迎高手们的建议和批评.Just for FUN! OK.
(ps:文中的代码都是片断,these don’t compile,如果你想要部分代码,可以和我联系,在引擎完成得差不多的时候我会邮给你,我的邮箱:xjyhust@gmail.com or xjyhust@126.com. )
 
  目标是写一个多渲染器的游戏引擎,先来谈其中的图形渲染部分,毕竟这个是关键,如果你想了解物理,网络或者其他的内容,很遗憾,这里没有(也许要等到很后面的了)。可以看一下我之前写的两篇blog,《游戏引擎中多渲染器的设计与实现》(1,2),里面讲到了用动态链接库实现的一种的方法,这里就不复习了,假设你已经完成了前面最基本的实现。
 
  引擎的核心部分是一切的前提,所以我们从这里开始。我强烈建议你在开始动手之前先看一下常用的3d模型的格式的解析——因为引擎的底层的基本数据类型的设计是非常重要,而且在后面是相当难以改动的——看一下常用的模型格式的解析,可以帮助你设计合理的底层数据类型(这里指的是像纹理,材质,三角形等的表示)。先以MilkShape 3D的格式MS3D为例。在他们的网站上,你可以下到一个C++解析组件,先看头文件中的数据类型:
typedef struct
{
    
byte    flags;                                      // SELECTED | SELECTED2 | HIDDEN
    float   vertex[3];                                  //
    char    boneId;                                     // -1 = no bone
    byte    referenceCount;
}
 ms3d_vertex_t;

typedef 
struct
{
    word    flags;                                      
// SELECTED | SELECTED2 | HIDDEN
    word    vertexIndices[3];                           //
    float   vertexNormals[3][3];                        //
    float   s[3];                                       //
    float   t[3];                                       //
    byte    smoothingGroup;                             // 1 - 32
    byte    groupIndex;                                 //
}
 ms3d_triangle_t;

typedef 
struct
{
    word edgeIndices[2];
}
 ms3d_edge_t;

typedef 
struct
{
    
byte            flags;                              // SELECTED | HIDDEN
    char            name[32];                           //
    word            numtriangles;                       //
    word*            triangleIndices;                    // the groups group the triangles
    char            materialIndex;                      // -1 = no material
}
 ms3d_group_t;

typedef 
struct
{
    
char            name[32];                           //
    float           ambient[4];                         //
    float           diffuse[4];                         //
    float           specular[4];                        //
    float           emissive[4];                        //
    float           shininess;                          // 0.0f - 128.0f
    float           transparency;                       // 0.0f - 1.0f
    char            mode;                               // 0, 1, 2 is unused now
    char            texture[128];                        // texture.bmp
    char            alphamap[128];                       // alpha.bmp
}
 ms3d_material_t;

  从代码中可以看出,Texture和Material都有name,都有fileName(指的是贴图文件名),Material中有4中颜色(这和图形学里面的物理意义也是一致的),然后就是Texture可以是alpha贴图,有属性transparency,这些都可以作为我们设计的参考。我们就停在这里,在后面我们还会看到这个经典的格式是怎样影响了我们的渲染批次的设计的。
 
  开始建立基础的数据类型:
    typedef struct _colorStruct
    
{
        
float r;
        
float g;
        
float b;
        
float a;
    }
UHECOLOR;

    typedef 
struct _materialStruct
    
{
        UHECOLOR Diffuse;
        UHECOLOR Ambient;
        UHECOLOR Specular;
        UHECOLOR Emissive;
        
float Power;
    }
UHEMATERIAL;

    typedef 
struct _textureStruct
    
{
        
bool    bAlpha;
        
float   fAlpha;
        
char    chName[128];
        
void    *pData;
        WORD    texType;
        WORD    texUsage;
    }
UHETEXTURE;

  这里很奇怪的是,我在Texture里面用了一个void*。恩,这个是用来存储不同API中的纹理。比如,如果是用的DX,我会一直把这个 void*看成LPDIRECT3DTEXTURE9*。在引擎中,我会大量的用到指针间的静态转换(非运行时)(hard core c++高手看到我的代码会说应该用static_cast,而不是用c语言里面的(typename)(…)。恩,我同意,只是有时候我忘了,或者懒了)。
 
  有很多的引擎,会将Texture单独的抽象成一个类,有相应的行为(成员函数);但是,我觉得,Texture的实质是一堆数据,既然Texture Manager(纹理管理器,简记为TextureMng)是必要的,那么单独的Texture的类的设计似乎没有太多的必要,我们有TextureMng的管理,这样似乎足够了,我暂时不想把事情搞得太复杂。
(ps:面对对象是很好的方法,但是引擎中的很多“东西”的实质还是数据的集合,在把他们变成类之前,考虑一下于他们相关的操作,考虑一下用类实现一些很小的数据体的时候效率的影响。。。像Quake3和Ogre就是两个设计的极端,是不是有时候结合两者会好一些?)
 
  还有很多的数据类型要写,比如很多的3D中的数学类,像Vector3,Matrix4,先把他们放一下。我比较喜欢迭代开发的感觉——用比较短的周期,作出简单的可运行的程序,然后在改进。好,我们就以dx sdk里面的例子开始,先实现一个Vertex的例子。
 
  我们需要定义一个VertexBuffer的抽象类,来给GL和DX提供公共的接口。
//File: UHEVertexBuffer.h
#ifndef _INCLUDE_UHEVERTEXBUFFER_H
#define _INCLUDE_UHEVERTEXBUFFER_H

namespace UHEngine
{
    
class _UHE_Export VertexBuffer
    
{
    
public:
        
// init and malloc a bunch of memory.
        virtual void    Create( UINT length, DWORD dwFVF, DWORD dwUsage, DWORD dwPoolType )     = 0;

        
// lock the whole buffer.
        // then can write to the buffer using GetLockedData() .
        virtual void    Lock()                                                                 = 0;

        
// unlock the locked data.
        virtual void    Unlock()                                                             = 0;

        
// delete .
        virtual void    Release()                                                             = 0;
        
        
// return the vertex buffer.
        // ex. in dx, this would be trans to LPDIRECT3DVERTEXBUFFER9 .
        virtual void    *GetVertexBuffer()                                                     = 0;
        
        
// return the addr of buffer after method Lock() .
        virtual void    *GetLockedData()                                                     = 0;
        
        
// return FVF type of vertex in the buffer.
        virtual DWORD    GetFVF()                                                             = 0;
        
        
// return the length of buffer( actual length in memory ).
        virtual UINT    GetLength()                                                             = 0;
        
        
// return Usage of vertex in the buffer.
        virtual DWORD    GetUsage()                                                             = 0;
        
        
// reutrn pool management type.
        virtual DWORD   GetPoolType()                                                         = 0;
    }
;
}

#endif
(ps:多渲染器引擎中,用抽象类(纯虚类)是一种实现中的设计,即使用不同的API的底层实现,对于用户来说,都是同一接口)

  在DX9渲染器中我们加入文件,UHEDX9VertexBuffer.h和UHEDX9VertexBuffer.cpp。
//File: UHEDX9VertexBuffer.h
#ifndef _INCLUDE_UHEDX9VERTEXBUFFER_H
#define _INCLUDE_UHEDX9VERTEXBUFFER_H

#include "UHEDX9RenderBase.h"
#include "UHEVertexBuffer.h"

namespace UHEngine
{
    
class _UHE_Export DX9VertexBuffer : public VertexBuffer
    
{
    
public:
        DX9VertexBuffer( LPDIRECT3D9 &pDX9, LPDIRECT3DDEVICE9 &pDevice )            ;
        ~DX9VertexBuffer()                                                            ;

        
void    Create( UINT length, DWORD dwFVF, DWORD dwUsage, DWORD dwPoolType ) ;
        
void    Lock()                                                                ;
        
void    Unlock()                                                            ;
        
void    Release()                                                            ;
        
        
void    *GetVertexBuffer() return (void*)m_pDXVertexBuffer; }                ;
        
void    *GetLockedData() return (void*)m_pData; }                            ;
        DWORD    GetFVF() 
return m_dwFVF; }                                        ;
        UINT    GetLength() 
return m_length; }                                    ;
        DWORD    GetUsage() 
return m_dwUsage; }                                    ;
        DWORD   GetPoolType()
return m_dwPoolType; }                                ;    
                                                                                     
    
private:
        LPDIRECT3D9                    m_pDX9              ;
        LPDIRECT3DDEVICE9            m_pDevice          ;

        LPDIRECT3DVERTEXBUFFER9        m_pDXVertexBuffer ;
        
void                        *m_pData          ;
        
bool                        m_bIsLocked          ;

        DWORD                        m_dwFVF              ;
        UINT                        m_length          ;
        DWORD                        m_dwUsage          ;
        DWORD                        m_dwPoolType      ;
    }
;
}

#endif
  在UHEDX9VertexBuffer.cpp中,完成这些实现(看一下dx sdk,没有什么值得多说的了)
  先写到这里,明天继续。。。
我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 自己写游戏引擎(01)
本类热点文章
  DDraw和D3D立即模式编程手册
  矩阵求逆的快速算法
  本地化支持:OGRE+CEGUI中文输入:OGRE方..
  Direct3D中实现图元的鼠标拾取
  3D场景中的圆形天空顶
  OpenGL显卡编程
  一种高效的基于大规模地形场景的OCCLUS..
  一个完善的读取3DS文件例子
  如何制作一个可控制的人体骨骼模型
  Direct3D 入门之我见
  Slope(斜坡) 法线生成算法,在地形渲染..
  在Direct3D中渲染文字
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00555