欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D3D9学习笔记之基础几何体的深入应用(一)

程序员文章站 2022-07-02 11:37:51
...

网格(一)

在开始之前,先附上基础网格对象的基础应用:
D3DX几何体的基础应用

在上面的链接中对 ID3DXMesh 接口有了一些了解,现在开始进一步研究该接口,内容很大程度上是与 ID3DXMesh 接口相关的数据和方法的概览。

注意,ID3DXMesh 接口继承了其父接口 ID3DXBaseMesh 的大部分功能,这一点很重要,因为其它类型的网格接口,如 ID3DXPMesh(渐进网格)也继承自接口 ID3DXBaseMesh ,所以接下来凡是涉及到其它网格类型的主题也都是相关的。

学习目标:

  • 了解 ID3DXMesh 接口对象的内部数据组织形式
  • 了解如何创建 ID3DXMesh 接口的对象
  • 了解如何优化 ID3DXMesh 接口的对象
  • 了解如何绘制 ID3DXMesh 接口的对象

几何信息:
ID3DXBaseMesh 接口包含了有一个顶点缓存(用于存储网格顶点)和一个索引缓存(决定顶点以哪种顺序构成三角形单元),我们可用下列方法得到指向这些接口的指针

HRESULT ID3DXMesh::GetVertexBuffer(LPDIRECT3DVERTEXBUFFER9* ppVB);
HRESULT ID3DXMesh::GetIndexBuffer(LPDIRECT3DINDEXBUFFER9* ppIB);

//下面示范如何使用这些方法
IDirect3DVertexBuffer9* vb =0;
Mesh->GetVertexBuffer(&vb);

IDirect3DIndexBuffer9* id =0;
Mesh->GetIndexBuffer(&ib);

注意:ID3DXMesh 接口仅支持将索引化的三角形单元列表作为其基本类型

锁定读写操作:
如果想锁定这些缓存,然后进行读写操作,可使用如下函数对,注意,这些方法锁定的是整个顶点缓存或索引缓存

HRESULT ID3DXMesh::LockVertexBuffer(DWORD Flags, BYTE** ppData);
HRESULT ID3DXMesh::LockIndexBuffer(DWORD Flags, BYTE** ppData);
  • Flags: 该参数描述如何进行锁定,锁定标记到这里看
  • ppData: 该参数返回指向被锁定的内存的指针的地址

当对锁定内存完成操作后,必须调用相应的解锁方法:

HRESULT ID3DXMesh::UnlockVertexBuffer();
HRESULT ID3DXMesh::UnlockIndexBuffer();

下面是 ID3DXMesh 接口用于获取几何信息的另外一些方法:

  • DWORD GetFVF(); 返回一个描述了顶点格式的 DWORD 类型值
  • DWORD GetNumVertices(); 返回顶点缓存中的顶点个数
  • DWORD GetNumBytesPerVertex(); 返回每个顶点所占的字节数
  • DWORD GetNumFaces(); 返回网格中(三角形)面片的个数

子集和属性缓存

一个网格由一个或多个子集组成,一个子集是网格中一组可用相同属性进行绘制的三角形单元,这里的属性是指材质,纹理和绘制状态。比如:
房子有:地板,墙,天花板,窗户
subset0: 地板。用地板的属性绘制该子集内的三角形
subset1: 墙。用墙的属性绘制该子集内的三角形
subset2: 天花板。用天花板的属性绘制该子集内的三角形
subset3: 窗户。用窗户的属性绘制该子集内的三角形

为了区分不同的子集,我们为每个子集指定一个唯一的非负的整数值,该值可为 DWORD 类型所能容纳的任何非负整数。

网格中每个三角形单元都被赋予了一个属性 ID, 该 ID 指定了该三角形单元所属的子集。
这些三角形单元的属性 ID 被存储在网格的属性缓存中,该属性缓存实际上是一个 DWORD类型的数组,由于每个面片(即三角形)在属性缓存中都有对应项,所以属性缓存中元素的个数与网格中面片的个数完全相等。而且属性缓存中的那些项与在索引缓存中定义的三角形单元是一一对应的;即属性缓存中的第 i 项对应于索引缓存中的第 i 个三角形。三角形单元 i 是由索引缓存中如下3个索引定义的:
A = i * 3
B = i * 3+1
C = i * 3+2

要想访问属性缓存,必须首先将其锁定,参见下面的代码段:

DWORD* buffer =0;
Mesh->LockAttributeBuffer(lockingFlags, &buffer);

//读或写属性缓冲区

Mesh->UnlockAttributeBuffer();

绘制

ID3DXMesh 接口提供了方法 DrawSubset(DWORD AttribId) 用于绘制由参数 AttribId 指定的子集中的三角形单元,例如,要想绘制子集0中的所有三角形单元,可这样做:

Mesh->DrawSubset(0);

若要绘制整个网格,必须绘制该网格的所有子集,比较方便的方法是将各子集的属性 ID 依次指定为 0,1,2,…, n-1,其中 n 为子集的总数,每个子集都有一个对应的材质和纹理数组,这样用索引 i 就可以找到与子集 i 相关的材质和纹理。这种指定方式也使我们能够用一个简单的循环完成整个网格的绘制。

for( int i=0; i<numSubsets; i++ )
{
	Device->SetMaterial( mtrls[i] );		//材质
	Device->SetTexture( 0, textures[i] );	//纹理
	Mesh->DrawSubset(i);					//绘制
}

网格优化

为了更高效的绘制一个网格,我们可对该网格中的定义和索引进行重组,这个重组的过程称为网格优化,我们可借助下面的方法来完成优化:

HRESULT ID3DXMesh::OptimizeInplace(
	DWORD Flags,
	CONST DWORD* pAdjacencyIn,
	DWORD* pAdjacencyOut,
	DWORD* pFaceRemap,
	LPD3DXBUFFER* ppVertexRemap
);
  • Flags: 优化选项标记,通知该方法所要实施的优化方案,该参数可选取下列选项中的一项或多项
  • D3DXMESHOPT_COMPACT 从网格中移除那些无用顶点和索引
  • D3DXMESHOPT_ATTSORT 依据属性对各三角形单元进行排序,并生成一个属性表,这样可使 DrawSubset 获得更高的绘制效率
  • D3DXMESHOPT_VERTEXCACHE 提高顶点高速缓存的命中率
  • D3DXMESHOPT_STRIPORDER 对索引进行重组,以使三角形单元条带尽可能的长
  • D3DXMESHOPT_IGNOREVERTS 仅对索引进行优化,忽略顶点
    注意:标记 D3DXMESHOPT_VERTEXCACHE 和 D3DXMESHOPT_STRIPREORDER 不应许被同时使用
  • pAdjacencyIn: 指向未经优化的网格的邻接数组的指针
  • pAdjacencyOut: 指向一个 DWORD 类型数组的指针,该数组被填充了经过优化后的网格的邻接信息,该数组的维数必须为 ID3DXMesh::GetNumFace()*3,如果您不需要该信息,可将该参数赋为0
  • pFaceRemap: 指向一个 DWORD 类型数组的指针,该数组填充了网格面片的重绘信息,该数组的维数应为 ID3DXMesh::GetNumFaces(),当对一个网格面实施优化后,其面片在索引缓存中可能发生了移动,该面片重绘信息表明了原始面片所被移动到的新位置,即 pFaceRemap 中的第 i 项保存了表示第 i 个原始面片被移动到哪里的面片索引。如果您不需要该信息,可将该参数赋为0
  • ppVertexRemap: 指向 ID3DXMesh 对象指针的地址,该对象中保存了顶点的重绘信息,该缓存所包含的顶点数应为 ID3DXMesh::GetNumFaces(),当网格面经过优化后,其顶点在索引缓存中的位置可能发生了变动,顶点重绘信息表明了原始顶点移动到的新位置,即 pFaceRemap 中的第 i 项保存了表示第 i 个原始顶点被移动到哪里的顶点索引,如果您不需要该值,将该参数赋为0
    调用示例:
//获取非优化网格的邻接信息
DWORD adjacencyInfo[Mesh->GetNumFaces()*3];
Mesh->GenerateAdjacency(0.0f, adjacencyInfo);

//保存优化邻接信息的数组
DWORD optimizedAdjacencyInfo[Mesh->GetNumFaces()*3];

Mesh->OptimizeInplace(
	D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_COMPACT|D3DXMESHOPT_VERTEXCACHE,
	adjacencyInfo,
	optimizedAdjacencyInfo,
	0,
	0
);

与上诉方法功能类似的另一个方法是 Optimize, 该方法将输出调用了该方法的网格对象优化后的版本,但是调用该方法的那个网格对线本身不会发生改变

HRESULT ID3DXMesh::Optimize(
	DWORD Flags,
	CONST DWORD* pAdjacencyIn,
	DWORD* pAdjacencyOut,
	DWORD* pFaceRemap,
	LPD3DXBUFFER* ppVertexRemap,
	LPD3DXMESH* ppOptMesh		//要输出的优化网格
);

属性表:

如果一个网格对象在优化处理时使用了 **D3DXMESHOPT_ATTRSORT ** 标记,则构成该网格的三角形面片就会依据其属性进行排序,这样属于特定子集的三角形面片就会被保存在顶点缓存或索引缓存中的一个连续储存空间内