The input mesh must have the D3DFVF_NORMAL flag specified in its flexible vertex format (FVF). A normal for a vertex is generated by averaging the normals of all faces that share that vertex. If adjacency is provided, replicated vertices are ignored and "smoothed" over. If adjacency is not provided, replicated vertices will have normals averaged in from only the faces explicitly referencing them. This function simply calls D3DXComputeTangentFrameEx with the following input parameters: D3DXComputeTangentFrameEx( pMesh, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DX_DEFAULT, 0, D3DDECLUSAGE_NORMAL, 0, D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS, pAdjacency, -1.01f, -0.01f, -1.01f, NULL, NULL); 下面的代码通过复制的方法生成了一个具有顶点法向量信息的网格:
LPD3DXMESH mesh; LPD3DXMESH mesh_clone = NULL;
mesh->CloneMeshFVF(mesh->GetOptions(), mesh->GetFVF() | D3DFVF_NORMAL, _d3d_device, &mesh_clone);
D3DXComputeNormals(mesh_clone, NULL); Mesh数据的优化
.X文件的网格数据装入缓冲区后,每个网格子集的数据可以进行优化,以提高子集渲染速度。对于顶点缓冲区来说,可以把位于同一个子集的顶点进行连续排放,减少三角形面的索引,也可以对邻接的顶点进行压缩,节省内存消耗和提高顶点的命中率。对于顶点索引缓冲区来说,该缓冲区提供了网格的所有三角形面的构成信息,如果把位于同一个子集的三角形面集中连续排放,就可以使属性缓冲区的子集编号按序排列。
ID3DXMesh接口提供了OptimizeInplace 函数进行网格数据各种类型的优化,它的使用说明如下所示: Generates a mesh with reordered faces and vertices to optimize drawing performance. This method reorders the existing mesh. HRESULT OptimizeInplace(
DWORD
Flags,
CONST DWORD *
pAdjacencyIn,
DWORD *
pAdjacencyOut,
DWORD *
pFaceRemap,
LPD3DXBUFFER *
ppVertexRemap ); Parameters- Flags
- [in] Combination of one or more D3DXMESHOPT flags, specifying the type of optimization to perform.
- pAdjacencyIn
- [in] Pointer to an array of three DWORDs per face that specifies the three neighbors for each face in the source mesh. If the edge has no adjacent faces, the value is 0xffffffff.
- pAdjacencyOut
- [out] Pointer to an array of three DWORDs per face that specifies the three neighbors for each face in the optimized mesh. If the edge has no adjacent faces, the value is 0xffffffff. If the value supplied for this argument is NULL, adjacency data is not returned.
- pFaceRemap
- [out] An array of DWORDs, one per face, that identifies the original mesh face that corresponds to each face in the optimized mesh. If the value supplied for this argument is NULL, face remap data is not returned.
- ppVertexRemap
- [out] Address of a pointer to an ID3DXBuffer interface, which contains a DWORD for each vertex that specifies how the new vertices map to the old vertices. This remap is useful if you need to alter external data based on the new vertex mapping. If the value supplied for this argument is NULL, vertex remap data is not returned.
Return ValuesIf the method succeeds, the return value is D3D_OK. If the method fails, the return value can be one of the following: D3DERR_INVALIDCALL, D3DXERR_CANNOTATTRSORT, E_OUTOFMEMORY. RemarksBefore running ID3DXMesh::OptimizeInplace, an application must generate an adjacency buffer by calling ID3DXBaseMesh::GenerateAdjacency. The adjacency buffer contains adjacency data, such as a list of edges and the faces that are adjacent to each other. Note This method will fail if the mesh is sharing its vertex buffer with another mesh, unless the D3DXMESHOPT_IGNOREVERTS is set in Flags. 下面来看看参数Flags可以使用的网格优化类型D3DXMESHOPT的具体定义:
Specifies the type of mesh optimization to be performed. typedef enum D3DXMESHOPT { D3DXMESHOPT_COMPACT = 0x01000000, D3DXMESHOPT_ATTRSORT = 0x02000000, D3DXMESHOPT_VERTEXCACHE = 0x04000000, D3DXMESHOPT_STRIPREORDER = 0x08000000, D3DXMESHOPT_IGNOREVERTS = 0x10000000, D3DXMESHOPT_DONOTSPLIT = 0x20000000, D3DXMESHOPT_DEVICEINDEPENDENT = 0x40000000, } D3DXMESHOPT, *LPD3DXMESHOPT; Constants- D3DXMESHOPT_COMPACT
- Reorders faces to remove unused vertices and faces.
- D3DXMESHOPT_ATTRSORT
- Reorders faces to optimize for fewer attribute bundle state changes and enhanced ID3DXBaseMesh:rawSubset performance.
- D3DXMESHOPT_VERTEXCACHE
- Reorders faces to increase the cache hit rate of vertex caches.
- D3DXMESHOPT_STRIPREORDER
- Reorders faces to maximize length of adjacent triangles.
- D3DXMESHOPT_IGNOREVERTS
- Optimize the faces only; do not optimize the vertices.
- D3DXMESHOPT_DONOTSPLIT
- While attribute sorting, do not split vertices that are shared between attribute groups.
- D3DXMESHOPT_DEVICEINDEPENDENT
- Affects the vertex cache size. Using this flag specifies a default vertex cache size that works well on legacy hardware.
RemarksThe D3DXMESHOPT_STRIPREORDER and D3DXMESHOPT_VERTEXCACHE optimization flags are mutually exclusive. The D3DXMESHOPT_SHAREVB flag has been removed from this enumeration. Use D3DXMESH_VB_SHARE instead, in D3DXMESH. D3DXLoadMeshFromX函数装入.X文件时,会自动为网格填充一个三角形面的邻接数组缓冲区,也可以利用 ID3DXMesh接口提供的GenerateAdjacency函数来生成,下面是该函数的具体使用说明:
Generate a list of mesh edges, as well as a list of faces that share each edge. HRESULT GenerateAdjacency(
FLOAT
Epsilon,
DWORD *
pAdjacency ); Parameters- Epsilon
- [in] Specifies that vertices that differ in position by less than epsilon should be treated as coincident.
- pAdjacency
- [in] Pointer to an array of three DWORDs per face to be filled with the indices of adjacent faces. The number of bytes in this array must be at least 3 * ID3DXBaseMesh::GetNumFaces * sizeof(DWORD).
Return ValuesIf the method succeeds, the return value is D3D_OK. If the method fails, the return value can be one of the following: D3DERR_INVALIDCALL, E_OUTOFMEMORY. RemarksAfter an application generates adjacency information for a mesh, the mesh data can be optimized for better drawing performance. The order of the entries in the adjacency buffer is determined by the order of the vertex indices in the index buffer. The adjacent triangle 0 always corresponds to the edge between the indices of the corners 0 and 1. The adjacent triangle 1 always corresponds to the edge between the indices of the corners 1 and 2 while the adjacent triangle 2 corresponds to the edge between the indices of the corners 2 and 0. 下面的代码段给出了利用OptimizeInplace进行优化的示例:
// Generates a mesh with reordered faces and vertices to optimize drawing performance. // This method reorders the existing mesh. _mesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*) _adjacency_buffer->GetBufferPointer(), NULL, NULL, NULL); 值得一提的是,进行D3DXMESHOPT_ATTRSORT优化操作后,将生成一个Attribute Table,它是一个D3DXATTRIBUTERANGE类型的数组,反映了优化后的子集的三角形面的划分和顶点的划分。
D3DXATTRIBUTERANGE的具体定义如下所示:
Stores an attribute table entry. typedef struct D3DXATTRIBUTERANGE { DWORD AttribId; DWORD FaceStart; DWORD FaceCount; DWORD VertexStart; DWORD VertexCount; } D3DXATTRIBUTERANGE, *LPD3DXATTRIBUTERANGE; Members- AttribId
- Attribute table identifier.
- FaceStart
- Starting face.
- FaceCount
- Face count.
- VertexStart
- Starting vertex.
- VertexCount
- Vertex count.
RemarksAn attribute table is used to identify areas of the mesh that need to be drawn with different textures, render states, materials, and so on. In addition, the application can use the attribute table to hide portions of a mesh by not drawing a given attribute identifier (AttribId) when drawing the frame. The LPD3DXATTRIBUTERANGE type is defined as a pointer to the D3DXATTRIBUTERANGE structure. typedef D3DXATTRIBUTERANGE* LPD3DXATTRIBUTERANGE; 可以调用ID3DXMesh接口的GetAttribute方法来获得指向属性表的指针和属性表的大小,该函数具体说明如下:
Retrieves either an attribute table for a mesh, or the number of entries stored in an attribute table for a mesh. HRESULT GetAttributeTable(
D3DXATTRIBUTERANGE *
pAttribTable,
DWORD *
pAttribTableSize ); Parameters- pAttribTable
- [in, out] Pointer to an array of D3DXATTRIBUTERANGE structures, representing the entries in the mesh's attribute table. Specify NULL to retrieve the value for pAttribTableSize.
- pAttribTableSize
- [in, out] Pointer to either the number of entries stored in pAttribTable or a value to be filled in with the number of entries stored in the attribute table for the mesh.
Return ValuesIf the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL. RemarksAn attribute table is created by ID3DXMesh::Optimize and passing D3DXMESHOPT_ATTRSORT for the Flags parameter. An attribute table is used to identify areas of the mesh that need to be drawn with different textures, render states, materials, and so on. In addition, the application can use the attribute table to hide portions of a mesh by not drawing a given attribute identifier when drawing the frame. |