Mesh的顶点和索引能够被重组以便能更有效的渲染mesh。当我们这样做时,我们说我们优化了一个mesh。我们可以使用下面的方法来进行优化:
HRESULT
ID3DXMesh::OptimizeInplace(
DWORD Flags,
CONST DWORD*
pAdjacencyIn,
DWORD*
pAdjacencyOut,
DWORD* pFaceRemap,
LPD3DXBUFFER*
ppVertexRemap
);
|
Flags
— 表示执行什么类型的优化方法。它可以是下面的一个或几个的组合:
D3DXMESHOPT_COMPACT
— 从mesh中移除没有用的顶点和索引项。
D3DXMESHOPT_ATTRSORT
— 根据属性给三角形排序并调整属性表,这将使DrawSubset执行更有效。
D3DXMESHOPT_VERTEXCACHE
— 增加顶点缓存的命中率。
D3DXMESHOPT_STRIPREORDER
— 重组顶点索引使三角带尽可能的长。
D3DXMESHOPT_IGNOREVERTS
— 只优化索引信息,忽略顶点信息。
注意:D3DXMESHOPT_VERTEXCACHE和D3DXMESHOPT_STRIPREORDER不能同时使用。
pAdjacencyIn
— 指向没有优化的mesh的邻接数组。
pAdjacencyOut
— 指向一个DWORD数组,它被用来填充优化好了的mesh邻接信息。该数组必须有ID3DXMesh::GetNumFaces()
* 3个元素。如果不需要该信息,可以将其设置为0。
pFaceRemap
—指向一个DWORD数组,它被用来填充面重影射信息。该数组必须不小于ID3DXMesh::GetNumFaces()。当一个mesh被优化时,由索引缓存定义的面可能被移动;也就是说,在pFaceRemap中的第i项表示第i个原始面被移动到的面索引值。如果不需要该信息,可以将其设置为0。
ppVertexRemap
— 指向ID3DXBuffer指针的地址,它被用来填充顶点重影射信息。这个缓存应该包含ID3DXMesh::GetNumVertices()个顶点。当一个mesh被优化后,顶点可能被移动。顶点重影射信息用来说明原来的顶点被移动到新位置;也就是说,在ppVertexRemap中的第i项表示原来的第i个顶点的新位置。如果不需要该信息,可以将其设置为0。
例子:
// Get the
adjacency info of the non-optimized mesh.
DWORD
adjacencyInfo[Mesh->GetNumFaces() * 3];
Mesh->GenerateAdjacency(0.0f, adjacencyInfo);
// Array to
hold optimized adjacency info.
DWORD
optimizedAdjacencyInfo[Mesh->GetNumFaces() * 3];
Mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT |
D3DXMESHOPT_VERTEXCACHE,
adjacencyInfo,
optimizedAdjacencyInfo, 0, 0);
|
一个更简单的方法是Optimize方法,它输出一个优化的mesh,而不是在原来mesh的基础上进行优化:
Generates a new mesh with reordered faces and vertices
to optimize drawing performance.
HRESULT Optimize(
DWORD Flags,
CONST DWORD * pAdjacencyIn,
DWORD * pAdjacencyOut,
DWORD * pFaceRemap,
LPD3DXBUFFER * ppVertexRemap,
LPD3DXMESH * ppOptMesh
);
Parameters
- Flags
- [in] Specifies the type of optimization to
perform. This parameter can be set to a combination of one or more flags
from D3DXMESHOPT and D3DXMESH (except D3DXMESH_32BIT, D3DXMESH_IB_WRITEONLY,
and D3DXMESH_WRITEONLY).
- 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. See Remarks.
- pAdjacencyOut
- [in, 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.
- pFaceRemap
- [in, 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.
- ppOptMesh
- [out] Address of a pointer to an ID3DXMesh
interface, representing the optimized mesh.
Return Values
If 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.
Remarks
This method generates a new mesh. Before running
Optimize, 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.
This method is very similar to the
ID3DXBaseMesh::CloneMesh method, except that it can perform optimization while
generating the new clone of the mesh. The output mesh inherits all of the
creation parameters of the input mesh.
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::DrawSubset 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.
Remarks
The 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.
当一个mesh被使用D3DXMESHOPT_ATTRSORT参数来优化后,mesh的几何信息将按照属性进行排序,这样各个子集的顶点/索引将组成连续的块(如图10.3)。
除了进行几何信息的排序外,D3DXMESHOPT_ATTRSORT优化项还将创建一个属性表。该表是D3DXATTRIBUTERANGE结构的一个数组。在属性表中的每一项对应mesh的一个子集并指示顶点/索引缓存中的一个连续连续内存块,这个子集的几何信息就包含在这个块中。D3DXATTRIBUTERANGE结构的定义如下:
typedef
struct _D3DXATTRIBUTERANGE {
DWORD AttribId;
DWORD FaceStart;
DWORD FaceCount;
DWORD VertexStart;
DWORD VertexCount;
} D3DXATTRIBUTERANGE;
|
AttribId
— 子集的ID。
FaceStart
— 该子集的面的起始值,FaceStart*3就是起始三角形在索引缓存中的序号。
FaceCount
— 在子集中的面(三角形)数。
VertexStart
— 该子集的起始顶点在顶点缓存中的序号。
VertexCount
— 在子集中的顶点数。
建立了属性表以后,渲染一个子集就很容易了。仅仅查一下属性表就能找出自己的几何信息。注意如果没有属性表,每渲染一个子集就需要对属性缓存进行一次线性搜索来找出子集包含的几何信息。
可以使用下面的方法来访问mesh的属性表:
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 Values
If the method succeeds, the return value is D3D_OK. If
the method fails, the return value can be D3DERR_INVALIDCALL.
Remarks
An 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.
这个方法能够做两件事情:它可以返回属性表的属性数,也可以用属性数据来填充一个D3DXATTRIBUTERANGE结构数组。
要得到属性表的元素个数,可以就将第一个参数设置为0:
DWORD numSubsets = 0;
Mesh->GetAttributeTable(0,
&numSubsets);
|
一旦我们知道了属性表的元素个数,我们就能够通过写属性表来填充一个D3DXATTRIBUTERANGE结构数组:
D3DXATTRIBUTERANGE table =
new D3DXATTRIBUTERANGE [numSubsets];
Mesh->GetAttributeTable(
table, &numSubsets );
|
我们能够使用ID3DXMesh::SetAttributeTable方法来直接设置属性表。
Sets the attribute table for a mesh and the number of
entries stored in the table.
HRESULT SetAttributeTable(
CONST D3DXATTRIBUTERANGE * pAttribTable,
DWORD cAttribTableSize
);
Parameters
- pAttribTable
- [in] Pointer to an array of D3DXATTRIBUTERANGE
structures, representing the entries in the mesh attribute table.
- cAttribTableSize
- [in] Number of attributes in the mesh attribute
table.
Return Values
If 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.
Remarks
If an application keeps track of the information in an
attribute table, and rearranges the table as a result of changes to attributes
or faces, this method allows the application to update the attribute tables
instead of calling ID3DXMesh::Optimize again.
下面的代码就是设置一个有12个子集的属性表:
D3DXATTRIBUTERANGE
attributeTable[12];
// ...fill
attributeTable array with data
Mesh->SetAttributeTable(
attributeTable, 12);
|
对于mesh的某些操作,如优化,有必要了解的是三角形之间的邻接信息。Mesh的邻接数组存储了这些信息。
邻接数组是一个DWORD数组,其中的每一项对应了mesh中的一个三角形。例如,第i项对应的三角形由以下三个索引值定义:
A
=
i
x3
B
=
i
x3 + 1
C
=
i
x3 + 2
注意,使用ULONG_MAX
= 4294967295表示该边没有邻接三角形。我们也可以用-1来表示,因为-1转换成DWORD就是ULONG_MAX。回想一下,DWORD就是一个unsigned32-bit整数。
因为每个三角形都有三条边,所以它最多有三个邻接三角形(如图10.4)。
因此,邻接数组必须有三项(ID3DXBaseMesh::GetNumFaces()*3)——
在mesh中每个三角形都可能有三个邻接三角形。
很多D3Dxmesh创造函数都能输出邻接信息,但我们也可以使用下面的方法:
HRESULT
ID3DXMesh::GenerateAdjacency(
FLOAT fEpsilon,
DWORD* pAdjacency
);
|
fEpsilon
— 指示当两个点距离有多近时,可以认为是一个点。当两点间的距离小于epsilon时,可认为它们是同一个点。
pAdjacency
— 一个指向填充了邻接信息的DWORD数组指针。
例子:
DWORD
adjacencyInfo[Mesh->GetNumFaces() * 3];
Mesh->GenerateAdjacency(0.001f, adjacencyInfo);
|