设计本身的3D图像引擎(4):WuguiEngine之模子、特效、贴图
副标题#e#
1. 媒介
话说有一段时间没有更新了,这段时间好好玩了一下,也抽闲写了一点措施,把八叉树场景打点写了,也优化了一点资源加载的一些内容。之前对DirectX的好些处所照旧没有弄清楚,此刻对这些处所至少有了更多的相识。发一下本日完成的八叉树场景打点,内里的模子用的是DirectX示例的老虎,这儿看不太清楚–;
本日主要说说我的引擎中的模子,特效,贴图的实现,至少把或许的意思说清楚。假如尚有不懂的处所可以跟我接洽。
2. 模子、特效、贴图的资源复用
各人也可以看到了,上面那张图上的老虎不止一个,当同一个模子的数目多到必然水平(好比说10000个),就要思量必然的优化了,假如每次都傻傻的从文件中把模子读取出来,生存为一个ID3DXMesh,那不只加载的时间慢的令人无法忍受,并且淹灭的内存同样庞大。在WuguiEngine中,我利用了一个较量简朴的要领来办理这个问题。
设计模式的中心思想就是对修改封锁,对扩展开放,中心思想就是“变革”,可是很欠盛情思的说,我对D3D一知半解,在许多时候甚至不清楚“变革”将呈此刻什么处所,所以我利用的要领,很简朴,此刻用起来很清晰,可是假如对之后的扩展支持欠好可能有更好的架构要领还望各人指点。本系列文章的宗旨就是抛砖引玉。
我利用了一个简朴的Map来完成这些内容下面给出资源打点器(ResourceManager)的界说
1: class GraphicsDevice;
2:
3: //资源的范例
4: enum ResourceType
5: {
6: RTTexture = 0,
7: RTMesh = 1,
8: RTEffect = 2,
9: };
10:
11: //一个资源的描写
12: //由ResourceType,Void*范例的指针pResource,引用次数useCount构成
13: typedef struct StructRes
14: {
15: public:
16: StructRes(void* pRes, ResourceType type)
17: {
18: pResource = pRes;
19: useCount = 1;
20: resourceType = type;
21: }
22: ResourceType resourceType;
23: void* pResource;
24: int useCount;
25: } StructRes;
26:
27: //资源打点器
28: class ResourceManager
29: {
30: public:
31: static ResourceManager* GetInstance();
32:
33: //按照文件名获取资源文件
34: void* GetD3DResource(string filename,
35: GraphicsDevice* pDevice,
36: ResourceType type);
37:
38: //按照文件名卸载资源文件
39: void DisposeD3DResource(string filename);
40: protected:
41: ResourceManager();
42:
43: map<string, StructRes*> resourceTable;
44: static ResourceManager* pInstance;
45: };
#p#副标题#e#
下面临代码举办一点表明:
ResourceType故名思意就是资源的范例,在今朝阶段,由贴图,特效,模子构成。
StructRes是每一个资源的布局体,内里的void*指针指向所包括数据的内存。所包括数据的中心思想就是“生存公有的内容”。譬喻对付一个模子来说:极点数据是公有的内容,可是贴图就纷歧样了,一个立方体可以贴成一个骰子,也可以贴成一个箱子,尚有模子的位置也不属于公有的内容。之后在讲到模子的时候我将会更具体的表明这个处所
ResourceManager就是我们措施中资源打点器了。在这儿设计成为单件模式,假如看了我之前几篇文章的伴侣们大概会发明我出格喜欢用单件模式,大概是我不喜欢把一个指针老当成参数传来传去吧,呵呵。
在ResourceManager中最重要的第一是数据布局,在今朝我利用的STL中的map。
1: map<string, StructRes*> resourceTable;
第一个参数string在今朝是资源的文件名,今朝引擎还不具备文件系统,读取文件的时候就直接利用的文件名,假如具有一个完整的文件系统,不只可以从硬盘中,还可以从内存中,压缩文件中,并且还可以在多个位置按先后顺序查找。StructRes*就是之前提过的布局体了。
ResourceManager最重要的要领是GetD3DResource
1: void* ResourceManager::GetD3DResource(string filename, GraphicsDevice* pDevice,
2: ResourceType type)
3: {
4: ResTable::iterator pResult = resourceTable.find(filename);
5:
6: //假如找到了对应的资源(已加载)
7: if (pResult != resourceTable.end())
8: {
9: (*pResult).second->useCount ++;
10: return (*pResult).second->pResource;
11: }
12: ..........
ResTable就是resourceTable的范例,stl的范例写起来太长了,就用typedef处理惩罚了一下。
#p#分页标题#e#
从第4行开始就是查找资源, 首先看看这个文件名所对应的资源是否存在,假如存在,就返回,代码都是挪用的根基stl的函数,假如看不太大白可以翻翻stl的辅佐文件。
1: //假如没有找到对应的资源
2: else
3: {
4: //假如是需要载入贴图
5: if (type == ResourceType::RTTexture)
6: {
7: IDirect3DTexture9* pTexture;
8:
9: //从filename中建设Texture
10: LPSTR str = UtilityTools::ConvertStringLPSTR(&filename);
11: if (D3DXCreateTextureFromFileExA(pDevice->GetLPDIRECT3DDEVICE9(),
12: str,
13: D3DX_DEFAULT, //width
14: D3DX_DEFAULT, //height
15: D3DX_DEFAULT, //levels
16: 0, //usage
17: D3DFMT_UNKNOWN, //format
18: D3DPOOL_MANAGED, //pool
19: D3DX_DEFAULT,
20: D3DX_DEFAULT,
21: 0,
22: NULL,
23: NULL,
24: &pTexture) != D3D_OK)
25:
26: {
27: throw "Exception To Create Texture";
28: }
29: delete str;
30:
31: //在Table中插手这个Resource
32: StructRes* pRes = new StructRes(pTexture, type);
33: resourceTable.insert(make_pair(filename, pRes));
34:
35: return pTexture;
36: }
37: else if (type == ResourceType::RTMesh)
38: {
39: .......
40: }
41: else if (type == ResourceType::RTEffect)
42: {
43: .......
44: }
接着上面的代码,假如对应文件名的资源没有存在,则按照资源的范例举办加载,挪用API函数。
这段代码应该照旧较量好领略的,这里就不说了。
贴一段用的时候的代码,以Texture为例,好比需要获取一份IDirect3DTexture9*(pTexture)的资源。
1: ResourceManager* pResourceMgr = ResourceManager::GetInstance();
2:
3: pTexture = (IDirect3DTexture9*)(pResourceMgr->
4: GetD3DResource(_filename, device,ResourceType::RTTexture));
别的尚有一个处所就是资源的释放,在StructRes中有一个useCount, 当被引用一次+1,被释放一次-1,最后一个出门的人就关灯锁门了。
3. 模子
之前将了一下资源复用,以贴图为例。贴图的内容相比拟力简朴,只需要生存一个引用IDirect3DTexture9*范例的指针就好了,可是模子就纷歧样,模子涉及到许多操纵,好比说获取mesh的VertexBuffer,IndexBuffer等等,这些内容也同样需要在ResourceManager中加载,因为他们也是“公有”的内容。
为了更利便的利用模子,我插手了ModelResource类,生存模子中的公有数据
下面就贴上ModelResource的界说
1: class ModelResource : IDisposed
2: {
3: public:
4: ModelResource(string _filename, GraphicsDevice* device);
5: virtual void Dispose();
6:
7: ID3DXMesh* GetD3DMesh();
8: IDirect3DVertexBuffer9* GetVertexBuffer();
9: IDirect3DIndexBuffer9* GetIndexBuffer();
10: BoundingSphere* GetOriginalSphere();
11: protected:
12: void Initialize();
13: void CalculateBoundingSphere();
14:
15: string filename;
16: GraphicsDevice* pDevice;
17: ID3DXMesh* pMesh;
18: IDirect3DVertexBuffer9* pVertexBuffer;
19: IDirect3DIndexBuffer9* pIndexBuffer;
20: BoundingSphere* pOriginalSphere;
21: DWORD FVF;
22: };
我在ModelResource中生存有VertexBuffer,IndexBuffer。OriginalSphere是模子加载时候的困绕球,也是属于公有的,利便做调动的时候利用。
代码详细介入ModelResource.cpp,这里就不具体的说了。
模子类中还包括有Material类(主要包括贴图),Transformation类(包括调动),这些代码都是较量好懂的,就纷歧一表明白。
4. 示例
本节的示例代码在Mainlogic中的Example2中可以找到
初始化一个模子,并插手贴图与Effect的代码看起来像这个样子:
#p#分页标题#e#
1: //初始化模子
2: pModel = new Model("Content\\Tiger.x", pDevice);
3: pModel->SetDiffuseMap("Content\\Tiger.bmp");
4: pModel->SetPosition(D3DXVECTOR3(0,0,-20));
5:
6: //初始化模子的属性
7: pModel->SetEffect(new SimpleEffect(pDevice, pModel, "SimpleTexture.fx"));
8: pModel->GetEffect()->Initialize();
很简朴吧。