在D3DX中,有很多函数都使用了ID3DXMesh接口,如D3DXCreate*之类。ID3DXMesh接口的主要功能继承自ID3DXBaseMesh父类接口,还有其他的Mesh接口也是从ID3DXBaseMesh接口继承的,如ID3DXPMesh接口,这个接口用于Progressive Mesh,把它翻译成“渐进Mesh”,不知是否合适。
本节要达到的目标:
l 学习ID3DXMesh对象的内部数据组织
l 学习创建一个ID3DXMesh对象
l 学习优化ID3DXMesh
l 学习渲染ID3DXMesh
10.1. 几何结构信息
接口ID3DXBaseMesh具有顶点缓冲和顶点索引缓冲,分别用于存储Mesh的顶点数据和顶点的索引数据,二者结合在一起才能够渲染出组成Mesh的三角形。使用下面的两个方法可得到指向两个缓冲区的指针:
HRESULT ID3DXMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB); HRESULT ID3DXMesh::GetIndexBuffer(LPDIRECT3DINDEXBUFFER9* ppIB); |
下面是一个关于上述两个方法用法的例子:
IDirect3DVertexBuffer9* pVB=NULL; Mesh->GetVertexBuffer(&pVB);
IDirect3DIndexBuffer9* pIB=NULL; Mesh->GetIndexBuffer(&pIB); |
另外,如果想修改顶点缓冲和顶点索引缓冲,需要先使用下面的两个方法加锁:
HRESULT ID3DXMesh::LockVertexBuffer(DWORD Flags,LPVOID* ppData); HRESULT ID3DXMesh::LockIndexBuffer(DWORD Flags,LPVOID* ppData); |
参数Flags用于说明加锁的方式,参数ppData返回被锁定的内存的地址。记住,如果加锁成功还需要调用与之配对的解锁函数:
HRESULT ID3DXMesh::UnlockVertexBuffer(); HRESULT ID3DXMesh::UnlockIndexBuffer(); |
下面是另外一些与Mesh的几何结构有关的ID3DXMesh接口的方法:
l DWORD GetFVF(); --返回顶点的格式
l DWORD GetNumVertices(); --返回顶点缓冲中的顶点数
l DWORD GetNumBytesPerVertex(); --返回一个顶点所占的字节数
l DWORD GetNumFaces(); --返回Mesh的面数,也就是三角形数
10.2. 子集和属性缓冲
一个Mesh由数个子集组成。子集是Mesh中的一组使用相同属性渲染的三角形。这里的属性指的是材质、纹理、渲染状态。每一个子集用一个唯一的非负整数表示其ID,如0,1,2,3等。
Mesh中的每一个三角形都与一个属性ID相关联,表示该三角形属于该子集。例如,在一个表示房子的Mesh中,组成地板的三角形具有属性ID 0,这就表示这些三角形属于子集0;同样的,组成墙的三角形的属性ID为1,他们属于子集1。
三角形的属性ID存储在Mesh的属性缓冲中,这是一个DWORD数组。因为每个面对应属性缓冲中的一项,所以属性缓冲中的项目数等于Mesh中的面的个数。属性缓冲中的项目和索引缓冲定义的三角形一一对应;也就是说,属性缓冲的第I项和索引缓冲中定义的第I个三角形相对应。三角形I有下面三个索引缓冲中的索引项定义:
A=I*3
B=I*3 + 1
C=I*3 + 2
可以使用下面的方法访问属性缓冲:
DWORD* buffer=NULL; Mesh->LockAttributeBuffer(lockingFlags,&buffer); // do something... Mesh->UnlockAttributeBuffer(); |
10.3. 渲染
接口ID3DXMesh提供了DrawSubset(DWORD AttribID)方法渲染参数AttribID指示的子集中的各个三角形。例如,如果渲染子集0中的所有三角形,可以使用如下方法:
Mesh->DrawSubset(0); |
如果要渲染整个Mesh,需要分别渲染Mesh的各个子集。因为子集序列与Mesh使用的材质、纹理的序列相对应,即子集I和材质、纹理数组的第I项对应,所以可以使用一个简单的循环渲染Mesh