自己写游戏引擎——Get your hands dirty!!! (02)

 

自己写游戏引擎——Get your hands dirty!!! (02)

分类: 游戏引擎   3949人阅读  评论(0)  收藏  举报
       关于Buffer的类型,在dx里面有static 和 dynamic两种,区别在于是一开始就分配好固定的Buffer区域或者让dx来管理(类似托管)。运行时的区别在于 效率:如果不用修改buffer的内容,那么用static很容易高效的命中显卡的缓冲区;如果是需要对buffer 的内容进行大量的修改,那么用dynamic可以减少数据大批的流过bus,从而提高运行时的性能。这一点对于IndexBuffer也是一样。
       在完成了DXVertexBuffer的实现之后,我们可以建立一个测试项目。其中的关键代码:
    g_pXVertexBuffer -> Create(  50 * 2 * sizeof (CUSTOMVERTEX), D3DFVF_CUSTOMVERTEX,  0 , UHEPOOL_DEFAULT );
   

    CUSTOMVERTEX
*  pVertices;
    g_pXVertexBuffer
-> Lock();
    pVertices 
=  ( CUSTOMVERTEX  *  )g_pXVertexBuffer -> GetLockedData();
    
    
for ( DWORD i = 0 ; i < 50 ; i ++  )
    
{
        FLOAT theta 
= (2*D3DX_PI*i)/(50-1);

        pVertices[
2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
        pVertices[
2*i+0].color    = 0xffffffff;

        pVertices[
2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
        pVertices[
2*i+1].color    = 0xff808080;
    }

    g_pXVertexBuffer
-> Unlock();
 
       代码中有宏UHEPOOL_DEFAULT,这是类似D3DPOOL_DEFAULT这样的作用的宏,表示的是buffer的类型。在引擎的核心部分,有很多基本的宏,一般都是和渲染的各种参数有关(ps:我对gl的具体api没有太多的了解,所以暂时将大部分的宏定义成和dx中一样的值;在后面的工作中,我会和我的roommate再讨论这些问题,毕竟公共部分是必须相当稳定的,不能有太大的改动)。
       继续,我们渲染VertexBuffer:
VOID Render()
{
    
// Clear the backbuffer and the zbuffer
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
                         D3DCOLOR_XRGB(
0,0,255), 1.0f0 );

    
// Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    
{
        SetupMatrices();

        
// Render the vertex buffer contents
        g_pd3dDevice->SetStreamSource( 0, g_pVB, 0sizeof(CUSTOMVERTEX) );
        g_pd3dDevice
->SetFVF( D3DFVF_CUSTOMVERTEX );
        g_pd3dDevice
->DrawPrimitive( D3DPT_TRIANGLESTRIP, 02*50-2 );
        
// End the scene
        g_pd3dDevice->EndScene();
    }


    
// Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

       在后面,我们也许会加入其他的接口或者实现,g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*50-2 )这样的调用很不好看。
 
       一样的,完成了VertexBuffer以后,我们可以开始写IndexBuffer,大部分的接口都是一样的,这里就不再罗嗦了。
       写完了这两个组件之后,我们的工作仍然还游历在引擎内核之外,和渲染器之间也没有任何联系。原因在于VertexBuffer 和 IndexBuffer 都太过于底层,对于引擎的渲染器来说,我们还是需要更高的抽象层面,这就是为什么这两个对象没有Render()这样的接口了。在后面会有RenderPass这样的类来管理他们。
       先把这个放一方,花长一点的时间做仔细的考虑,先写一些简单的管理(这里值得是设计)。
        开始写 TextureMng 。对于 DX 来说,这不是个很难写的类,因为 DX 提供了比较“无敌”的接口,可以读取绝大多数的纹理格式;如果是 gl ,这里还要加入外部的解析库了。看一下接口:
// file: UHETextureMng.h
#ifndef _INCLUDE_UHETEXTUREMNG_H
#define  _INCLUDE_UHETEXTUREMNG_H

#include 
" UHEPrerequisites.h "
#include 
" UHEBasicStruct.h "
#include 
" UHEBasicType.h "

namespace  UHEngine
{
    
class TextureMng
    
{
    
public:
        
// add a already-created tex.
        virtual void Add( UHETEXTURE * pTex ) = 0;

        
// create a tex from file.
        virtual void Create( UHETEXTURETYPE texType, 
                             UHETEXTUREUSAGE texUsage,  
                             
char *chName, 
                             
bool bAlpha = false
                             
float fAlpha = 1.0f
                            ) 
= 0;

        
// delete a tex by the index in the vector.
        virtual void Delete( UHETEXTURETYPE texType, WORD texID )                        = 0;
        
        
// delete all tex. 
        virtual void DeleteAll()                                                        = 0;

        
// return tex, located by index in the vector.
        virtual UHETEXTURE *GetTexByID( UHETEXTURETYPE texType, WORD texID )            = 0;

        
// return tex, located by name of the tex.
        virtual UHETEXTURE *GetTexByName( UHETEXTURETYPE texType, char *chName )        = 0;
        
        
// return the index of the tex in the vector by its name.
        virtual int GetIDByName( UHETEXTURETYPE texType, char *chName )                    = 0;
        
        
// use tex located by its index.
        virtual void UseTex( UHETEXTURETYPE texType, WORD texID, WORD stage )            = 0;
        
        
// use tex located by its name.
        virtual void UseTex( UHETEXTURETYPE    texType, char *chName, WORD stage )            = 0;
    }
;
}

#endif
在看一下dx渲染器中的头文件 
// file: UHEDX9TextureMng.h
#ifndef _INCLUDE_UHEDX9TEXTUREMNG_H
#define  _INCLUDE_UHEDX9TEXTUREMNG_H

#include 
" UHEDX9RenderBase.h "

namespace  UHEngine
{
    
class DX9TextureMng : public TextureMng
    
{   
    
public:
        DX9TextureMng( LPDIRECT3D9 
& pDX9, LPDIRECT3DDEVICE9 & pDevice );
        
~DX9TextureMng();

        
void Add( UHETEXTURE * pTex );
        
void Create( UHETEXTURETYPE texType, 
                     UHETEXTUREUSAGE texUsage,  
                     
char *chName, 
                     
bool bAlpha = false
                     
float fAlpha = 1.0f
                    );
        
void Delete( UHETEXTURETYPE texType, WORD texID );
        
void DeleteAll();

        UHETEXTURE 
*GetTexByID( UHETEXTURETYPE texType, WORD texID );
        UHETEXTURE 
*GetTexByName( UHETEXTURETYPE texType, char *chName );
        
int GetIDByName( UHETEXTURETYPE texType, char *chName );

        
void UseTex( UHETEXTURETYPE texType, WORD texID, WORD stage );
        
void UseTex( UHETEXTURETYPE    texType, char *chName, WORD stage);

    
private:
        LPDIRECT3D9            m_pDX9;
        LPDIRECT3DDEVICE9    m_pDevice;
        
        UHETEXTUREVECTOR    m_Tex1D;
        UHETEXTUREVECTOR    m_Tex2D;
        UHETEXTUREVECTOR    m_Tex3D;
        UHETEXTUREVECTOR    m_Tex4D;
    }
;
}

#endif
这里说一下这个类的设计:不好!第一,用Map来实现比较好一些,(可以看一下ogre的代码),这样做只是简单的重复已经写得很好的Map;第二,文件名用的是char*,这样也不好,没有用Unicode,而且不如string方便和安全;第三,这个接口就是简单而已。。。
其中的UHETEXTUREVECTOR为std::vector<UHETEXTURE*>,而用了四个这样的容器,为了存储不同“维度”的纹理(具体可以看一下dx sdk里面的文档)。而内存模型没有过多的考虑,因为这里是用的指针,而不是直接的对象,在vector中进行添加元素没有效率影响,但是考虑到很多纹理的时候,这种设计的有一个不好的地方就体现出来了。每一次添加新的纹理的之前,都要在内存里面分配一块区域,这种实现可以用对象池来改进,关于对象池,可以看一下C++的优化方面的书,或者直接看一下zfx engine的代码,它的纹理管理就是用的对象池优化的。
(今天先写道这里,挺花时间的。。。)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值