【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3434|回复: 9

.X文件的应用

[复制链接]
发表于 2008-4-19 23:06:24 | 显示全部楼层 |阅读模式

三维物体表面的各个剖分三角形构成了一个所谓的网格(Mesh),使用3D建模软件绘制三维图象,可取得网格的顶点坐标,顶点纹理坐标以及三角形面的材质等数据,并可将这些数据保存到相应的三维图象文件中。此时调用DirectX提供的网格接口函数,读取三维图象文件的顶点数据,就可对三维物体表面进行渲染处理。

.X文件的基本格式

使用 DirectX SDK安装目录下的MView.exe可以打开.X文件,比如我的电脑上的可执行文件路径是E:\Microsoft DirectX 9.0 SDK (April 2005)\Utilities\Bin\x86\MView.exe。 (注: 最新版的DirectX SDK已经不包含该文件了,所以你可能需要下载安装旧版的DirectX SDK来得到这个文件。)

下面是使用MeshView打开一个.X文件的截图:



我们来看看下面这个.X文件的具体信息描述,该文件描述与上面那个截图无关。

xof 0302txt 0064

template Header {
<3D82AB43-62DA-11cf-AB39-0020AF71E433>
WORD major;
WORD minor;
DWORD flags;
}

template Vector {
<3D82AB5E-62DA-11cf-AB39-0020AF71E433>
FLOAT x;
FLOAT y;
FLOAT z;
}

template Coords2d {
<F6F23F44-7686-11cf-8F52-0040333594A3>
FLOAT u;
FLOAT v;
}

template Matrix4x4 {
<F6F23F45-7686-11cf-8F52-0040333594A3>
array FLOAT matrix[16];
}

template ColorRGBA {
<35FF44E0-6C7C-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
FLOAT alpha;
}

template ColorRGB {
<D3E16E81-7835-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
}

template IndexedColor {
<1630B820-7842-11cf-8F52-0040333594A3>
DWORD index;
ColorRGBA indexColor;
}

template Boolean {
<4885AE61-78E8-11cf-8F52-0040333594A3>
WORD truefalse;
}

template Boolean2d {
<4885AE63-78E8-11cf-8F52-0040333594A3>
Boolean u;
Boolean v;
}

template MaterialWrap {
<4885AE60-78E8-11cf-8F52-0040333594A3>
Boolean u;
Boolean v;
}

template TextureFilename {
<A42790E1-7810-11cf-8F52-0040333594A3>
STRING filename;
}

template Material {
<3D82AB4D-62DA-11cf-AB39-0020AF71E433>
ColorRGBA faceColor;
FLOAT power;
ColorRGB specularColor;
ColorRGB emissiveColor;
[...]
}

template MeshFace {
<3D82AB5F-62DA-11cf-AB39-0020AF71E433>
DWORD nFaceVertexIndices;
array DWORD faceVertexIndices[nFaceVertexIndices];
}

template MeshFaceWraps {
<4885AE62-78E8-11cf-8F52-0040333594A3>
DWORD nFaceWrapValues;
Boolean2d faceWrapValues;
}

template MeshTextureCoords {
<F6F23F40-7686-11cf-8F52-0040333594A3>
DWORD nTextureCoords;
array Coords2d textureCoords[nTextureCoords];
}

template MeshMaterialList {
<F6F23F42-7686-11cf-8F52-0040333594A3>
DWORD nMaterials;
DWORD nFaceIndexes;
array DWORD faceIndexes[nFaceIndexes];
[Material
<3D82AB4D-62DA-11cf-AB39-0020AF71E433>]
}

template MeshNormals {
<F6F23F43-7686-11cf-8F52-0040333594A3>
DWORD nNormals;
array Vector normals[nNormals];
DWORD nFaceNormals;
array MeshFace faceNormals[nFaceNormals];
}

template MeshVertexColors {
<1630B821-7842-11cf-8F52-0040333594A3>
DWORD nVertexColors;
array IndexedColor vertexColors[nVertexColors];
}

template Mesh {
<3D82AB44-62DA-11cf-AB39-0020AF71E433>
DWORD nVertices;
array Vector vertices[nVertices];
DWORD nFaces;
array MeshFace faces[nFaces];
[...]
}

template FrameTransformMatrix {
<F6F23F41-7686-11cf-8F52-0040333594A3>
Matrix4x4 frameMatrix;
}

template Frame {
<3D82AB46-62DA-11cf-AB39-0020AF71E433>
[...]
}

Frame Scene_Root { // 场景主框架
FrameTransformMatrix { // 主框架的变换矩阵
0.000000, 0.000000, 0.000000, 0.000000,
0.000000, 1.000000, 0.000000, 0.000000,
0.000000, 0.000000, 1.000000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000;;
}

Frame Quad { // 主框架下的Quad框架
Mesh { // 网格数据
4; // 顶点数
-0.500000; -0.500000; 0.000000;, // 顶点1坐标
0.500000; -0.500000; 0.000000;, // 顶点2坐标
-0.500000; 0.500000; 0.000000;, // 顶点3坐标
0.500000; 0.500000; 0.000000;; // 顶点4坐标

2; // 三角形面数
3; 0,1,2;, // 第一个三角形面的顶点索引数和三个顶点索引值
3; 0,2,1;; // 第二个三角形面的顶点索引数和三个顶点索引值

MeshNormals {
4; // 顶点法向量的个数
0.000000; 0.000000; 1.000000;, // 顶点1的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点2的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点3的法向量坐标
0.000000; 0.000000; 1.000000;; // 顶点4的法向量坐标

2; // 三角形面的法向量个数
3; 0, 1, 2;, // 法向量的索引数和3个法向量的索引值(计算面的法向量)
3; 3, 2, 1;; // 法向量的索引数和3个法向量的索引值(计算面的法向量)
}

MeshTextureCoords { // 纹理坐标模版
4; // 纹理坐标个数
0.000000; 1.000000;, // 纹理坐标1
1.000000; 1.000000;, // 纹理坐标2
0.000000; 0.000000;, // 纹理坐标3
1.000000; 0.000000;; // 纹理坐标4
}

MeshMaterialList { // 材质列表模版
1; // 材质个数
2; // 三角形面的材质索引数(实际是三角形面的个数)
0, // 第一个三角形使用0号材质索引
0, // 第二个三角形使用0号材质索引

Material{ // 材质模版
1.000000; 1.000000; 1.000000; 1.000000;; // 三角形面的颜色
0.000000; // 镜面光的高光强度
1.000000; 1.000000; 1.000000;; // 镜面光颜色
0.000000; 0.000000; 0.000000;; // 自发射光颜色

TextureFilename { // 纹理贴图文件
"bb.jpg";
};
}
}
}
}
}

第一行的“xof 0302txt 0064”表明这个文件是一个.X 文件(由"xof"子串解析),文件的版本为3.2(由“0302”子串解析),数据以文本格式进行存放(由"txt"子串解析),所使用的浮点数是64 位的浮点数据(由"0064"子串进行解析)。如果第一行的内容为“xof 0303bin 0032”,则表示该.X文件是一个二进制文件,此时将不能直接查看文件数据的含义。

接下来是 Scene_Root对象的定义,该对象为一个Frame模版数据,用Frame Scene_Root引出,在随后的配对大括号"{"和"}"内,定义Scene_Root对象的具体数据。这里,作为数据类型的Frame模版同样提供了数据正确性的检测方法和它的对象数据的说明方法。

Frame模版用来定义游戏场景的各个框架部分,通过在框架中定义子框架,就可形成具有层次关系的一系列框架。Frame模版在DirectX中定义如下:
template Frame {
<3D82AB46-62DA-11cf-AB39-0020AF71E433>
[...]
}

关键字"template"表明下面是一个模版的定义,Frame为该模版的名字,每个模版都有一个唯一的全局标志符,随后的 [...]说明Frame模版是一个开放模版(Open Template),开放模版的对象可以定义其他模版类型的数据。

在Scene_Root对象中,定义了一个省略了对象名的FrameTransformMatrix模版对象如下:

FrameTransformMatrix { // 主框架的变换矩阵
0.000000, 0.000000, 0.000000, 0.000000,
0.000000, 1.000000, 0.000000, 0.000000,
0.000000, 0.000000, 1.000000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000;;
}

FrameTransformMatrix模版用来指定框架的变换矩阵,它的定义如下所示:

template FrameTransformMatrix {
<F6F23F41-7686-11cf-8F52-0040333594A3>
Matrix4x4 frameMatrix;
}

template Matrix4x4 {
<F6F23F45-7686-11cf-8F52-0040333594A3>
array FLOAT matrix[16];
}

在Scene_Root框架对象内定义了另一个Quad框架对象如下:

Mesh { // 网格数据
4; // 顶点数
-0.500000; -0.500000; 0.000000;, // 顶点1坐标
0.500000; -0.500000; 0.000000;, // 顶点2坐标
-0.500000; 0.500000; 0.000000;, // 顶点3坐标
0.500000; 0.500000; 0.000000;; // 顶点4坐标

2; // 三角形面数
3; 0,1,2;, // 第一个三角形面的顶点索引数和三个顶点索引值
3; 0,2,1;; // 第二个三角形面的顶点索引数和三个顶点索引值

MeshNormals {
4; // 顶点法向量的个数
0.000000; 0.000000; 1.000000;, // 顶点1的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点2的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点3的法向量坐标
0.000000; 0.000000; 1.000000;; // 顶点4的法向量坐标

2; // 三角形面的法向量个数
3; 0, 1, 2;, // 法向量的索引数和3个法向量的索引值(计算面的法向量)
3; 3, 2, 1;; // 法向量的索引数和3个法向量的索引值(计算面的法向量)
}

MeshTextureCoords { // 纹理坐标模版
4; // 纹理坐标个数
0.000000; 1.000000;, // 纹理坐标1
1.000000; 1.000000;, // 纹理坐标2
0.000000; 0.000000;, // 纹理坐标3
1.000000; 0.000000;; // 纹理坐标4
}

MeshMaterialList { // 材质列表模版
1; // 材质个数
2; // 三角形面的材质索引数(实际是三角形面的个数)
0, // 第一个三角形使用0号材质索引
0, // 第二个三角形使用0号材质索引

Material{ // 材质模版
1.000000; 1.000000; 1.000000; 1.000000;; // 三角形面的颜色
0.000000; // 镜面光的高光强度
1.000000; 1.000000; 1.000000;; // 镜面光颜色
0.000000; 0.000000; 0.000000;; // 自发射光颜色

TextureFilename { // 纹理贴图文件
"bb.jpg";
};
}
}
}

 楼主| 发表于 2008-4-19 23:06:45 | 显示全部楼层

该对象提供了正方形网格(Mesh)的数据说明,如下所示:

template Mesh { // 网格模版定义
<3D82AB44-62DA-11cf-AB39-0020AF71E433>
DWORD nVertices; // 顶点数
array Vector vertices [nVertices]; // 顶点数组
DWORD nFaces; // 三角形面数
array MeshFace faces[nFaces]; // 三角形面数组
[...] // 开放模版定义
}

template MeshFace {
<3D82AB5F-62DA-11cf-AB39-0020AF71E433>
DWORD nFaceVertexIndices; // 三角形面的顶点索引数,一般为3。
array DWORD faceVertexIndices[nFaceVertexIndices]; // 三角形面内各个顶点的索引值
}

而在Mesh数据里又定义了一个模板数据MeshNormals如下:

MeshNormals {
4; // 顶点法向量的个数
0.000000; 0.000000; 1.000000;, // 顶点1的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点2的法向量坐标
0.000000; 0.000000; 1.000000;, // 顶点3的法向量坐标
0.000000; 0.000000; 1.000000;; // 顶点4的法向量坐标

2; // 三角形面的法向量个数
3; 0, 1, 2;, // 法向量的索引数和3个法向量的索引值(计算面的法向量)
3; 3, 2, 1;; // 法向量的索引数和3个法向量的索引值(计算面的法向量)

}

来看看MeshNormals对象的模版数据说明,定义了顶点和三角形面的法向量,如下所示:

template MeshNormals {
<F6F23F43-7686-11cf-8F52-0040333594A3>
DWORD nNormals; // 顶点法向量个数
array Vector normals [nNormals]; // 顶点法向量数组
DWORD nFaceNormals; // 三角形面法向量个数
array MeshFace faceNormals[nFaceNormals]; // 三角形面法向量数组
}

template Vector {
<3D82AB5E-62DA-11cf-AB39-0020AF71E433>
FLOAT x;
FLOAT y;
FLOAT z;
}

template MeshFace {
<3D82AB5F-62DA-11cf-AB39-0020AF71E433>
DWORD nFaceVertexIndices;
array DWORD faceVertexIndices[nFaceVertexIndices];
}

在Mesh数据里又定义了一个正方形的纹理贴图模板数据MeshTextureCoords以指定纹理坐标如下:

MeshTextureCoords { // 纹理坐标模版
4; // 纹理坐标个数
0.000000; 1.000000;, // 纹理坐标1
1.000000; 1.000000;, // 纹理坐标2
0.000000; 0.000000;, // 纹理坐标3
1.000000; 0.000000;; // 纹理坐标4

}

来看看MeshTextureCoords模版的定义:

template MeshTextureCoords {
<F6F23F40-7686-11cf-8F52-0040333594A3>
DWORD nTextureCoords; // 纹理坐标数
array Coords2d textureCoords [nTextureCoords]; // 纹理坐标数组
}

template Coords2d {
<F6F23F44-7686-11cf-8F52-0040333594A3>
FLOAT u; // 纹理U坐标
FLOAT v; // 纹理V坐标

}
在Mesh数据里还定义了一个模板数据MeshMaterialList以指示材质信息:

MeshMaterialList { // 材质列表模版
1; // 材质个数
2; // 三角形面的材质索引数(实际是三角形面的个数)
0, // 第一个三角形使用0号材质索引
0, // 第二个三角形使用0号材质索引

Material{ // 材质模版
1.000000; 1.000000; 1.000000; 1.000000;; // 三角形面的颜色
0.000000; // 镜面光的高光强度
1.000000; 1.000000; 1.000000;; // 镜面光颜色
0.000000; 0.000000; 0.000000;; // 自发射光颜色

TextureFilename { // 纹理贴图文件
"bb.jpg";
};
}
}

MeshMaterialList模版说明该Mesh网格所使用的材质数目,每个三角形面对应的材质索引和Material材质对象。在MeshMaterialList模版中,用[Material <3D82AB4D-62DA-11cf-AB39-0020AF71E433>]来指明MeshMaterialList模版的对象可包含全局标志符为"3D82AB4D-62DA-11cf-AB39-0020AF71E433"的Material模版对象(可以不止一个对象)。

template MeshMaterialList { // 材质列表模版
<F6F23F42-7686-11cf-8F52-0040333594A3>
DWORD nMaterials; // 材质个数
DWORD nFaceIndexes; // 三角形面的材质索引数(实际是三角形面的个数)
array DWORD faceIndexes[nFaceIndexes]; // 三角形面的材质索引值
[Material
<3D82AB4D-62DA-11cf-AB39-0020AF71E433>] // 材质
}

template Material { // 材质模版
<3D82AB4D-62DA-11cf-AB39-0020AF71E433>
ColorRGBA faceColor; // 三角形面的颜色
FLOAT power; // 镜面光的高光强度
ColorRGB specularColor; // 镜面光的颜色
ColorRGB emissiveColor; // 自发射光的颜色
[...]
}

template ColorRGBA {
<35FF44E0-6C7C-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
FLOAT alpha;
}

template ColorRGB {
<D3E16E81-7835-11cf-8F52-0040333594A3>
FLOAT red;
FLOAT green;
FLOAT blue;
}


模版中通过"[模版]"的形式引入其他模版的对象,这种模版称为严格模版(Restricted Template)。MeshMaterialList模版就是一个严格模版。

通常在Material模版对象中加入纹理贴图文件的说明,此时需要使用TextureFilename模版对象来指定文件名。
template TextureFilename {
<A42790E1-7810-11cf-8F52-0040333594A3>
STRING filename; // 纹理贴图的文件名
}

最后,对模版的定义和使用进行简单的归纳。如下所示是模版的一般定义格式:
template <template-name> { // 模版定义
<GUID> // 全局标志符
<mmeber 1> // 成员1
....
<mmeber 2> // 成员2
[restrictions] // 其他模版对象
}

其中,各个成员对象的类型可取为WORD, DWORD, FLOAT, DOUBLE, CHAR, UCHAR, BYTE, STRING等。此外,还可以使用如下的数组形式来说明模版中的数据对象。
array <data-type> <name>[<dimension-size>];
array为数组的关键字,data-type为数组元素的类型,name为数组的名字,dimension-size为数组的维数。

模版的全局标志符可利用VS提供的guidgen.exe程序自动生成,该工具位于“$ vs_setup_dir\Common7\Tools”下,如下所示:



如果一个模版,如ColorRGB模版,不包含其他模版的数据,那么该模版称为封闭模版(Closed Template),是最简单的一种说明数据格式的模版。

在模版对象中,用来分隔数据的逗号和分号的用法需要补充说明一下。例如下面的变换矩阵的定义,中间全部用逗号分隔,最后用两个分号结束。
FrameTransformMatrix { // 主框架的变换矩阵
1.000000, 0.000000, 0.000000, 0.000000,
0.000000, 1.000000, 0.000000, 0.000000,
0.000000, 0.000000, 1.000000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000;;
}

在上面的矩阵数据中,中间的逗号是数组元素的分隔,最后的第一个分号来自于数组定义的结束,第二个分号来自于矩阵数据定义的结束。观察如下的模版定义,可以清楚的看出。
template FrameTransformMatrix {
<F6F23F41-7686-11cf-8F52-0040333594A3>
Matrix4x4 frameMatrix; // 产生第2个分号
}

template Matrix4x4 {
<F6F23F45-7686-11cf-8F52-0040333594A3>
array FLOAT matrix[16]; // 产生第1个分号,数组元素之间规定用逗号分隔
}

由此可见,定义模版对象数据时,应采用代入的观点进行数据的构造,即保持模版定义中的逗号和分号不变,只是将具体的数值代入相应的变量处,就可简单地构造出合法的模版对象数据。
 楼主| 发表于 2008-4-19 23:07:14 | 显示全部楼层
.X文件的数据装入

在上一篇的.X文件中,主场景框架 Scene_Root提供了一个变换矩阵和一个子框架Quad。这个Quad具有一个Mesh网格(包括顶点,材质,纹理等数据),其中 Scene_Root框架的变换矩阵(实际为单位矩阵)说明了Quad子框架的Mesh网格数据应做的变换,以正确摆放在父框架的空间中(这里指世界空间)。对于仅含有单一网格的.X文件来说,利用D3DXLoadMeshFromX函数可实现简单网格数据的加载。

来看看D3DXLoadMeshFromX的具体使用说明:

Loads a mesh from a DirectX .x file.

HRESULT D3DXLoadMeshFromX(
LPCTSTR pFilename,
DWORD Options,
LPDIRECT3DDEVICE9 pD3DDevice,
LPD3DXBUFFER * ppAdjacency,
LPD3DXBUFFER * ppMaterials,
LPD3DXBUFFER * ppEffectInstances,
DWORD * pNumMaterials,
LPD3DXMESH * ppMesh
);

Parameters

pFilename
[in] Pointer to a string that specifies the filename. If the compiler settings require Unicode, the data type LPCTSTR resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See Remarks.
Options
[in] Combination of one or more flags from the D3DXMESH enumeration, which specifies creation options for the mesh.
pD3DDevice
[in] Pointer to an IDirect3DDevice9 interface, the device object associated with the mesh.
ppAdjacency
[out] Pointer to a buffer that contains adjacency data. The adjacency data contains an array of three DWORDs per face that specify the three neighbors for each face in the mesh. For more information about accessing the buffer, see ID3DXBuffer.
ppMaterials
[out] Pointer to a buffer containing materials data. The buffer contains an array of D3DXMATERIAL structures, containing information from the DirectX file. For more information about accessing the buffer, see ID3DXBuffer.
ppEffectInstances
[out] Pointer to a buffer containing an array of effect instances, one per attribute group in the returned mesh. An effect instance is a particular instance of state information used to initialize an effect. See D3DXEFFECTINSTANCE. For more information about accessing the buffer, see ID3DXBuffer.
pNumMaterials
[out] Pointer to the number of D3DXMATERIAL structures in the ppMaterials array, when the method returns.
ppMesh
[out] Address of a pointer to an ID3DXMesh interface, representing the loaded mesh.

Return Values

If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be one of the following values: D3DERR_INVALIDCALL, E_OUTOFMEMORY.

Remarks

The compiler setting also determines the function version. If Unicode is defined, the function call resolves to D3DXLoadMeshFromXW. Otherwise, the function call resolves to D3DXLoadMeshFromXA because ANSI strings are being used.

All the meshes in the file will be collapsed into one output mesh. If the file contains a frame hierarchy, all the transformations will be applied to the mesh.

For mesh files that do not contain effect instance information, default effect instances will be generated from the material information in the .x file. A default effect instance will have default values that correspond to the members of the D3DMATERIAL9 structure.

The default texture name is also filled in, but is handled differently. The name will be Texture0@Name, which corresponds to an effect variable by the name of "Texture0" with an annotation called "Name." This will contain the string file name for the texture.


来看看参数Option可以指定的网格创建模式:

Flags used to specify creation options for a mesh.

typedef enum D3DXMESH
{
D3DXMESH_32BIT = 0x001,
D3DXMESH_DONOTCLIP = 0x002,
D3DXMESH_POINTS = 0x004,
D3DXMESH_RTPATCHES = 0x008,
D3DXMESH_NPATCHES = 0x4000,
D3DXMESH_VB_SYSTEMMEM = 0x010,
D3DXMESH_VB_MANAGED = 0x020,
D3DXMESH_VB_WRITEONLY = 0x040,
D3DXMESH_VB_DYNAMIC = 0x080,
D3DXMESH_VB_SOFTWAREPROCESSING = 0x8000,
D3DXMESH_IB_SYSTEMMEM = 0x100,
D3DXMESH_IB_MANAGED = 0x200,
D3DXMESH_IB_WRITEONLY = 0x400,
D3DXMESH_IB_DYNAMIC = 0x800,
D3DXMESH_IB_SOFTWAREPROCESSING = 0x10000,
D3DXMESH_VB_SHARE = 0x1000,
D3DXMESH_USEHWONLY = 0x2000,
D3DXMESH_SYSTEMMEM = 0x110,
D3DXMESH_MANAGED = 0x220,
D3DXMESH_WRITEONLY = 0x440,
D3DXMESH_DYNAMIC = 0x880,
D3DXMESH_SOFTWAREPROCESSING = 0x18000,
} D3DXMESH, *LPD3DXMESH;

Constants

D3DXMESH_32BIT
The mesh has 32-bit indices instead of 16-bit indices. See Remarks.
D3DXMESH_DONOTCLIP
Use the D3DUSAGE_DONOTCLIP usage flag for vertex and index buffers.
D3DXMESH_POINTS
Use the D3DUSAGE_POINTS usage flag for vertex and index buffers.
D3DXMESH_RTPATCHES
Use the D3DUSAGE_RTPATCHES usage flag for vertex and index buffers.
D3DXMESH_NPATCHES
Specifying this flag causes the vertex and index buffer of the mesh to be created with D3DUSAGE_NPATCHES flag. This is required if the mesh object is to be rendered using N-patch enhancement using Direct3D.
D3DXMESH_VB_SYSTEMMEM
Use the D3DPOOL_SYSTEMMEM usage flag for vertex buffers.
D3DXMESH_VB_MANAGED
Use the D3DPOOL_MANAGED usage flag for vertex buffers.
D3DXMESH_VB_WRITEONLY
Use the D3DUSAGE_WRITEONLY usage flag for vertex buffers.
D3DXMESH_VB_DYNAMIC
Use the D3DUSAGE_DYNAMIC usage flag for vertex buffers.
D3DXMESH_VB_SOFTWAREPROCESSING
Use the D3DUSAGE_SOFTWAREPROCESSING usage flag for vertex buffers.
D3DXMESH_IB_SYSTEMMEM
Use the D3DPOOL_SYSTEMMEM usage flag for index buffers.
D3DXMESH_IB_MANAGED
Use the D3DPOOL_MANAGED usage flag for index buffers.
D3DXMESH_IB_WRITEONLY
Use the D3DUSAGE_WRITEONLY usage flag for index buffers.
D3DXMESH_IB_DYNAMIC
Use the D3DUSAGE_DYNAMIC usage flag for index buffers.
D3DXMESH_IB_SOFTWAREPROCESSING
Use the D3DUSAGE_SOFTWAREPROCESSING usage flag for index buffers.
D3DXMESH_VB_SHARE
Forces the cloned meshes to share vertex buffers.
D3DXMESH_USEHWONLY
Use hardware processing only. For mixed-mode device, this flag will cause the system to use hardware (if supported in hardware) or will default to software processing.
D3DXMESH_SYSTEMMEM
Equivalent to specifying both D3DXMESH_VB_SYSTEMMEM and D3DXMESH_IB_SYSTEMMEM.
D3DXMESH_MANAGED
Equivalent to specifying both D3DXMESH_VB_MANAGED and D3DXMESH_IB_MANAGED.
D3DXMESH_WRITEONLY
Equivalent to specifying both D3DXMESH_VB_WRITEONLY and D3DXMESH_IB_WRITEONLY.
D3DXMESH_DYNAMIC
Equivalent to specifying both D3DXMESH_VB_DYNAMIC and D3DXMESH_IB_DYNAMIC.
D3DXMESH_SOFTWAREPROCESSING
Equivalent to specifying both D3DXMESH_VB_SOFTWAREPROCESSING and D3DXMESH_IB_SOFTWAREPROCESSING.

Remarks

A 32-bit mesh (D3DXMESH_32BIT) can theoretically support (2^32)-1 faces and vertices. However, allocating memory for a mesh that large on a 32-bit operating system is not practical.


参数ppAdjacency, ppMaterials, ppEffectInstances的类型都是LPD3DXBUFFER,它实际上是指向ID3DXBUFFER的指针:

 楼主| 发表于 2008-4-19 23:07:32 | 显示全部楼层

The ID3DXBuffer interface is used as a data buffer, storing vertex, adjacency, and material information during mesh optimization and loading operations. The buffer object is used to return arbitrary length data. Also, buffer objects are used to return object code and error messages in methods that assemble vertex and pixel shaders.

ID3DXBuffer Members

MethodDescription
ID3DXBuffer::GetBufferPointerRetrieves a pointer to the data in the buffer.
ID3DXBuffer::GetBufferSizeRetrieves the total size of the data in the buffer.

Remarks

The ID3DXBuffer interface is obtained by calling the D3DXCreateBuffer function.

The LPD3DXBUFFER type is defined as a pointer to the ID3DXBuffer interface.

typedef interface ID3DXBuffer ID3DXBuffer;
typedef interface ID3DXBuffer *LPD3DXBUFFER;

来看看ID3DXBuffer提供的两个方法,先来看看GetBufferPointer的具体使用信息:
Retrieves a pointer to the data in the buffer.

LPVOID GetBufferPointer();

Parameters
None.

Return Values
Returns a pointer to the data in the buffer.

再来看看GetBufferSize的具体使用信息:

Retrieves the total size of the data in the buffer.

DWORD GetBufferSize();

Parameters
None.

Return Values
Returns the total size of the data in the buffer, in bytes.


ID3DXBuffer可利用DirectX API函数D3DXCreateBuffer来创建,不过,一般不需要直接创建,下面是该函数的具体使用信息:

Creates a buffer object.

HRESULT D3DXCreateBuffer(
DWORD NumBytes,
LPD3DXBUFFER * ppBuffer
);

Parameters

NumBytes
[in] Size of the buffer to create, in bytes.

ppBuffer
[out] Address of a pointer to an ID3DXBuffer interface, representing the created buffer object.

Return Values

If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be one of the following: E_OUTOFMEMORY.

利用pNumMaterials指针参数可获得网格mesh所使用的材质的数量,ppMesh参数则是返回的一个ID3DXMESH 接口的指针地址,利用ID3DXMESH 接口提供的方法,可对装入的网格数据进行读取,优化和渲染等。

由于利用D3DXLoadMeshFromX函数装入的材质和纹理贴图文件名被封装在一个扩展的D3DXMATERIAL结构体内,因此通常需要将材质取出,放入材质数组中,将纹理贴图文件名取出,创建相应的纹理对象,再将这些纹理对象放入纹理对象数组中,以方便后续的纹理网格渲染。

来看看D3DXMATERIAL的具体信息:
Returns material information saved in Direct3D (.x) files.

typedef struct D3DXMATERIAL {
D3DMATERIAL9 MatD3D;
LPSTR pTextureFilename;
} D3DXMATERIAL, *LPD3DXMATERIAL;

Members

MatD3D
D3DMATERIAL9 structure that describes the material properties.

pTextureFilename
Pointer to a string that specifies the file name of the texture.

Remarks

The D3DXLoadMeshFromX and D3DXLoadMeshFromXof functions return an array of D3DXMATERIAL structures that specify the material color and name of the texture for each material in the mesh. The application is then required to load the texture.

The LPD3DXMATERIAL type is defined as a pointer to the D3DXMATERIAL structure.

typedef struct D3DXMATERIAL* LPD3DXMATERIAL;

其中用到了结构体D3DMATERIAL9,它的具体定义是:
Specifies material properties.

typedef struct D3DMATERIAL9 {
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Ambient;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Emissive;
float Power;
} D3DMATERIAL9, *LPD3DMATERIAL9;

Members

Diffuse
Value specifying the diffuse color of the material. See D3DCOLORVALUE.

Ambient
Value specifying the ambient color of the material. See D3DCOLORVALUE.

Specular
Value specifying the specular color of the material. See D3DCOLORVALUE.

Emissive
Value specifying the emissive color of the material. See D3DCOLORVALUE.

Power
Floating-point value specifying the sharpness of specular highlights. The higher the value, the sharper the highlight.

Remarks

To turn off specular highlights, set D3DRS_SPECULARENABLE to FALSE, using D3DRENDERSTATETYPE. This is the fastest option because no specular highlights will be calculated.

For more information about using the lighting engine to calculate specular lighting, see Specular Lighting (Direct3D 9).

下面的代码演示了怎样加载.X文件,以及加载后怎样获得相应的数据。
IDirect3D9* _d3d;
IDirect3DDevice9* _d3d_device;
ID3DXBuffer* _adjacency_buffer;
ID3DXBuffer* _material_buffer;
D3DMATERIAL9* _material_array;
IDirect3DTexture9** _texture_array;

DWORD _num_materials;
ID3DXMesh* _mesh;

//------------------------------------------------------------------------------------
// Load .X file
//------------------------------------------------------------------------------------
bool BASIC_XFILE:oad_XFile(char* x_filename)
{
// Loads a mesh from a DirectX .x file
if(FAILED(D3DXLoadMeshFromX(
x_filename, // Pointer to a string that specifies the filename
D3DXMESH_MANAGED, // specifies creation options for the mesh
_d3d_device, // Pointer to an IDirect3DDevice9 interface
&_adjacency_buffer, // Pointer to a buffer that contains adjacency data
&_material_buffer, // Pointer to a buffer containing materials data
NULL, // Pointer to a buffer containing an array of effect instances
&_num_materials, // Pointer to the number of D3DXMATERIAL structures
&_mesh))) // Address of a pointer to an ID3DXMesh interface
{
MessageBox(NULL, "Load .X file failed.", "ERROR", MB_OK);
return false;
}

// invalid data
if(_material_buffer == NULL || _num_materials == 0)
return false;

// retrieves a pointer to the data in the buffer
D3DXMATERIAL* material = (D3DXMATERIAL*) _material_buffer->GetBufferPointer();

if(material != NULL)
{
// allocate memory for material array and texture array
_material_array = new D3DMATERIAL9[_num_materials];
_texture_array = new IDirect3DTexture9*[_num_materials];

for(DWORD i = 0; i < _num_materials; i++)
{
// assign material to array
_material_array = material.MatD3D;

if(material.pTextureFilename != NULL)
{
if(FAILED(D3DXCreateTextureFromFile(_d3d_device, material.pTextureFilename, &_texture_array)))
_texture_array = NULL;
}
}
}

// Generates a mesh with reordered faces and vertices to optimize drawing performance.
// This method reorders the existing mesh.
_mesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*) _adjacency_buffer->GetBufferPointer(), NULL, NULL, NULL);

_material_buffer->Release();
_adjacency_buffer->Release();

return true;
}
 楼主| 发表于 2008-4-19 23:07:47 | 显示全部楼层
Mesh数据的处理

执行D3DXLoadMeshFromX函数完成.X文件的加载后,Mesh的各种数据将存放在顶点缓冲区,顶点索引缓冲区,材质缓冲区,邻接顶点缓冲区,特效属性缓冲区,网格缓冲区中。其中,材质缓冲区(包含材质信息和纹理贴图文件名信息),邻接顶点缓冲区以及特效属性缓冲区的地址由 D3DXLoadMeshFromX函数成功执行后返回,其他的缓冲区地址可利用ID3DXMesh接口函数来获得。

.X网格的渲染和优化就是使用上面缓冲区的数据来进行的。顶点缓冲区给出了整个网格的顶点坐标列表(包括顶点坐标和顶点纹理坐标),顶点索引缓冲区给出了每个三角形面的顶点构成信息(三个顶点的索引值),从而间接给出了整个网格的所有三角形面的顶点信息说明,属性缓冲区为每个三角形面的一个网格子集编号,即给出了网格的每个三角形面的分组号。具有同一个Subset编号的三角形,将使用相同的材质和纹理对象进行渲染。

Mesh网格的渲染,可以用一个for循环来进行,循环的次数为总的材质数。每一次循环都将那些具有相同Subset子集号的三角形面渲染出来,即渲染每个子集Subset。不过每次循环首先要设置渲染管道线的材质和纹理对象,如下所示:
//------------------------------------------------------------------------------------
// Render mesh.
//------------------------------------------------------------------------------------
void BASIC_XFILE::Render()
{
// Clear a render target and the depth buffer
_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

_d3d_device->BeginScene();

// draw all face in the mesh
for(DWORD i = 0; i < _num_materials; i++)
{
// Sets the material properties for the device
_d3d_device->SetMaterial(&_material_array);

// Assigns a texture to a stage for a device
_d3d_device->SetTexture(0, _texture_array);

// Draws a subset of a mesh
_mesh->DrawSubset(i);
}

_d3d_device->EndScene();

// Presents the contents of the next buffer in the sequence of back buffers owned by the device
_d3d_device->resent(NULL, NULL, NULL, NULL);
}

上面的代码中使用Clear对Z缓冲区进行了清除,因此必须在初始化D3D设备时,开启Z缓冲区,否则该函数调用失败并且屏幕将出现重影。
D3DPRESENT_PARAMETERS present_param;

present_param.EnableAutoDepthStencil = TRUE;

如果没有加入上面的代码,则出现重影,如下图所示:



Render函数中使用DrawSubset函数来渲染每一个Mesh子集,该函数只需要指定一个子集号,就可将网格中具有该子集号的三角形面渲染出来,下面是该函数的具体使用信息:
Draws a subset of a mesh.

HRESULT DrawSubset(
DWORD AttribId
);

Parameters

AttribId
[in] DWORD that specifies which subset of the mesh to draw. This value is used to differentiate faces in a mesh as belonging to one or more attribute groups.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.

Remarks

The subset that is specified by AttribId will be rendered by the IDirect3DDevice9:rawIndexedPrimitive method, using the D3DPT_TRIANGLELIST primitive type, so an index buffer must be properly initialized.

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 (AttribId) when drawing the frame.
 楼主| 发表于 2008-4-19 23:08:10 | 显示全部楼层
上篇介绍了.X文件网格的渲染方法,如果需要创建自己的网格文件,并将它渲染出来,那么可以考虑创建一个空的网格,然后读取网格文件内容,将顶点,材质和纹理数据写入以上的网格相关缓冲区中。

创建一个自定义顶点格式的空Mesh网格可由 D3DXCreateMeshFVF来实现,来看看它的具体信息说明:

Creates a mesh object using a flexible vertex format (FVF) code.

HRESULT D3DXCreateMeshFVF(
DWORD NumFaces,
DWORD NumVertices,
DWORD Options,
DWORD FVF,
LPDIRECT3DDEVICE9 pD3DDevice,
LPD3DXMESH * ppMesh
);

Parameters

NumFaces
[in] Number of faces for the mesh. The valid range for this number is greater than 0, and one less than the max DWORD value, typically 232 - 1, because the last index is reserved.
NumVertices
[in] Number of vertices for the mesh. This parameter must be greater than 0.
Options
[in] Combination of one or more flags from the D3DXMESH enumeration, specifying creation options for the mesh.
FVF
[in] Combination of D3DFVF that describes the vertex format for the returned mesh. This function does not support D3DFVF_XYZRHW.
pD3DDevice
[in] Pointer to an IDirect3DDevice9 interface, the device object to be associated with the mesh.
ppMesh
[out] Address of a pointer to an ID3DXMesh interface, representing the created mesh object.

Return Values

If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be one of the following: D3DERR_INVALIDCALL, E_OUTOFMEMORY.


空网格创建出来后,用ID3DXMesh接口的LockVertexBuffer函数取得顶点缓冲区的指针,这样就可以将文件的顶点数据写入已锁定的缓冲区内,最后还要调用UnlockVertexBuffer来进行解锁。

来看看 LockVertexBuffer函数的具体信息说明:

Locks a vertex buffer and obtains a pointer to the vertex buffer memory.

HRESULT LockVertexBuffer(
DWORD Flags,
LPVOID * ppData
);

Parameters

Flags

Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:

  • D3DLOCK_DISCARD
  • D3DLOCK_NO_DIRTY_UPDATE
  • D3DLOCK_NOSYSLOCK
  • D3DLOCK_READONLY
  • D3DLOCK_NOOVERWRITE
[in] For a description of the flags, see D3DLOCK.

ppData
[out, retval] VOID* pointer to a buffer containing the vertex data.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.

Remarks

When working with vertex buffers, you are allowed to make multiple lock calls; however, you must ensure that the number of lock calls match the number of unlock calls. DrawPrimitive calls will not succeed with any outstanding lock count on any currently set vertex buffer.


来看看参数Flags可以使用的D3DLOCK的具体定义:

A combination of zero or more locking options that describe the type of lock to perform.

#defineDescription
D3DLOCK_DISCARDThe application discards all memory within the locked region. For vertex and index buffers, the entire buffer will be discarded. This option is only valid when the resource is created with dynamic usage (see D3DUSAGE).
D3DLOCK_DONOTWAITAllows an application to gain back CPU cycles if the driver cannot lock the surface immediately. If this flag is set and the driver cannot lock the surface immediately, the lock call will return D3DERR_WASSTILLDRAWING. This flag can only be used when locking a surface created using IDirect3DDevice9::CreateOffscreenPlainSurface, IDirect3DDevice9::CreateRenderTarget, or IDirect3DDevice9::CreateDepthStencilSurface. This flag can also be used with a back buffer.
D3DLOCK_NO_DIRTY_UPDATEBy default, a lock on a resource adds a dirty region to that resource. This option prevents any changes to the dirty state of the resource. Applications should use this option when they have additional information about the set of regions changed during the lock operation.
D3DLOCK_NOOVERWRITEIndicates that memory that was referred to in a drawing call since the last lock without this flag will not be modified during the lock. This can enable optimizations when the application is appending data to a resource. Specifying this flag enables the driver to return immediately if the resource is in use, otherwise, the driver must finish using the resource before returning from locking.
D3DLOCK_NOSYSLOCKThe default behavior of a video memory lock is to reserve a system-wide critical section, guaranteeing that no display mode changes will occur for the duration of the lock. This option causes the system-wide critical section not to be held for the duration of the lock.

The lock operation is time consuming, but can enable the system to perform other duties, such as moving the mouse cursor. This option is useful for long-duration locks, such as the lock of the back buffer for software rendering that would otherwise adversely affect system responsiveness.

D3DLOCK_READONLYThe application will not write to the buffer. This enables resources stored in non-native formats to save the recompression step when unlocking.
 楼主| 发表于 2008-4-19 23:08:35 | 显示全部楼层
再来看看UnlockVertexBuffer函数的具体信息说明:

Unlocks a vertex buffer.

HRESULT UnlockVertexBuffer();

Parameters

None.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.


同样,利用ID3DXMesh接口的LockIndexBuffer和UnlockIndexBuffer函数,可锁定顶点索引缓冲区,并写入三角形面的顶点索引值,然后解锁。

LockIndexBuffer的具体使用信息如下所示:

Locks an index buffer and obtains a pointer to the index buffer memory.

HRESULT LockIndexBuffer(
DWORD Flags,
LPVOID * ppData
);

Parameters

Flags

Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:

  • D3DLOCK_DISCARD
  • D3DLOCK_NO_DIRTY_UPDATE
  • D3DLOCK_NOSYSLOCK
  • D3DLOCK_READONLY
[in] For a description of the flags, see D3DLOCK.

ppData
[out, retval] VOID* pointer to a buffer containing the index data. The count of indices in this buffer will be equal to ID3DXBaseMesh::GetNumFaces * 3.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.

Remarks

When working with index buffers, you are allowed to make multiple lock calls. However, you must ensure that the number of lock calls match the number of unlock calls. DrawPrimitive calls will not succeed with any outstanding lock count on any currently set index buffer.


该函数使用信息说明中提到的GetNumFaces用来获取该网格包含的三角形面数,信息说明如下所示:

Retrieves the number of faces in the mesh.

DWORD GetNumFaces();

Parameters

None.

Return Values

Returns the number of faces in the mesh.


再来看看UnlockIndexBuffer的使用说明:

Unlocks an index buffer.

HRESULT UnlockIndexBuffer();

Parameters

None.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.


接着我们可以利用ID3DXMesh接口的LockAttributeBuffer函数锁定属性缓冲区,并取得缓冲区的指针,然后将每个三角形面的子集号写入,最后调用该接口的UnlockAttributeBuffer函数将缓冲区解锁。

来看看LockAttributeBuffer的使用说明:

Locks the mesh buffer that contains the mesh attribute data, and returns a pointer to it.

HRESULT LockAttributeBuffer(
DWORD Flags,
DWORD ** ppData
);

Parameters

Flags

Combination of zero or more locking flags that describe the type of lock to perform. For this method, the valid flags are:

  • D3DLOCK_DISCARD
  • D3DLOCK_NO_DIRTY_UPDATE
  • D3DLOCK_NOSYSLOCK
  • D3DLOCK_READONLY
[in] For a description of the flags, see D3DLOCK.

ppData
[out] Address of a pointer to a buffer containing a DWORD for each face in 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

If ID3DXMesh::Optimize has been called, the mesh will also have an attribute table that can be accessed using the ID3DXBaseMesh::GetAttributeTable method.


再来看看UnlockAttributeBuffer的使用说明:

Unlocks an attribute buffer.

HRESULT UnlockAttributeBuffer();

Parameters

None.

Return Values

If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.


如果网格没有提供各顶点的法向量坐标数据,可使用ID3DXMesh接口的CloneMeshFVF函数复制生成一个包含法向量的网格,然后调用D3DXComputeNormals计算各顶点的法向量。

来看看CloneMeshFVF的使用说明:

Clones a mesh using a flexible vertex format (FVF) code.

HRESULT CloneMeshFVF(
DWORD Options,
DWORD FVF,
LPDIRECT3DDEVICE9 pDevice,
LPD3DXMESH * ppCloneMesh
);

Parameters

Options
[in] A combination of one or more D3DXMESH flags specifying creation options for the mesh.
FVF
[in] Combination of FVF codes, which specifies the vertex format for the vertices in the output mesh. For the values of the codes, see D3DFVF.
pDevice
[in] Pointer to an IDirect3DDevice9 interface representing the device object associated with the mesh.
ppCloneMesh
[out, retval] Address of a pointer to an ID3DXMesh interface, representing the cloned 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

ID3DXBaseMesh::CloneMeshFVF is used to reformat and change the vertex data layout. This is done by creating a new mesh object. For example, use it to to add space for normals, texture coordinates, colors, weights, etc. that were not present before.

ID3DXBaseMesh::UpdateSemantics updates the vertex declaration with different semantic information without changing the layout of the vertex buffer. This method does not modify the contents of the vertex buffer. For example, use it to relabel a 3D texture coordinate as a binormal or tangent or vice versa.


以及D3DXComputeNormals的使用说明:

Computes unit normals for each vertex in a mesh. Provided to support legacy applications. Use D3DXComputeTangentFrameEx for better results.

HRESULT D3DXComputeNormals(
LPD3DXBASEMESH pMesh,
CONST DWORD * pAdjacency
);

Parameters

pMesh
[in, out] Pointer to an ID3DXBaseMesh interface, representing the normalized mesh object. This function may not take an ID3DXPMesh progressive mesh as input.
pAdjacency
[in] Pointer to an array of three DWORDs per face that specify the three neighbors for each face in the created progressive mesh. This parameter is optional and should be set to NULL if it is unused.

Return Values

If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the following: D3DERR_INVALIDCALL, D3DXERR_INVALIDDATA, E_OUTOFMEMORY.

Remarks

 楼主| 发表于 2008-4-19 23:09:00 | 显示全部楼层

The input mesh must have the D3DFVF_NORMAL flag specified in its flexible vertex format (FVF).

A normal for a vertex is generated by averaging the normals of all faces that share that vertex.

If adjacency is provided, replicated vertices are ignored and "smoothed" over. If adjacency is not provided, replicated vertices will have normals averaged in from only the faces explicitly referencing them.

This function simply calls D3DXComputeTangentFrameEx with the following input parameters:

D3DXComputeTangentFrameEx( pMesh,
D3DX_DEFAULT,
0,
D3DX_DEFAULT,
0,
D3DX_DEFAULT,
0,
D3DDECLUSAGE_NORMAL,
0,
D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_CALCULATE_NORMALS,
pAdjacency,
-1.01f,
-0.01f,
-1.01f,
NULL,
NULL);

下面的代码通过复制的方法生成了一个具有顶点法向量信息的网格:
LPD3DXMESH mesh;
LPD3DXMESH mesh_clone = NULL;

mesh->CloneMeshFVF(mesh->GetOptions(), mesh->GetFVF() | D3DFVF_NORMAL, _d3d_device, &mesh_clone);

D3DXComputeNormals(mesh_clone, NULL);

Mesh数据的优化

.X文件的网格数据装入缓冲区后,每个网格子集的数据可以进行优化,以提高子集渲染速度。对于顶点缓冲区来说,可以把位于同一个子集的顶点进行连续排放,减少三角形面的索引,也可以对邻接的顶点进行压缩,节省内存消耗和提高顶点的命中率。对于顶点索引缓冲区来说,该缓冲区提供了网格的所有三角形面的构成信息,如果把位于同一个子集的三角形面集中连续排放,就可以使属性缓冲区的子集编号按序排列。

ID3DXMesh接口提供了OptimizeInplace 函数进行网格数据各种类型的优化,它的使用说明如下所示:

Generates a mesh with reordered faces and vertices to optimize drawing performance. This method reorders the existing mesh.

HRESULT OptimizeInplace(
DWORD Flags,
CONST DWORD * pAdjacencyIn,
DWORD * pAdjacencyOut,
DWORD * pFaceRemap,
LPD3DXBUFFER * ppVertexRemap
);

Parameters

Flags
[in] Combination of one or more D3DXMESHOPT flags, specifying the type of optimization to perform.
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.
pAdjacencyOut
[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. If the value supplied for this argument is NULL, adjacency data is not returned.
pFaceRemap
[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. If the value supplied for this argument is NULL, vertex remap data is not returned.

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, D3DXERR_CANNOTATTRSORT, E_OUTOFMEMORY.

Remarks

Before running ID3DXMesh::OptimizeInplace, 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.

Note This method will fail if the mesh is sharing its vertex buffer with another mesh, unless the D3DXMESHOPT_IGNOREVERTS is set in Flags.


下面来看看参数Flags可以使用的网格优化类型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:rawSubset 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.


D3DXLoadMeshFromX函数装入.X文件时,会自动为网格填充一个三角形面的邻接数组缓冲区,也可以利用 ID3DXMesh接口提供的GenerateAdjacency函数来生成,下面是该函数的具体使用说明:

Generate a list of mesh edges, as well as a list of faces that share each edge.

HRESULT GenerateAdjacency(
FLOAT Epsilon,
DWORD * pAdjacency
);

Parameters

Epsilon
[in] Specifies that vertices that differ in position by less than epsilon should be treated as coincident.
pAdjacency
[in] Pointer to an array of three DWORDs per face to be filled with the indices of adjacent faces. The number of bytes in this array must be at least 3 * ID3DXBaseMesh::GetNumFaces * sizeof(DWORD).

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

After an application generates adjacency information for a mesh, the mesh data can be optimized for better drawing performance.

The order of the entries in the adjacency buffer is determined by the order of the vertex indices in the index buffer. The adjacent triangle 0 always corresponds to the edge between the indices of the corners 0 and 1. The adjacent triangle 1 always corresponds to the edge between the indices of the corners 1 and 2 while the adjacent triangle 2 corresponds to the edge between the indices of the corners 2 and 0.


下面的代码段给出了利用OptimizeInplace进行优化的示例:

// Generates a mesh with reordered faces and vertices to optimize drawing performance.
// This method reorders the existing mesh.
_mesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*) _adjacency_buffer->GetBufferPointer(), NULL, NULL, NULL);

值得一提的是,进行D3DXMESHOPT_ATTRSORT优化操作后,将生成一个Attribute Table,它是一个D3DXATTRIBUTERANGE类型的数组,反映了优化后的子集的三角形面的划分和顶点的划分。 D3DXATTRIBUTERANGE的具体定义如下所示:

Stores an attribute table entry.

typedef struct D3DXATTRIBUTERANGE {
DWORD AttribId;
DWORD FaceStart;
DWORD FaceCount;
DWORD VertexStart;
DWORD VertexCount;
} D3DXATTRIBUTERANGE, *LPD3DXATTRIBUTERANGE;

Members

AttribId
Attribute table identifier.
FaceStart
Starting face.
FaceCount
Face count.
VertexStart
Starting vertex.
VertexCount
Vertex count.

Remarks

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 (AttribId) when drawing the frame.

The LPD3DXATTRIBUTERANGE type is defined as a pointer to the D3DXATTRIBUTERANGE structure.

typedef D3DXATTRIBUTERANGE* LPD3DXATTRIBUTERANGE;

可以调用ID3DXMesh接口的GetAttribute方法来获得指向属性表的指针和属性表的大小,该函数具体说明如下:

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.

 楼主| 发表于 2008-4-19 23:09:27 | 显示全部楼层
好了,现在来看一个例子。

需要在工程中设置链接d3dx9.lib d3d9.lib dinput8.lib dxguid.lib winmm.lib。
由于文件中用到了GE_APP和GE_INPUT这两个类,它的具体使用说明请参阅 主窗口和DirectInput的封装。
文件中同时还用到了GE_TIMER这个类,它的具体使用说明请参阅
游戏中时间的封装

若发现代码中存在错误,敬请指出。


源码与素材下载

来看看XFileLoad.h的定义:

/*************************************************************************************
[Include File]

PURPOSE:
Load .X file.
*************************************************************************************/


#ifndef BASIC_XFILE_H
#define BASIC_XFILE_H

class BASIC_XFILE
{
private:
IDirect3D9* _d3d;
IDirect3DDevice9* _d3d_device;
ID3DXBuffer* _adjacency_buffer;
ID3DXBuffer* _material_buffer;
D3DMATERIAL9* _material_array;
IDirect3DTexture9** _texture_array;

DWORD _num_materials;
ID3DXMesh* _mesh;
D3DXVECTOR3 _eye_point;

public:
BASIC_XFILE();
~BASIC_XFILE();

bool Create_D3D_Device(HWND hwnd, bool full_screen = true);
bool Load_XFile(char* x_filename);
void Render();
void Set_Camera();
void Set_Projection();
void Rotate(float angle);
void Release_Direct3D();
};

#endif

再来看看XFileLoad.cpp的定义:

/*************************************************************************************
[Implement File]

PURPOSE:
Load .X file.
*************************************************************************************/


#include "GE_COMMON.h"
#include "XFileLoad.h"

//------------------------------------------------------------------------------------
// Constrcutor, initialize data member.
//------------------------------------------------------------------------------------
BASIC_XFILE::BASIC_XFILE()
{
_d3d_device = NULL;
_adjacency_buffer = NULL;
_material_buffer = NULL;
_material_array = NULL;
_texture_array = NULL;
_mesh = NULL;

_num_materials = 0;

_eye_point = D3DXVECTOR3(3.0f, 0.0f, -3.0f);
}

//------------------------------------------------------------------------------------
// Destructor, release all Direct3D resource has allocated.
//------------------------------------------------------------------------------------
BASIC_XFILE::~BASIC_XFILE()
{
Release_Direct3D();
}

//------------------------------------------------------------------------------------
// Create direct3D interface and direct3D device.
//------------------------------------------------------------------------------------
bool BASIC_XFILE::Create_D3D_Device(HWND hwnd, bool full_screen)
{
// Create a IDirect3D9 object and returns an interace to it.
_d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(_d3d == NULL)
return false;

// retrieve adapter capability
D3DCAPS9 d3d_caps;
_d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d_caps);

bool hardware_process_enable = (d3d_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ? true : false);

// Retrieves the current display mode of the adapter.
D3DDISPLAYMODE display_mode;
if(FAILED(_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &display_mode)))
return false;

// set present parameter for direct3D device
D3DPRESENT_PARAMETERS present_param;

ZeroMemory(&present_param,
sizeof(present_param));

present_param.BackBufferWidth = WINDOW_WIDTH;
present_param.BackBufferHeight = WINDOW_HEIGHT;
present_param.BackBufferFormat = display_mode.Format;
present_param.BackBufferCount = 1;
present_param.hDeviceWindow = hwnd;
present_param.Windowed = !full_screen;
present_param.SwapEffect = D3DSWAPEFFECT_FLIP;
present_param.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
present_param.EnableAutoDepthStencil = TRUE;
present_param.AutoDepthStencilFormat = D3DFMT_D16;

// Creates a device to represent the display adapter.
DWORD behavior_flags;

behavior_flags = hardware_process_enable ? D3DCREATE_HARDWARE_VERTEXPROCESSING :

D3DCREATE_SOFTWARE_VERTEXPROCESSING;

if(FAILED(_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, behavior_flags,
&present_param, &_d3d_device)))
{
return false;
}

// create successfully
return true;
}

//------------------------------------------------------------------------------------
// Load .X file
//------------------------------------------------------------------------------------
bool BASIC_XFILE:oad_XFile(char* x_filename)
{
// Loads a mesh from a DirectX .x file
if(FAILED(D3DXLoadMeshFromX(
x_filename,
// Pointer to a string that specifies the filename
D3DXMESH_MANAGED, // specifies creation options for the mesh
_d3d_device, // Pointer to an IDirect3DDevice9 interface
&_adjacency_buffer, // Pointer to a buffer that contains adjacency data
&_material_buffer, // Pointer to a buffer containing materials data
NULL, // Pointer to a buffer containing an array of effect instances
&_num_materials, // Pointer to the number of D3DXMATERIAL structures
&_mesh))) // Address of a pointer to an ID3DXMesh interface
{
MessageBox(NULL, "Load .X file failed.", "ERROR", MB_OK);
return false;
}

// invalid data
if(_material_buffer == NULL || _num_materials == 0)
return false;

// retrieves a pointer to the data in the buffer
D3DXMATERIAL* material = (D3DXMATERIAL*) _material_buffer->GetBufferPointer();

if(material != NULL)
{
// allocate memory for material array and texture array
_material_array = new D3DMATERIAL9[_num_materials];
_texture_array =
new IDirect3DTexture9*[_num_materials];

for(DWORD i = 0; i < _num_materials; i++)
{
// assign material to array
_material_array = material.MatD3D;

if(material.pTextureFilename != NULL)
{
if(FAILED(D3DXCreateTextureFromFile(_d3d_device, material.pTextureFilename, &_texture_array)))
_texture_array = NULL;
}
}
}

// Generates a mesh with reordered faces and vertices to optimize drawing performance.
// This method reorders the existing mesh.
_mesh->OptimizeInplace(D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*) _adjacency_buffer->GetBufferPointer(), NULL, NULL, NULL);

_material_buffer->Release();
_adjacency_buffer->Release();

return true;
}

//------------------------------------------------------------------------------------
// Render mesh.
//------------------------------------------------------------------------------------
void BASIC_XFILE::Render()
{
// Clear a render target and the depth buffer
_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

_d3d_device->BeginScene();

// draw all face in the mesh
for(DWORD i = 0; i < _num_materials; i++)
{
// Sets the material properties for the device
_d3d_device->SetMaterial(&_material_array);

// Assigns a texture to a stage for a device
_d3d_device->SetTexture(0, _texture_array);

// Draws a subset of a mesh
_mesh->DrawSubset(i);
}

_d3d_device->EndScene();

// Presents the contents of the next buffer in the sequence of back buffers owned by the device
_d3d_device->resent(NULL, NULL, NULL, NULL);
}

//------------------------------------------------------------------------------------
// Set camera's view transformation matrix
//------------------------------------------------------------------------------------
void BASIC_XFILE::Set_Camera()
{
D3DXVECTOR3 at(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);

D3DXMATRIX view_matrix;

// get transformation matrix to transform world coordinate into view coordinate
D3DXMatrixLookAtLH(&view_matrix, &_eye_point, &at, &up);

// set view transformation matrix to D3D device
_d3d_device->SetTransform(D3DTS_VIEW, &view_matrix);
}

//------------------------------------------------------------------------------------
// Set projection matrix for D3D device.
//------------------------------------------------------------------------------------
void BASIC_XFILE::Set_Projection()
{
D3DXMATRIX proj_matrix;

// build a perspective matrix using left hand
D3DXMatrixPerspectiveFovLH(&proj_matrix, D3DX_PI/2, WINDOW_WIDTH/WINDOW_HEIGHT, 1.0f, 1000.0f);

// set projection matrix to D3D device
_d3d_device->SetTransform(D3DTS_PROJECTION, &proj_matrix);

// enable automatic normalization of vertex normals
_d3d_device->SetRenderState(D3DRS_NORMALIZENORMALS, true);

// set magnification filter with linear mode
_d3d_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

// set minification filter with linear mode
_d3d_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

// set mipmap filter with point mode
_d3d_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

// disable lighting
_d3d_device->SetRenderState(D3DRS_LIGHTING, false);
}

//------------------------------------------------------------------------------------
// Rotate eye point with specified angle around y axis.
//------------------------------------------------------------------------------------
void BASIC_XFILE::Rotate(float angle)
{
D3DXMATRIX mat_rotate;

// Builds a matrix that rotates around the y-axis
D3DXMatrixRotationY(&mat_rotate, angle);

// Transforms a 3D vector by a given matrix, projecting the result back into w = 1.
D3DXVec3TransformCoord(&_eye_point, &_eye_point, &mat_rotate);
}

//------------------------------------------------------------------------------------
// Release all Direct3D object.
//------------------------------------------------------------------------------------
void BASIC_XFILE::Release_Direct3D()
{
for(DWORD i = 0; i < _num_materials; i++)
Safe_Release(_texture_array);

Safe_Release(_mesh);
Safe_Release(_d3d_device);
}
 楼主| 发表于 2008-4-19 23:09:39 | 显示全部楼层
最后看看测试文件main.cpp的实现:

/*************************************************************************************
[Implement File]

PURPOSE:
Test for loading .X file.
*************************************************************************************/


#define DIRECTINPUT_VERSION 0x0800

#include "GE_COMMON.h"
#include "GE_APP.h"
#include "GE_INPUT.h"
#include "GE_TIMER.h"
#include "XFileLoad.h"

#pragma warning(disable : 4305 4996)

const float ROTATE_ANGLE = 0.05;

int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
GE_APP ge_app;
GE_INPUT ge_input;
GE_TIMER ge_timer;

BASIC_XFILE x_file;

MSG msg = {0};

// create window
if(! ge_app.Create_Window("Transparent blending test", instance, cmd_show))
return false;

ge_timer.Init_Game_Time();

HWND hwnd = ge_app.Get_Window_Handle();

SetWindowPos(hwnd, 0, 0,0,0,0, SWP_NOSIZE);
SetCursorPos(0, 0);

// create direct input
ge_input.Create_Input(instance, hwnd);

// Create direct3D interface and direct3D device.
if(! x_file.Create_D3D_Device(hwnd, false))
return false;

if(x_file.Load_XFile("tiger.x"))
{
x_file.Set_Camera();
x_file.Set_Projection();
x_file.Render();
}

float last_render_time = ge_timer.Get_Game_Play_Time();

while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, NULL, 0,0 , PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// get keyboard input
if(ge_input.Read_Keyboard())
{
if(ge_input.Is_Key_Pressed(DIK_ESCAPE))
PostQuitMessage(0);

// if it is time to render again
if(ge_timer.Get_Game_Play_Time() > last_render_time + 30)
{
// rotate camera
x_file.Rotate(ROTATE_ANGLE);

// reset camera
x_file.Set_Camera();

x_file.Render();

// update last render time
last_render_time = ge_timer.Get_Game_Play_Time();
}
}
}
}

UnregisterClass(WINDOW_CLASS_NAME, instance);

return true;
}

运行效果:


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 07:02

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表