VC++2010游戏开发随记之四十四 - 图文(5)

2019-01-12 16:02

■ 第三个参数,LPDIRECT3DDEVICE9类型的pD3DDevice,也就是我们的金钥匙,Direct3D设备的指针。

■ 第四个参数,LPD3DXBUFFER类型的*ppAdjacency,用于保存加载网格的邻接信息,也就是包含每个多边形周围的多边形信息的缓冲区的内存地址。

■ 第五个参数,LPD3DXBUFFER类型的*ppMaterials,用于保存网格的所有子集的材质,指向用于存储模型材质和纹理文件名的缓冲区的地址,而材质的数目存在之后第七个参数pNumMaterials中了。

■ 第六个参数,LPD3DXBUFFER类型的*ppEffectInstances,用于存储网格模型的特殊效果,指向用于存储模型效果实例的缓冲区的内存地址,这个参数通常设为NULL就可以了。 ■ 第七个参数,DWORD类型的*pNumMaterials,它配合着第五个参数,用于存储所有子集材质的数目。

■ 第八个参数,LPD3DXMESH类型的*ppMesh,指向我们从文件生成的Direct3D网格模型指针的地址。可以说我们调用D3DXLoadMeshFromX就是为了从文件加载X文件的模型信息并进行模型的创建,从而能得到这个指向创建好的模型的指针地址。后面关于我们创建好的网格模型的访问,都靠这个ppMesh参数了。

我们应该可以发现,在上面我们的D3DXLoadMeshFromX函数中引入了一个新的Direct3D类型,他就是LPD3DXBUFFER。LPD3DXBUFFER因数据操作的方便性而诞生,我们称它为泛型数据结构。它的好处是可以存储顶点位置坐标、材质、纹理等多种类型的Direct3D数据,而不必对每种数据都去声明一种函数接口类型。可使用接口函数

ID3DXBuffer::GetBufferPointer()获取缓冲区中的数据,使用ID3DXBuffer::GetBufferSize()获得缓冲区数据大小、这两个接口函数的声明如下:

[cpp] view plaincopyprint?

1. LPVOID GetBufferPointer(); 2. DWORD GetBufferSize();

没错,这就是原型声明,因为这两个函数都没有参数,所以他们的身子显得非常单薄。

比如,我们要从网格模型中提取材质属性和纹理文件名,那么代码就是像这样写:

[cpp] view plaincopyprint?

1. D3DXMATERIAL *pMtrls =(D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();

Ⅱ. 三步曲之二:载入材质和纹理

如果之前的D3DXLoadMeshFromX函数调用成功的话,那么参数ppMaterials就会获得.X文件中三维模型的材质和纹理等信息,而pNumMaterials参数就会获得材质的数目。 X文件中的材质信息是以D3DXMATERIAL结构类型的数组形式储存的。其中,该结构定义了D3DMATERIAL9结构类型的成员和一个指向以NULL结尾的字符串指针,而该字符串用于指定与网格子集相关的纹理贴图文件名。我们可以在MSDN中查到D3DXMATERIAL结构体的定义如下:

[cpp] view plaincopyprint?

1. typedef struct D3DXMATERIAL { 2. D3DMATERIAL9 MatD3D; //材质信息

3. LPSTR pTextureFilename; //纹理贴图文件 4. } D3DXMATERIAL, *LPD3DXMATERIAL;

当我们加载X文件后,需要遍历整个D3DXMATERIAL结构类型的数组,用于取出保存在ID3DXBuffer接口对象中的材质信息。由于X文件中并未存储具体的纹理数据,它只包含纹理贴图的文件名,因此需要我们自己根据该文件名创建相应的纹理对象。就像这样:

[cpp] view plaincopyprint?

1. // 从X文件中加载网格数据

2. LPD3DXBUFFER pAdjBuffer = NULL; 3. LPD3DXBUFFER pMtrlBuffer =NULL; 4.

5. D3DXLoadMeshFromX(L\,D3DXMESH_MANAGED, g_pd3dDevice, 6. &pAdjBuffer,&pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh); 7.

8. // 读取材质和纹理数据

9. D3DXMATERIAL *pMtrls =(D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer()

; //创建一个D3DXMATERIAL结构体用于读取材质和纹理信息 10. g_pMaterials = newD3DMATERIAL9[g_dwNumMtrls];

11. g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls]; 12.

13. for (DWORD i=0;i

15. //获取材质,并设置一下环境光的颜色值 16. g_pMaterials[i] =pMtrls[i].MatD3D;

17. g_pMaterials[i].Ambient= g_pMaterials[i].Diffuse; 18.

19. //创建一下纹理对象

20. g_pTextures[i] = NULL;

21. D3DXCreateTextureFromFileA(g_pd3dDevice,pMtrls[i].pTextureFile

name, &g_pTextures[i]); 22. } 23.

24. SAFE_RELEASE(pAdjBuffer) 25. SAFE_RELEASE(pMtrlBuffer)

Ⅲ. 三步曲之三:绘制网格模型

完成前两步做好准备工作之后,也就是生成X文件网格和材质和纹理的读取之后,接下来就是把我们准备的内容绘制出来就行了。我们依然是用ID3DXMesh接口的DrawSubset方法绘制网格中的每个子集的。但是由于绘制的部分比较多,对每个部分的绘制,我们都需要专门为其进行材质和纹理的设置,然后才进行绘制,所以一般我们在绘制从X文件读取的三维模型的时候,一般用一个for循环来进行绘制,就像这样:

[cpp] view plaincopyprint?

1. g_pd3dDevice->BeginScene(); // 开始绘制 2.

3. //用一个for循环,进行网格各个部分的绘制 4. for(DWORD i = 0; i < g_dwNumMtrls; i++) 5. {

6. g_pd3dDevice->SetMaterial(&g_pMaterials[i]); 7. g_pd3dDevice->SetTexture(0,g_pTextures[i]); 8. g_pMesh->DrawSubset(i); 9. }

10. g_pd3dDevice->EndScene(); // 结束绘制

Ⅳ.总结与升华

做一下总结,从X文件读取模型并进行绘制其实很简单,就三步工作,简明扼要十二个字,三步曲:

加载网格,加载材质纹理,绘制

核心代码如下:

[cpp] view plaincopyprint?

1. // 三步曲之一,从X文件中加载网格数据 2. LPD3DXBUFFERpAdjBuffer = NULL; 3. LPD3DXBUFFERpMtrlBuffer = NULL; 4.

5. D3DXLoadMeshFromX(L\,D3DXMESH_MANAGED, g_pd3dDevice, 6. &pAdjBuffer,&pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh); 7. 8.

9. //三步曲之二,读取材质和纹理数据

10. D3DXMATERIAL*pMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPoint

er(); //创建一个D3DXMATERIAL结构体用于读取材质和纹理信息 11. g_pMaterials= new D3DMATERIAL9[g_dwNumMtrls];

12. g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls]; 13.

14. for(DWORD i=0; i

16. //获取材质,并设置一下环境光的颜色值 17. g_pMaterials[i]= pMtrls[i].MatD3D;

18. g_pMaterials[i].Ambient= g_pMaterials[i].Diffuse; 19.

20. //创建一下纹理对象

21. g_pTextures[i] = NULL;

22. D3DXCreateTextureFromFileA(g_pd3dDevice,pMtrls[i].pTextureF

ilename, &g_pTextures[i]); 23. } 24.

25. SAFE_RELEASE(pAdjBuffer) 26. SAFE_RELEASE(pMtrlBuffer) 27.

28. void Direct3D_Render(HWND hwnd) 29. { 30.

31. g_pd3dDevice->Clear(0,NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3

DCOLOR_XRGB(100, 100, 100), 1.0f, 0); 32. //三步曲之三,绘制

33. g_pd3dDevice->BeginScene(); // 开始绘制 34.

35. //用一个for循环,进行网格各个部分的绘制 36. for(DWORD i = 0; i < g_dwNumMtrls; i++) 37. {

38. g_pd3dDevice->SetMaterial(&g_pMaterials[i]); 39. g_pd3dDevice->SetTexture(0,g_pTextures[i]); 40. g_pMesh->DrawSubset(i); 41. }

42. g_pd3dDevice->EndScene(); // 结束绘制 43. g_pd3dDevice->Present(NULL, NULL, NULL,NULL); // 翻转与显示 44. 45. }

七、详细注释的配套源代码欣赏

本篇文章的配套源代码依旧是包含四个文件,主要用于公共辅助宏定义的D3DUtil.h,用于封装了DirectInput输入控制API的DirectInputClass.h和DirectInputClass.cpp最后才是核心代码main.cpp。

其实D3DUtil.h,DirectInputClass.h以及DirectInputClass.cpp在上篇文章的配套demo的基础上并没有做任何修改,我们只是修改了main.cpp中的代码而已。但是为了大家的观看方便,浅墨依旧是把这些代码都依次贴出来。

此篇文章中我们的三维模型的素材文件选的是初音的战斗装(本来这次是想选diablo3中diablo的,但是那个看起来太暴力了,就选的这个初音)。如图:


VC++2010游戏开发随记之四十四 - 图文(5).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:郑大远程电路在线测试答案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: