文章目录
本章研究如何从磁盘上加载一个复杂的3D模型并将该模型绘制出来
,或者利用渐进网格(progressive mesh)接口
来控制网格的细节层次(level of details)
1、ID3DXBuffer
ID3DXBuffer接口
是一种泛型(generic)数据结构
,该接口为D3DX库
所使用,并可将数据存储在一个连续的内存块中
上述接口中只有两个方法:
- 1、
LPVOID GetBufferPointer()
:返回指向缓存中数据起始位置的指针 - 2、
DWORD GetBufferSize()
:返回缓存的大小,单位为字节
为了保持该接口的通用性,该接口使用了void类型的指针。这就意味着必须由我们来实现被存储的数据类型
(书上有相关的例子说明)
也可以通过函数HRESULT D3DXCreateBuffer(DWORD NumBytes, LPD3DXBUFFER *ppBuffer);
来创建一个空的ID3DXBuffer对象
。由于ID3DXBuffer对象
是一个COM对象,所以在该接口使用完毕后必须将其释放,以防内存泄漏
2、XFile
用于游戏制作的比较流行的建模工具有3DS Max
(www.discreet.com)、LightWave
(www.newtek.com)以及Maya
(www.aliasingwave-front.com)
这些建模工具能够将网格数据(几何信息、材质、动画以及其他可能的有用数据)
导出到文件中。这样,我们可以编写一个文件读取程序来提取网格数据并在我们的3D应用程序
中使用
有一种特殊的网格文件格式称为XFile格式(扩展名为.X)
,许多3D建模工具可以将模型数据导出成这种格式。XFile之所以使用方便,最主要的原因是它是DirectX定义的格式,所以该格式得到了D3DX库的有力支持
。即D3DX库提供了对XFile格式的文件进行加载和保存的函数。所以在使用这种格式时,我们无需自己编写这类文件的加载和保存程序了
2.1、加载XFile文件
创建一个ID3DXMesh对象
,并将XFile文件中的几何数据加载到该对象中
HRESULT D3DXLoadMeshFromX(
LPCSTR pFilename,
DWORD Options,
LPDIRECT3DDEVICE9 pDevice,
LPD3DXBUFFER *ppAdjacency,
LPD3DXBUFFER *ppMaterials,
LPD3DXBUFFER *ppEffectInstance,
PDWORD pNumMaterials,
LPD3DXMESH *ppMesh
);
Mesh对象中只有几何数据
2.2、XFile材质
XFile文件中并未存储纹理数据,它只包含了纹理图像文件名
,该文件名是对包含了实际纹理数据的纹理图像的引用。所以,当用上述函数加载了一个XFile文件后,我们必须根据指定的纹理文件名加载纹理数据
值得一提的是,上述函数在加载完XFile中的数据后,返回的D3DXMATERIAL结构数组
中的第i项就与第i个子集相对应(D3DXMATERIAL结构体中包含了纹理文件名
)
2.3、生成顶点法线
XFile文件中有可能没有存放顶点的法向量。如果出现这种情况,为了使用光照,我们需要通过相关函数来计算每个顶点的法向量
有时在计算顶点法线之前,必须更改顶点格式
(是通过网格克隆
完成的)
3、渐进网格
渐进网格
允许我们运用一系列的边折叠变换(Edge Collapse Transformations)
对网格进行简化。每次ECT
都移除一个顶点以及一个或两个面片
由于每次ECT都是可逆的
(其逆运算称为顶点分裂
),我们可对简化过程进行逆转,从而将网格精确恢复到初始状态
。当然,我们无法获得比原始网格更丰富的细节。我们只能对网格进行简化及其逆运算
多级渐进纹理
:进行纹理映射时,我们会注意到如果对一个小而远的图元应用高分辨率的纹理实在是一种浪费,因为观察者根本不可能注意到这些细节
渐进网格的思路与纹理中的多级渐进纹理类似
在满足要求的条件下,我们总是用尽量少的面片来表达一个网格,以节省宝贵的绘制时间
3.1、生成渐进网格
HRESULT D3DXGeneratePMesh(
LPD3DXMESH pMesh,
const D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights,
const float *pVertexWeights,
DWORD MinValue,
DWORD Options,
LPD3DXMESH *ppMesh
);
建议实际使用一下
3.2、顶点属性权值
除非有充分的理由,一般情况下我们都建议您使用默认权值
3.3、ID3DXPMesh接口方法
都是一些关于界限设置
的一些方法
如何动态的实现LOD的变换
??????
4、外接体
有时我们需要计算一个网格的外接体(bounding volume)
两种常见的外接体:
- 1、
外接球(bounding sphere)
: - 2、
外接体(bounding box)
:
还存在外接圆柱体(cylinders)
、椭球体(ellipsoids)
、菱形体(lozenges)
以及胶囊状容器(capsule)
外接球或外接体常用于加速可见性检测(visibility)和碰撞检测(collision test)
。检测外接体的可见性要比检测网格中每个面片的可见性的代价低得多;碰撞检测同理,因为我们可借助外接体快速排除那些显然不可能被击中的物体
D3DX库
提供了一些函数用来计算一个网格的外接体或外接球。这些函数接收一个顶点数组
,然后依据这些顶点计算出外接球或外接体
4.1、一些新的特殊常量
const float INFINITY = FLT_MAX;
const float EPSILON = 0.001f;
浮点数相等性检测:
bool Equals(float lhs, float rhs)
{
return fabs(lhs - rhs) < EPSILON ? true : false;
}
4.2、外接体的类型
为了更方便的使用外接体,我们可以为每种外接体实现一个类