资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级二级二级二级二级二级二级二级二级二级二级,第三级,第四级,第五级,*,第,11,章 网格,(1),在,DirectX,中,除了,ID3DXMesh,接口从,ID3DXBaseMesh,接口继承外,另一个主要的,Mesh,接口,ID3DXPMesh(Progressive Mesh),也从,ID3DXBaseMesh,接口继承,如何运用不同类型的,Mesh,接口,也将是本章讨论的内容。,主要目标:,学习,ID3DXMesh,对象的内部数据组织。,学习,ID3DXMesh,对象的创建。,学习,ID3DXMesh,对象的优化方法。,渲染,ID3DXMesh,对象。,2,11.1,几 何 信 息,ID3DXBaseMesh,接口包括了一个用于保存网格中顶点数据的顶点缓冲区和一个用于记录三角形顶点在顶点缓冲区中索引信息的索引缓冲区。,在,ID3DXBaseMesh,中,可以通过下面的方法得到指向这些缓冲区的指针:,HRESULT ID3DXMesh:GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9 *,ppVB,);,HRESULT ID3DXMesh:GetIndexBuffer(LPDIRECT3DINDEXBUFFER9 *,ppIB,);,可以通过下列方式对这些方法进行调用:,IDirect3DVertexBuffer9 *,vb,= 0;,Mesh-,GetVertexBuffer(&vb,);,IDirect3DIndexBuffer9 *,ib,= 0;,Mesh-,GetIndexBuffer(&ib,);,3,11.1,几 何 信 息,如果需要锁定缓冲区以进行缓冲区读写,可以通过下面的方法来实现,注意这里锁定的将是整个顶点缓冲区或索引缓冲区:,HRESULT ID3DXMesh:LockVertexBuffer(DWORD Flags, BYTE *,ppData,);,HRESULT ID3DXMesh:LockIndexBuffer(DWORD Flags, BYTE *,ppData,);,对锁定缓冲区的访问结束后,应该调用相应的,Unlock,方法解除缓冲区锁定,如下所示:,HRESULT ID3DXMesh:UnlockVertexBuffer();,HRESULT ID3DXMesh:UnlockIndexBuffer();,4,11.1,几 何 信 息,下面是,ID3DXMesh,接口提供的用于获得相关几何数据信息的另外几个方法:,DWORD,GetFVF,(); /,返回一个描述顶点格式的,DWORD,DWORD,GetNumVertices,(); /,返回顶点缓冲区中的顶点数目,DWORD,GetNumBytesPerVertex,(); /,返回每个顶点所用的字节数,DWORD,GetNumFaces,(); /,获得网格的面数,5,11.2,网格子集,(Subset),和属性缓冲区,网格由一个或者多个网格子集组成。网格子集是一个网格中可被按照同样属性进行渲染的三角形的集合。,图,11.1,阐述了一个代表房子的网格怎样被划分成不同的网格子集。,6,11.2,网格子集,(Subset),和属性缓冲区,每个三角形对应的子集,ID,被存储在网格的属性缓冲区中,这个缓冲区是一个,DWORD,类型的数组。由于网格中的每一个面,(,一个三角形对应一个面,),在属性缓冲区中都有一个对应的元素,因此缓冲区中的元素个数等于网格中面的数量。,图,11.2,展示了属性缓冲区中的元素与索引缓冲区中的三角形之间的对应关系。,7,11.2,网格子集,(Subset),和属性缓冲区,通过如下代码,可以锁定属性缓冲区,并获得指向属性缓冲区的指针:,DWORD *buffer = 0;,Mesh-,LockAttributeBuffer(lockingFlags, ,/.,读或写属性缓冲区,Mesh-,UnlockAttributeBuffer,();,8,11.3,网格的渲染,ID3DXMesh,接口提供了,DrawSubset,方法来渲染指定网格子集中的所有三角形。,如果要渲染整个网格,就需要渲染网格中的所有子集。可以按顺序为每个网格子集指定网格,ID,为,0,、,1,、,2,、,、,n-1,,这里,n,是网格子集的数量,然后依次指定每个网格子集对应的材质和纹理。最后,通过简单的循环就可以渲染一个完整的网格:,for(int,i=0; i,SetMaterial(mtrlsi,);,Device-SetTexture(0,texturesi,);,Mesh-,DrawSubset(i,);,9,11.4,网 格 优 化,网格的顶点和索引可以进行重新组织以便更有效率地渲染网格,即对网格进行优化。在,ID3DXMesh,接口中对网格的优化通过如下方法进行:,HRESULT ID3DXMesh:OptimizeInplace(,DWORD Flags,CONST DWORD *,pAdjacencyIn,DWORD *,pAdjacencyOut,DWORD *,pFaceRemap,LPD3DXBUFFER *,ppVertexRemap,);,10,11.4,网 格 优 化,另一个可以使用的、与,OptimizeInplace,类似的方法是,Optimize,。使用,Optimize,时,可以通过最后一个参数返回一个新的优化过的网格,而不是对所调用的网格本身进行优化。,此方法的原型如下:,HRESULT ID3DXMesh:Optimize(,DWORD Flags,CONST DWORD *,pAdjacencyIn,DWORD *,pAdjacencyOut,DWORD *,pFaceRemap,LPD3DXBUFFER *,ppVertexRemap,LPD3DXMESH *,ppOptMesh,/,通过这个参数传出优化后的网格,);,11,11.5,网格属性表,当使用,D3DXMESHOPT_ATTRSORT,标志对网格进行优化后,网格中的几何图元将被按照其属性重新划分到顶点缓冲区和索引缓冲区的连续存储块中,这些存储块就是将用于渲染的网格子集,在图,11.3,中,几何图元和对应的属性缓冲区都被按照属性排序过,因此同一种属性的几何图元在缓冲区中是连续的。,12,11.5,网格属性表,这个属性表就是一个存放,D3DXATTRIBUTERANGE,结构的数组。属性表里的每一个元素都对应到网格中的一个网格子集,用于描述这个网格子集中的几何图元在顶点缓冲区和索引缓冲区中的存储信息。,D3DXATTRIBUTERANGE,结构声明如下:,typedef,struct,_D3DXATTRIBUTERANGE ,DWORD,AttribId,;,DWORD,FaceStart,;,DWORD,FaceCount,;,DWORD,VertexStart,;,DWORD,VertexCount,;, D3DXATTRIBUTERANGE;,13,11.5,网格属性表,通过下面的方法访问网格属性表:,HRESULT ID3DXMesh:GetAttributeTable(,D3DXATTRIBUTERANGE *,pAttribTable,DWORD *,pAttribTableSize,);,这个方法可以用来完成两个任务:,返回属性表中存储的元素的数量。,通过一个,D3DXATTRIBUTERANGE,结构的数组来获得指定的属性数据。,14,11.5,网格属性表,如果需要得到属性表里面元素的数量,需要再把第一个参数赋值为,0,:,DWORD,numSubsets,= 0;,Mesh-GetAttributeTable(0, &,numSubsets,);,知道了元素的数量后,就可以直接用当前的属性表来填写,D3DXATTRIBUTERANGE,数组了,如下所示:,D3DXATTRIBUTERANGE table = new D3DXATTRIBUTERANGE ,numSubsets,;,Mesh-,GetAttributeTable(table, &,numSubsets,);,同时可以直接用,ID3DXMesh:SetAttributeTable,方法来设置属性表。下面的例子设置了一个具有,12,个网格子集的属性表:,D3DXATTRIBUTERANGE attributeTable12;,/ .fill,attributeTable,array with data,/,用当前数据填充属性表,Mesh-,SetAttributeTable(attributeTable, 12);,15,11.6,邻 接 信 息,邻接数组是一个,DWORD,类型的数组,邻接数组中的每一个元素都对应于网格中的一个三角形。比如,第,i,个元素代表了由以下这三个索引所组成的三角形:,A = i3,B = i3 + 1,C = i3 + 2,注意当邻接数组存储的元素值为,ULONG_MAX(=4294967295),时,表示三角形当前的边没有邻接三角形。,16,11.6,邻 接 信 息,由于三角形有三个边,因此每一个三角形都会有三个邻接三角形,在图,11.4,中,每一个三角形都在邻接数组里面有三个对应元素来指明与其邻接的三角形。,邻接数组的大小必须为网格中的面数的三倍,(,假设面为三角形,),,用来存放网格中每个三角形对应的三个邻接三角形的索引值。,17,11.6,邻 接 信 息,许多,D3DX,的网格创建函数都可以输出邻接信息,也可用下面的方法来获得邻接信息:,HRESULT ID3DXMesh:GenerateAdjacency(,FLOAT,fEpsilon,DWORD *,pAdjacency,);,例如:,DWORD,adjacencyInfoMesh,-,GetNumFaces,() * 3;,Mesh-GenerateAdjacency(0.001f,adjacencyInfo,);,18,11.7,网格的克隆,(Cloning),需要把一个网格的数据拷贝到另一个网格中去,这个工作可以通过,ID3DXBaseMesh:CloneMeshFVF,方法来完成:,HRESULT ID3DXMesh:CloneMeshFVF(,DWORD Options,DWORD FVF,LPDIRECT3DDEVICE9,pDevice,LPD3DXMESH *,ppCloneMesh,);,19,11.7,网格的克隆,(Cloning),注意这个方法允许目标网格的灵活顶点格式和源网格的灵活顶点格式不同。例如,假设现有的网格的灵活顶点格式为,D3DFVF_XYZ,,而需要灵活顶点格式为,D3DFVF_XYZ| D3DFVF_NORMAL,的网格,那么可以按照以下方法编写程序:,/,假定,mesh,和,device,都是可用的,ID3DXMesh *clone = 0;,Mesh-,CloneMeshFVF,(,Mesh-,GetOptions,(), /,使用与源网格同样的设置,D3DFVF_XYZ | D3DFVF_NORMAL,/,指定目标网格的,FVF,Device,20,11.8,网格的创建,(D3DXCreateMeshFVF),下面显示了如何使用,D3DXCreateMeshFVF,函数来创建一个网格:,HRESULT D3DXCreateMeshFVF(,DWORD,NumFaces,DWORD,NumVertices,DWORD Options,DWORD FVF,LPDIRECT3DDEVICE9,pDevice,LPD3DXMESH *,ppMesh,);,21,11.8,网格的创建,(D3DXCreateMeshFVF),还可以用,D3DXCreateMesh,方法来创建网格,它的原型是:,HRESULT D3DXCreateMesh(,DWORD,NumFaces,DWORD,NumVertices,DWORD Options,CONST LPD3DVERTEXELEMENT9 *,pDeclaration,LPDIRECT3DDEVICE9,pDevice,LPD3DXMESH *,ppMesh,);,22,11.8,网格的创建,(D3DXCreateMeshFVF),D3DXDeclaratorFromFVF,通过一个给定的,FVF,输出一个,D3DVERTEXELEMENT9,结构的数组。,注意这里,MAX_FVF_DECL_SIZE,是一个枚举变量,定义如下:,typedef,enum,MAX_FVF_DECL_SIZE = 18, MAX_FVF_DECL_SIZE;,23,11.9,示例:创建并渲染一个网格,本节的示例程序将渲染一个代表箱子的网格,如图,11.5,所示。,这个示例展示了在本章讨论的大部分函数,包括下面的操作:,创建一个网格。,为网格填充立方体的几何信息。,指定网格中的网格子集。,创建网格邻接信息。,优化网格。,渲染网格。,24,11.9,示例:创建并渲染一个网格,在函数中首先创建一个网格:,bool,Setup(),HRESULT hr = 0;,hr = D3DXCreateMeshFVF(,12,24,D3DXMESH_MANAGED,Vertex:FVF,Device,要完成这些工作,先锁定这两个缓冲区,然后把数据填写到缓冲区中:,参见教材,P170,25,11.9,示例:创建并渲染一个网格,在这个示例中,指定索引缓冲区里的前,4,个三角形存在于网格子集,0,中,接下来,4,个三角形存在于网格子集,1,中,最后,4,个三角形,(,总共,12,个,),存在于网格子集,2,中,可以通过下面的代码来完成这些工作:,参见教材,P170,在优化网格之前,必须要计算出网格的邻接信息:,std:vector,adjacencyBuffer(Mesh,-,GetNumFaces,() * 3);,Mesh-GenerateAdjacency(0.0f, ,然后就可以进行网格的优化了:,hr = Mesh-,OptimizeInplace,(,D3DXMESHOPT_ATTRSORT,|D3DXMESHOPT_COMPACT,|D3DXMESHOPT_VERTEXCACHE,&adjacencyBuffer0,0, 0, 0);,26,11.9,示例:创建并渲染一个网格,下面通过这个示例输出的,Mesh,Dump.txt,文件中的内容,展示通过,dumpAttributeTable,(),函数输出的网格属性表信息:,参见教材,P172,可以发现这些数据与我们为网格所指定的数据,(3,个网格子集、每个网格子集里面有,4,个三角形,),完全吻合。,最后,可以用下面的代码来渲染网格,在渲染方法中循环遍历每一个网格子集,设置相关的纹理,然后渲染网格子集。,27,11.9,示例:创建并渲染一个网格,渲染实际上是一个很简单的工作:,bool,Display(float,timeDelta,),if(Device,),/ .,这里更新,Frame,的代码忽略掉了,Device-Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0x00000000, 1.0f, 0);,Device-,BeginScene,();,for(int,i=0; iSetTexture(0,Texturesi,);,Mesh-,DrawSubset(i,);,Device-,EndScene,();,Device-Present(0, 0, 0, 0);,return true;,28,11.10,小 结,一个网格包括了顶点、索引和属性缓冲区。顶点和索引缓冲区存放了网格的几何信息,(,顶点和三角形,),。属性缓冲区为每个三角形保存了一个相应的元素,它指定了三角形所处的网格子集。,网格可以用,OptimizeInplace,或者,Optimize,方法来优化。优化可以令网格的渲染更有效率。在优化网格时,如果指定了,D3DXMESHOPT_ATTRSORT,标志位,将生成一个属性表。如果有属性表,网格就可以通过一个简单的查询属性表操作来渲染整个网格子集。,网格的邻接信息是一个,DWORD,数组,网格中的每个三角形在这个数组中都对应了三个索引值,这三个索引值分别指定与这个三角形所邻接的三个三角形。,可以通过,D3DXCreateMeshFVF,方法来创建空网格,然后通过合适的锁定方法,(,LockVertexBuffer,、,LockIndexBuffer,和,LockAttributeBuffer,),向网格中写入有效的数据。,29,
展开阅读全文