关于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.0f, 0 );

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

// Render the vertex buffer contents
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*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的代码,它的纹理管理就是用的对象池优化的。
(今天先写道这里,挺花时间的。。。)