天行健 君子当自强而不息

D3D中的网格模型(2)

10.4 优化

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.


10.5 属性表

当一个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);


10.6 邻接信息

对于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);


posted on 2008-03-27 11:32 lovedday 阅读(1470) 评论(1)  编辑 收藏 引用

评论

# re: D3D中的网格模型(2) 2008-10-09 23:21 leshy

关于pFaceRemap,pVertexMap说反了  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论