您的位置:首页 > 编程语言

【阅读笔记之十二】《DIRECTX.9.0.3D游戏开发编程基础》:网格(二)浅话X文件和渐进网格

2012-12-10 23:48 411 查看
网格(二)

这里我们学习的关于网格部分是以上一章内容为基础的,这里给出链接: /article/11437162.html

在D3DX库中,Microsoft提供很多与网格相关的接口、结构和函数。这里我们主要学习X文件的相关操作和渐进网格。

1. XFile
到目前为止,我们已经能够使用D3DXCreate*函数创建一些简单的几何体,例如球体、圆柱体等。但是,我们需要明白的是,Microsoft不可能把所有我们想要绘制的3D物体都做好供给我们使用。Microsoft只是提供了几个常用的简单的几何体的信息,然后通过简单的函数接口(D3DXCreate*函数)供给我们用户来绘制这些非常常用的几何体。但是,假如我们想要绘制一条小狗(自己家养的旺财~),就必须依赖于自己对于狗的几何信息(顶点数据)以及毛色(材质)有足够充分的了解。这样,我们就能够在一个唤作X文件里面写出我们要绘制的狗的所有信息。设想一下,这是一件非常繁杂的工作。万幸的是,我们有建模软件诸如3DS
Max、Maya等,这样,我们就可以通过可视化的方法描述绘制的对象,最后在导出XFile。
X文件是微软捣鼓出来的,它是在DirectX中定义的一种特殊的网格格式(这种网格格式理所当然地包含了几何信息,属性信息等)。正是因为XFile是微软的儿子,所以其在Windows下面的支持是木有任何问题的。废话不多说了,我们直接来学习怎么样使用XFile。

1)加载XFile
需要说明的是,XFile只是描述了我们将要绘制的几何体的信息(包括几何信息,属性等信息),这个我们可以从X文件的命名上看得出来。例如我们定义一个关于旺财的XFile为 dogWangCai.x 。利用3D建模软件创建好XFile之后,我们利用一个函数将这个XFile和它的上线(ID3DXMesh对象)接头。这个函数就是D3DXLoadMeshFromX,其原型如下:
HRESULT D3DXLoadMeshFromX(
LPCSTR pFilename,		//所要加载的XFile文件名
DWORD Options,			//创建网格时所使用的创建标记
LPDIRECT3DDEVICE9 pDevice,	//相关设备指针
LPD3DXBUFFER *ppAdjacency,	//返回一个ID3DXBuffer对象,其中包含了网格对象的邻接信息
LPD3DXBUFFER *ppMaterials,	//返回一个ID3DXBuffer对象,其中包含了网格对象的材质数据
//材质数据由D3DXMATERIAL类型的结构数组描述
LPD3DXBUFFER *ppEffectInstances,//返回一个ID3DXBuffer对象,通常为0
PDWORD pNumMaterials,		//网格中的材质数目
LPD3DXMESH *ppMesh		//【out】返回所创建的并以填充了XFile几何数据的ID3DXMesh对象
);

这里我们需要解释一下ID3DXBuffer接口。在这之前,我们已经接触过很多缓存结构,如顶点缓存,索引缓存,属性缓存等等。而ID3DXBuffer接口就是作为一种缓存接口。该接口是一种泛型数据结构,存储在一个连续的内存块中。该接口只有两个方法:
LPVOID GetBufferPointer(); 返回指向缓存中数据起始位置的指针
DWORD GetBufferSize(); 返回缓存的大小,单位为字节
该接口之所用void类型的指针,是为了保持其通用性,但是使用时需要强制类型转换成我们使用的缓存结构类型。例如我们需要一个表示网格邻接信息的缓存时,因为表示邻接信息的是一个DWORD类型的数组,因此我们强制类型转换,可以这样写:

DWORD *pAdjacencyInfo = (DWORD *)adjacencyInfo->GetBufferPointer();
惯例,最后需要说明的是,ID3DXBuffer是一个COM对象,接口使用完毕之后必须将其释放,以防内存泄露。

2)XFile材质
现实中的一个几何体有几何信息,也有材质等信息。这也就是说XFile中也必然包含这些信息。上面的D3DXLoadMeshFromX函数的参数中,有描述几何信息的邻接信息的参数,当然还有材质信息的ppMaterials的参数。然而,材质信息是被存储在一个被称作D3DXMATERIAL类型的结构数组中。值得一提的是,D3DXMATERIAL结构数组的第i项与第i个子集(子集就是一系列用相同绘制属性绘制三角形图元的组合,在上一章中有讲述)相对应,绘制时候循环遍历即可。该结构定义如下:
typedef struct D3DXMATERIAL{
D3DMATERIAL9 MatD3D;
LPSTR pTextureFilename;
} D3DXMATERIAL;

其中,字符串指针pTextureFilename指定了与网格相关的纹理文件名。需要说明的是,XFile文件中并未存储纹理数据,它只包含了纹理图像文件名,该文件名是对包含了实际纹理数据的纹理图像的引用。当用函数D3DXLoadMeshFromX加载XFile文件之后需要根据指定的纹理文件名加载纹理数据。

2. 渐进网格
首先,我们需要明白为什么需要渐进网格这个东西。在游戏中,我们绘制的场景中是尽可能地模拟现实世界的一切。自然地,所有物体对于观察者都会有远景之分。当你距离某物体很远时,你看到的就会比较模糊,而这种模糊和粗糙在Direct3D中就是通过减少物体的面元个数来实现的。事实上,这也是必须的。对于一个大型游戏而言,如果所有的物体都按照最原始的网格面片个数来绘制的,那么这样做的话是和游戏对速度的要求是矛盾的。渐进网格就是在这样的情况下应运而生的。
废话就不多了,我们来了解一下渐进网格的具体用法。渐进网格类似于多级渐进纹理。在代码中我们用ID3DXPMesh接口来使用渐进纹理。
1)生成渐进网格
和前面一样,我们需要先弄出个具体的ID3DXPMesh对象并用对应的信息填充。在Direct3D中,我们用如下函数创建ID3DXPMesh对象。
HRESULT D3DXGeneratePMesh(
LPD3DXMESH pMesh,	// 渐进网格信息根据这个网格信息产生
CONST DWORD *pAdjacency,	//pMesh的邻接信息
CONST D3DXATTRIBUTEWEIGHTS *pVertexAttributeWeights,	//解释如下
CONST FLOAT *pVertexWeights,	//顶点权值
DWORD MinValue,		//网格中的顶点数或面片数可被简化的下限
DWORD Options,
LPD3DXPMESH *ppPMesh	//输出的渐进网格
);

2)顶点属性权值
在前面学习顶点我们知道,我们定义的顶点结构体都有自己的属性,这些属性包括了顶点的位置、颜色等等。渐进网格就是要根据实际情况来移除一些不必要的顶点。这样说来,到底应该移除顶点呢?计算机并不是我们想象中那么智能,相反,他是很笨,聪明的是人。我们需要为顶点每一个可能的分量指定一个权值,以指定它被移除的概率大小。权值越大,被移除的概率越大。在代码中,我们用一个唤作D3DXATTRIBUTEWEIRHTS的结构体来描述顶点属性权值。该结构定义如下:
typedef struct D3DXATTRIBUTEWEIGHTS{
FLOAT Position;
FLOAT Boundary;
FLOAT Normal;
FLOAT Diffuse;
FLOAT Specular;
FLOAT Texcoord[8];
FLOAT Tangent;
FLOAT Binormal;
} D3DXATTRIBUTEWEIGHTS,*LPD3DXATTRIBUTEWEIGHTS;

在Direct3D中,D3DXATTRIBUTEWEIGHTS都有默认值,如下。一般情况,除非特别需要,一般使用默认值。
D3DXATTRIBUTEWEIGHTS AttributeWeights;
AttributeWeights.Position = 1.0;
AttributeWeights.Boundary = 1.0;
AttributeWeights.Normal = 1.0;
AttributeWeights.Diffuse = 0.0;
AttributeWeights.Specular = 0.0;
AttributeWeights.Tex[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,};

关于渐进网格的学习就到这里了。兴许这个时候对渐进网格的感觉还是很模糊,这个是正常的。我们下面的学习还会再接触渐进网格。

理论的学习是枯燥的,大家加油,共勉!

本章完~

——Josh 2012年12月10日
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐