以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  网格模型高级技术(1)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=70511)


--  作者:卷积内核
--  发布时间:12/15/2008 3:25:00 PM

--  网格模型高级技术(1)
在三维图形程序设计中,网格模型占有非常重要的地位,而且也是比较复杂的部分,特别是包含动画和蒙皮信息的网格模型。

.x文件格式分析

.x文件格式最初是为传统的Direct3D保留模式而设计的,在DirectX 6.0问世后,针对立即模式对它作过一次扩展。要想在Direct3D程序中灵活自如地使用网格模型,应当深入理解.x文件格式。

.x文件是由模板(template)驱动的,模板定义了如何存储一个数据对象,这样用户便可以自己定义具体的格式。Direct3D预定义了许多模板,这些预定义的模板位于rmxftmpl.h中,模板标识符都在rmxfguid.h中,通用文件DXUTMesh.cpp包含了这两个头文件。模板所允许的数据类型称为可选成员(optional member),这些可选成员作为数据对象的子对象来保存,子对象可以是另一种数据类型或对先前数据对象的引用,或是一个二进制对象。

来看一个.x文件(cube_1.x)的完整内容:

xof 0302txt 0064
Header { 1; 0; 1;}
Mesh Cube {   //网格 8;                                //8个顶点,以下为8个顶点的坐标 1.000000;1.000000;-1.000000;,  -1.000000;1.000000;-1.000000;, -1.000000;1.000000;1.000000;,  1.000000;1.000000;1.000000;, 1.000000;-1.000000;-1.000000;, -1.000000;-1.000000;-1.000000;, -1.000000;-1.000000;1.000000;, 1.000000;-1.000000;1.000000;;
 12;            // 12个面, 以下为每个面三个顶点的索引 3;0,1,2;, 3;0,2,3;, 3;0,4,5;, 3;0,5,1;, 3;1,5,6;, 3;1,6,2;, 3;2,6,7;, 3;2,7,3;, 3;3,7,4;, 3;3,4,0;, 3;4,7,6;, 3;4,6,5;;}
该模型的效果图如下:

按此在新窗口浏览图片

第一行文件头中的 "xof"告诉程序,它加载的文件是一个.x文件,"0302"表示它使用的是DirectX 3.2 版本的模板,"txt"表示这些数据是以文本形式存储的,"0064"定义了浮点数的位数是64位。

文件头后面的一个数据块涉及了模板和数据对象等内容。一个模板和一个数据对象之间的差异在于所有的模板都是以一个template单词开始,模板看起来很像一个C语言的结构定义,数据对象就是那些模板的实例。使用模板定义包含在.x文件里的数据对象(一个模板定义了数据对象的布局),每个模板都可以通过一个数据类型的集合去定义并容纳任何类型的数据。同时,任何数据类型的组合都可以在一个模板里使用。

模板header的定义如下:

template Header { <3D82AB43-62DA-11cf-AB39-0020AF71E433> WORD major; WORD minor; DWORD flags;}
各成员分别表示.x文件最大版本,最小版本,以及定义方式。

.x文件中涉及模板的概念,它由四部分组成:第一部分是模板的名字,可是由数字、字符、下划线构成,但不能以数字开头,第二部分是GUID(Global Unique Identifier,全局唯一标识符),第三部分由各个数据项构成,最后一部分用于控制模板的限制程度,一个模板可以是开放的、闭合的或受限的。开放模板的定义在结束部位有一个待展开的方括号[...]表示它可以包含其他数据类型,封闭模板不能包含其他任何数据类型,受限模板只能包含特定的数据类型。模板的使用与结构体有相似之处。

一般情况下,.x文件都至少包含一个Mesh模板,其定义如下:

Defines a simple mesh. The first array is a list of vertices, and the second array defines the faces of the mesh by indexing into the vertex array.

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

nVertices - Number of vertices.
array Vector vertices[nVertices] - Array of vertices, each of type Vector.
nFaces - Number of faces.
array MeshFace faces[nFaces] - Array of faces, each of type MeshFace.
[ ... ] - Any .x file template can be used here. This makes the architecture extensible. Material and TextureFilename templates are typically used.
Mesh模板是一个开放的模板,同时它还用到了Vector模板和MeshFace模板,它们的定义如下:

Defines a vector.

template Vector {     < 3D82AB5E-62DA-11cf-AB39-0020AF71E433 >     float x;     float y;     float z; }
Used by the Mesh template to define a mesh's faces. Each element of the nFaceVertexIndices array references a mesh vertex used to build the face.

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

nFaceVertexIndices - Number of indices.
array DWORD faceVertexIndices[nFaceVertexIndices] - Array of indices.
因为没有为网格模型设置材质和纹理等信息,所以该文件显示效果是一个黑色立方体,接下来将为该立方体添加材质、法线和纹理信息。


--  作者:卷积内核
--  发布时间:12/15/2008 3:26:00 PM

--  
我们在cube_1.x的基础上添加材质、法线和纹理,构成cube_2.x:

xof 0302txt 0064
Header { 1; 0; 1;}
Material RedMaterial {                    //第一块材料 1.000000;0.000000;0.000000;1.000000;;     // R = 1.0, G = 0.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename  {   "Tex1.jpg";  //纹理文件名 }           }
Material GreenMaterial {                  //第二块材料 0.000000;1.000000;0.000000;1.000000;;     // R = 0.0, G = 1.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename  {   "Tex2.jpg";  //纹理文件名 }           }
Mesh Cube {   //网格 8;                                //8个顶点,以下为8个顶点的坐标 1.000000;1.000000;-1.000000;,  -1.000000;1.000000;-1.000000;, -1.000000;1.000000;1.000000;,  1.000000;1.000000;1.000000;, 1.000000;-1.000000;-1.000000;, -1.000000;-1.000000;-1.000000;, -1.000000;-1.000000;1.000000;, 1.000000;-1.000000;1.000000;;
 12;            // 12个面, 以下为每个面三个顶点的索引 3;0,1,2;, 3;0,2,3;, 3;0,4,5;, 3;0,5,1;, 3;1,5,6;, 3;1,6,2;, 3;2,6,7;, 3;2,7,3;, 3;3,7,4;, 3;3,4,0;, 3;4,7,6;, 3;4,6,5;;
 //网格材质列表 MeshMaterialList {  2;                    //使用材质的数量:2块材质  12;                   //为12个面指定材质  0,                    //为前6个面使用第一块材质  0,  0,  0,  0,  0,  1,                    //为后面的6个面使用第二块材质  1,  1,  1,  1,  1;;  
  {RedMaterial}       //第一块材质,引用前面定义的RedMaterial材质  {GreenMaterial}     //第二块材质,引用前面定义的GreenMaterial材质 }
 //顶点法线 MeshNormals {  8;                    //定义8个法线向量  0.333333;0.666667;-0.666667;,  -0.816497;0.408248;-0.408248;,  -0.333333;0.666667;0.666667;,  0.816497;0.408248;0.408248;,  0.666667;-0.666667;-0.333333;,  -0.408248;-0.408248;-0.816497;,  -0.666667;-0.666667;0.333333;,  0.408248;-0.408248;0.816497;;  
  12;                   //为12个面的每个顶点指定法线  3;0,1,2;,  3;0,2,3;,  3;0,4,5;,  3;0,5,1;,  3;1,5,6;,  3;1,6,2;,  3;2,6,7;,  3;2,7,3;,  3;3,7,4;,  3;3,4,0;,  3;4,7,6;,  3;4,6,5;; }
 //纹理坐标 MeshTextureCoords {  8;                        //定义8对纹理坐标  0.000000;1.000000;  1.000000;1.000000;  0.000000;1.000000;  1.000000;1.000000;  0.000000;0.000000;  1.000000;0.000000;  0.000000;0.000000;  1.000000;0.000000;; }}

效果图如下:

按此在新窗口浏览图片

可以看到在Mesh模板中嵌套着一个子模板MeshMaterialList,它是Mesh模板的一部分,用来将每个面与材质相关联,其定义如下:

Used in a mesh object to specify which material applies to which faces. The nMaterials member specifies how many materials are present, and materials specify which material to apply.

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

nMaterials - A DWORD. The number of materials.
nFaceIndexes - A DWORD. The number of indices.
faceIndexes[nFaceIndexes] - An arrray of DWORDs containing the face indices.
MeshMaterialList是一个受限的模板,它只能包含Material模板,其定义如下:

Defines a basic material color that can be applied to either a complete mesh or a mesh's individual faces. The power is the specular exponent of the material.

Note     The ambient color requires an alpha component.

TextureFilename is an optional data object. If this object is not present, the face is untextured.

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

faceColor - Face color. A ColorRGBA template.
power - Material specular color exponent.
specularColor - Material specular color. A ColorRGB template.
emissiveColor - Material emissive color. A ColorRGB template.

Defines a color object with an alpha component. This is used for the face color in the material template definition.

template ColorRGBA{    < 35FF44E0-6C7C-11cf-8F52-0040333594A3 >    float red;    float green;    float blue;    float alpha;}
Defines the basic RGB color object.

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

在cube_2.x中,首先定义了两个材质RedMaterial和GreenMaterial:

Material RedMaterial {                    //第一块材料 1.000000;0.000000;0.000000;1.000000;;     // R = 1.0, G = 0.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename  {   "Tex1.jpg";  //纹理文件名 }           }
Material GreenMaterial {                  //第二块材料 0.000000;1.000000;0.000000;1.000000;;     // R = 0.0, G = 1.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename  {   "Tex2.jpg";  //纹理文件名 }           }
在模板MeshMaterialList中则给出了各个面与材质的关联信息:

//网格材质列表MeshMaterialList { 2;                    //使用材质的数量:2块材质 12;                   //为12个面指定材质 0,                    //为前6个面使用第一块材质 0, 0, 0, 0, 0, 1,                    //为后面的6个面使用第二块材质 1, 1, 1, 1, 1;; 
 {RedMaterial}       //第一块材质,引用前面定义的RedMaterial材质 {GreenMaterial}     //第二块材质,引用前面定义的GreenMaterial材质}
其中,{RedMaterial}和{GreenMaterial}是对上面定义的材质模板对象的引用。

在光照模型运算时需要用到法向量,法向量分为面法向量和顶点法向量。在基于逐顶点计算的光照模型中,需要使用顶点法向量。通常顶点法向量的计算过程是:先将共享该顶点的几个面的面法向量相加并除以共享该顶点的面的个数,接着归一化这个结果。模板MeshNormals用来指定法向量:

Defines normals for a mesh. The first array of vectors is the normal vectors themselves, and the second array is an array of indexes specifying which normals should be applied to a given face. The value of the nFaceNormals member should be equal to the number of faces in a mesh.

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

nNormals - Number of normals.
array Vector normals[nNormals] - Array of normals.
nFaceNormals - Number of face normals.
array MeshFace faceNormals[nFaceNormals] - Array of mesh face normals.
在文件cube_2.x中,法向量的定义以及为面指定法向量的内容如下:

//顶点法线MeshNormals { 8;                    //定义8个法线向量 0.333333;0.666667;-0.666667;, -0.816497;0.408248;-0.408248;, -0.333333;0.666667;0.666667;, 0.816497;0.408248;0.408248;, 0.666667;-0.666667;-0.333333;, -0.408248;-0.408248;-0.816497;, -0.666667;-0.666667;0.333333;, 0.408248;-0.408248;0.816497;; 
 12;                   //为12个面的每个顶点指定法线 3;0,1,2;, 3;0,2,3;, 3;0,4,5;, 3;0,5,1;, 3;1,5,6;, 3;1,6,2;, 3;2,6,7;, 3;2,7,3;, 3;3,7,4;, 3;3,4,0;, 3;4,7,6;, 3;4,6,5;;}
模板TextureFilename用于引用纹理,它通常作为Material模板对象的子对象出现,其定义如下:

Enables you to specify the file name of a texture to apply to a mesh or a face. This template should appear within a material object.

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

在使用TextureFilename模板时,只需要使用字符串filename指定一个纹理文件名即可,但要将这幅纹理映射到网格模型中,还需要指定纹理坐标:

Defines a mesh's texture coordinates.

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

nTextureCoords - Number of texture coordinates.
array Coords2d textureCoords[nTextureCoords] - Array of 2D texture coordinates.
Defines a two dimensional vector used to define a mesh's (u, v) texture coordinates.

template Coords2d{    < F6F23F44-7686-11cf-8F52-0040333594A3 >    float u;    float v;}
u - u coordinate value.
v - v coordinate value.
在cube_2.x中,定义纹理坐标的代码如下:

//纹理坐标MeshTextureCoords { 8;                        //定义8对纹理坐标 0.000000;1.000000; 1.000000;1.000000; 0.000000;1.000000; 1.000000;1.000000; 0.000000;0.000000; 1.000000;0.000000; 0.000000;0.000000; 1.000000;0.000000;;}


--  作者:卷积内核
--  发布时间:12/15/2008 3:27:00 PM

--  
通过前面的介绍,可以建立起一个网格模型,但这个网格模型是浑然一体的,而在现实生活中,为了能独立对一个物体的不同部分进行变换,必须将模型分割成不同的模块,在.x文件中使用框架(frame)对一个网格模型的不同部分进行组织和管理。框架仅仅是一个外壳,在框架中通常需要包含具体的网格和一个框架变换矩阵,其中框架变换矩阵用于指定该框架包含的部分在整个模型中的初始位置。

模板Frame和FrameTransformMatrix的定义如下:

Defines a coordinate frame, or "frame of reference." The Frame template is open and can contain any object. The D3DX mesh-loading functions recognize Mesh, FrameTransformMatrix, and Frame template instances as child objects when loading a Frame instance.

template Frame{    < 3D82AB46-62DA-11CF-AB39-0020AF71E433 >    [...]   }
The frame template recognizes child Frame and Mesh nodes inside a frame and can recognize user-defined templates through a callback function.

Defines a local transform for a frame (and all its child objects).

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

frameMatrix - A Matrix4x4 template.
Defines a 4 x 4 matrix. This is used as a frame transformation matrix.

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

array float matrix[16] - Array of 16 floats.
框架可以嵌套,即一个框架可以由许多子框架构成。例如为了模拟一个人的网格模型,整体可以由头部、胸部、左臂、右臂、左腿、右腿等框架组成,而左、右臂又可以由上臂、下臂和手三个框架组成,而手又可以由五指和手掌6个框架组成,甚至每个手指还可以继续细分。

我们在cube_2.x的基础上添加框架构成cube_3.x:

xof 0302txt 0064
Header { 1; 0; 1;}
Material RedMaterial {                    //第一块材料 1.000000;0.000000;0.000000;1.000000;;     // R = 1.0, G = 0.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename  {   "Tex1.jpg";  //纹理文件名 }           }
Material GreenMaterial {                  //第二块材料 0.000000;1.000000;0.000000;1.000000;;     // R = 0.0, G = 1.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; 
 TextureFilename   {   "Tex2.jpg";  //纹理文件名 }           }
Frame  CubeFrame {      //框架 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.001000, 0.001000, 0.001000, 1.000000;; } 
 Mesh Cube {   //网格  8;                                //8个顶点,以下为8个顶点的坐标  1.000000;1.000000;-1.000000;,   -1.000000;1.000000;-1.000000;,  -1.000000;1.000000;1.000000;,   1.000000;1.000000;1.000000;,  1.000000;-1.000000;-1.000000;,  -1.000000;-1.000000;-1.000000;,  -1.000000;-1.000000;1.000000;,  1.000000;-1.000000;1.000000;;
  12;            // 12个面, 以下为每个面三个顶点的索引  3;0,1,2;,  3;0,2,3;,  3;0,4,5;,  3;0,5,1;,  3;1,5,6;,  3;1,6,2;,  3;2,6,7;,  3;2,7,3;,  3;3,7,4;,  3;3,4,0;,  3;4,7,6;,  3;4,6,5;;
  //网格材质列表  MeshMaterialList {   2;                    //使用材质的数量:2块材质   12;                   //为12个面指定材质   
   0,                    //为前6个面使用第一块材质   0,   0,   0,   0,   0,   1,                    //为后面的6个面使用第二块材质   1,   1,   1,   1,   1;;   
   {RedMaterial}       //第一块材质,引用前面定义的RedMaterial材质   {GreenMaterial}     //第二块材质,引用前面定义的GreenMaterial材质  }
  //顶点法线  MeshNormals {   8;                    //定义8个法线向量   0.333333;0.666667;-0.666667;,   -0.816497;0.408248;-0.408248;,   -0.333333;0.666667;0.666667;,   0.816497;0.408248;0.408248;,   0.666667;-0.666667;-0.333333;,   -0.408248;-0.408248;-0.816497;,   -0.666667;-0.666667;0.333333;,   0.408248;-0.408248;0.816497;;   
   12;                   //为12个面的每个顶点指定法线   3;0,1,2;,   3;0,2,3;,   3;0,4,5;,   3;0,5,1;,   3;1,5,6;,   3;1,6,2;,   3;2,6,7;,   3;2,7,3;,   3;3,7,4;,   3;3,4,0;,   3;4,7,6;,   3;4,6,5;;  }
  //纹理坐标  MeshTextureCoords {   8;                        //定义8对纹理坐标   0.000000;1.000000;   1.000000;1.000000;   0.000000;1.000000;   1.000000;1.000000;   0.000000;0.000000;   1.000000;0.000000;   0.000000;0.000000;   1.000000;0.000000;;  } }}


--  作者:卷积内核
--  发布时间:12/15/2008 3:27:00 PM

--  
为了使一个.x文件产生动画,必须至少提供一个动画集,每个动画集都应具有一个对某个框架的引用。模板 AnimationSet用来定义动画集:

Contains one or more Animation objects. Each animation within an animation set has the same time at any given point. Increasing the animation set's time increases the time for all the animations it contains.

template AnimationSet{    < 3D82AB50-62DA-11cf-AB39-0020AF71E433 >    [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ]}
Where:

[ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ] - Optional animation template.
模板Animation的定义如下:

Contains one or more Animation objects. Each animation within an animation set has the same time at any given point. Increasing the animation set's time increases the time for all the animations it contains.

template AnimationSet{    < 3D82AB50-62DA-11cf-AB39-0020AF71E433 >    [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ]}
Where:

[ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ] - Optional animation template.
很显然,Animation是一个完全开放的模板,一般情况下,用模板AnimationKey来填充它,模板AnimationKey的定义如下:

Defines a set of animation keys. A matrix key is useful for sets of animation data that need to be represented as transformation matrices.

template AnimationKey{    < 10DD46A8-775B-11CF-8F52-0040333594A3 >    DWORD keyType;    DWORD nKeys;    array TimedFloatKeys keys[nKeys];}
Where:

keyType - Specifies whether the keys are rotation, scale, position, or matrix keys (using the integers 0, 1, 2, or 4, respectively).
nKeys - Number of keys.
keys - An array of keys.
在模板AnimationKey中,keyType可取的值是0、1、2、4。

0表示旋转键,在.x文件中,用一个四元数来实现模型的旋转,旋转值使用4个分量w、x、y、z来存储,也就是说,此时变换数组的大小是4,它依次存储四元数的4个分量。

1表示缩放键,可以使用这种类型的关键帧实现模型的缩放,此时变换数组的大小是3,它们分别对应x、y、z轴的缩放值。

2表示平移键,使用3个分量实现模型的平移,此时变换数组的大小是3,它们分别对应沿x、y、z轴的平移值。

4表示变换矩阵键,此时关键帧的变换数组使用16个浮点数来实现该模型的各种变换。因为矩阵可以实现模型的平移、旋转、缩放以及它们的组合变换。

模板AnimationKey用来定义一组动画关键帧,而模板TimeFloatKeys用来定义每个动画关键帧:

Defines a set of floats and a positive time used in animations.

template TimedFloatKeys {     < F406B180-7B3B-11cf-8F52-0040333594A3 >     DWORD time;     FloatKeys tfkeys; }
Where:

tfkeys - See FloatKeys.
Defines an array of floating-point numbers (floats) and the number of floats in that array. This is used for defining sets of animation keys.

template FloatKeys{    < 10DD46A9-775B-11cf-8F52-0040333594A3 >    DWORD nValues;    array float values[nValues];}
nValues - Number of floats.
values[nValues] - Array of float values.
我们在cube_3.x的基础上添加动画部分形成cube_4.x,该动画集定义了立方体绕y轴旋转,增加部分如下:

AnimationSet AnimationSet0 {  //动画集 Animation Animation0 {    //动画  {CubeFrame}           //引用上面的立方体框架,表示下面的动画是针对立方体框架的  
  AnimationKey {                //动画键   沿Y轴旋转网格   0;              // Rotation keys   10;             // 9 keys   
   1000; 4; 0.000000, 0.15643448, 0.000000, 0.98768836;;,   2000; 4; 0.000000, 0.30901700, 0.000000, 0.95105654;;,   3000; 4; 0.000000, 0.45399046, 0.000000, 0.89100653;;,   4000; 4; 0.000000, 0.58778530, 0.000000, 0.80901694;;,   5000; 4; 0.000000, 0.70710671, 0.000000, 0.70710683;;,   6000; 4; 0.000000, 0.80901694, 0.000000,  0.58778530;;,   7000; 4; 0.000000, 0.89100653,  0.000000, 0.45399052;;,   8000; 4; 0.000000, 0.95105654,  0.000000, 0.30901697;;,   9000; 4; 0.000000, 0.98768836,  0.000000, 0.15643449;;,   10000; 4; 0.000000, 1.0000000,  0.000000, 0.00000000;;;  } }}
这里一共定义了10个关键帧,在第10个关键帧时回到初始位置开始新一轮的动画。{CubeFrame}表示该动画集是对框架CubeFrame进行的操作。

我们在cube_3.x的基础上添加缩放动画形成cube_5.x:

AnimationSet AnimationSet0 {   //动画集 Animation Animation0 {     //动画 {CubeFrame}    // Use the frame containing the cube. 
  AnimationKey {                 //动画键, 放大和缩小网格   1;             // Scaling keys   9;             // 9 keys   
   1000; 3; 1.000000, 1.000000, 1.000000;;,   2000; 3; 0.800000, 0.800000, 0.800000;;,   3000; 3; 0.600000, 0.600000, 0.600000;;,   4000; 3; 0.400000, 0.400000, 0.400000;;,   5000; 3; 0.200000, 0.200000, 0.200000;;,   6000; 3; 0.400000, 0.400000, 0.400000;;,   7000; 3; 0.600000, 0.600000, 0.600000;;,   8000; 3; 0.800000, 0.800000, 0.800000;;,   9000; 3; 1.000000, 1.000000, 1.000000;;;  } }}
效果图:

按此在新窗口浏览图片

我们也可以在cube_3.x的基础上添加一个沿y轴移动的动画形成cube_6.x:

AnimationSet AnimationSet0 {   //动画集 Animation Animation0 {         //动画  {CubeFrame}    // Use the frame containing the cube.  
  AnimationKey {                 //动画键   沿Y轴方向移动网格   2;             // Position keys   19;             // 9 keys   1000; 3; 0.000000, -5.000000, 0.000000;;,   2000; 3; 0.000000, -4.000000, 0.000000;;,   3000; 3; 0.000000, -3.000000, 0.000000;;,   4000; 3; 0.000000, -2.000000, 0.000000;;,   5000; 3; 0.000000, -1.000000, 0.000000;;,   6000; 3; 0.000000, 0.000000, 0.000000;;,   7000; 3; 0.000000, 1.000000,  0.000000;;,   8000; 3; 0.000000, 2.000000,  0.000000;;,   9000; 3; 0.000000, 3.000000,  0.000000;;,   10000; 3; 0.000000, 4.000000,  0.000000;;,   11000; 3; 0.000000, 5.000000,  0.000000;;,   12000; 3; 0.000000, 4.000000,  0.000000;;,   12000; 3; 0.000000, 3.000000,  0.000000;;,   13000; 3; 0.000000, 2.000000,  0.000000;;,   14000; 3; 0.000000, 1.000000,  0.000000;;,   15000; 3; 0.000000, 0.000000,  0.000000;;,   16000; 3; 0.000000, -1.000000, 0.000000;;,   17000; 3; 0.000000, -2.000000, 0.000000;;,   18000; 3; 0.000000, -3.000000, 0.000000;;,   19000; 3; 0.000000, -4.000000, 0.000000;;,  } }}
效果图:

按此在新窗口浏览图片

包含在.x文件中的动画通常用来实现模型不同部分之间的相对运动,对于一个模型整体上的运动,应该是在程序中通过其世界变换矩阵来实现。

蒙皮信息

一个动画网格模型很多情况下可能涉及到蒙皮信息,模板XSkinMeshHeader仅对于具有蒙皮信息的网格模型有效,它用来记录网格模型的蒙皮信息,该模板的定义如下:

This template is instantiated on a per-mesh basis only in meshes that contain exported skinning information. The purpose of this template is to provide information about the nature of the skinning information that was exported.

template XSkinMeshHeader {     < 3CF169CE-FF7C-44ab-93C0-F78F62D172E2 >      WORD nMaxSkinWeightsPerVertex;     WORD nMaxSkinWeightsPerFace;     WORD nBones; }
Where:

nMaxSkinWeightsPerVertex - Maximum number of transforms that affect a vertex in the mesh.
nMaxSkinWeightsPerFace - Maximum number of unique transforms that affect the three vertices of any face.
nBones - Number of bones that affect vertices in this mesh.
在一个具有蒙皮信息的网格模型中,可能出现模板SkinWeights的n个实例,n等于该网格模型中骨骼的数量。该模板的每个实例都定义了一个具体的骨骼对于相应顶点的影响权重,该模板的具体定义如下:

This template is instantiated on a per-mesh basis. Within a mesh, a sequence of n instances of this template will appear, where n is the number of bones (X file frames) that influence the vertices in the mesh. Each instance of the template basically defines the influence of a particular bone on the mesh. There is a list of vertex indices, and a corresponding list of weights.

template SkinWeights {     < 6F0D123B-BAD2-4167-A0D0-80224F25FABB >     STRING transformNodeName;     DWORD nWeights;     array DWORD vertexIndices[nWeights];     array float weights[nWeights];     Matrix4x4 matrixOffset; }
Where:

The name of the bone whose influence is being defined is transformNodeName, and nWeights is the number of vertices affected by this bone.
The vertices influenced by this bone are contained in vertexIndices, and the weights for each of the vertices influenced by this bone are contained in weights.
The matrix matrixOffset transforms the mesh vertices to the space of the bone. When concatenated to the bone's transform, this provides the world space coordinates of the mesh as affected by the bone.

[B][URL=http://www.cppblog.com/Files/changingnow/CubeResource.rar]下载cube_1.x ~ cube6.x[/URL][/B]


--  作者:卷积内核
--  发布时间:12/15/2008 3:28:00 PM

--  
Direct3D对加载到内存中的网格模型提供了优化功能,通过网格模型优化可以明显提高三维模型的渲染速度,这对渲染速度要求较高的三维图形程序和游戏具有非常重要的现实意义。

对于程序员而言,对网格模型进行优化是比较简单的,只需调用接口ID3DXMesh的方法Optimize(),该函数的声明如下:

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.

Direct3D提供了7种网格模型优化方式,由枚举常量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.

D3DXMESH
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.

因为调用ID3DXMesh::Optimize()函数对网格模型进行优化时,需要用到网格模型中每个面的三个邻接信息,该信息在加载网格模型时得到:

ID3DXBuffer* material_buffer;
V_RETURN(D3DXLoadMeshFromXW(L"Dwarf.x", D3DXMESH_MANAGED, pd3dDevice, &g_adj_buffer, &material_buffer, NULL,       &g_num_materials, &g_mesh));
D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();g_mesh_materials = new D3DMATERIAL9[g_num_materials];g_mesh_textures  = new IDirect3DTexture9*[g_num_materials];
for(DWORD i = 0; i < g_num_materials; i++){ g_mesh_materials[i] = xmaterials[i].MatD3D; g_mesh_materials[i].Ambient = g_mesh_materials[i].Diffuse;
 WCHAR wfilename[256]; RemovePathFromFileName(xmaterials[i].pTextureFilename, wfilename);
 g_mesh_textures[i] = NULL;
 if(xmaterials[i].pTextureFilename != NULL && lstrlen(wfilename) > 0) {  V_RETURN(D3DXCreateTextureFromFileW(pd3dDevice, wfilename, &g_mesh_textures[i])); }}
material_buffer->Release();
接着我们以三种方式对原始网格模型进行了优化:

DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer();
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,     &g_mesh_attr_sort));
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,     &g_mesh_strip_reorder)); 
V_RETURN(g_mesh->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,     &g_mesh_vertex_cache));
渲染优化后的网格模型与未优化的网格模型相比没有任何区别:

// Clear the render target and the zbuffer V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );
// Render the sceneif( SUCCEEDED( pd3dDevice->BeginScene() ) ){ for(DWORD i = 0; i < g_num_materials; i++) {  pd3dDevice->SetMaterial(&g_mesh_materials[i]);  pd3dDevice->SetTexture(0, g_mesh_textures[i]);
  switch(g_render_flag)  {  case OPT_NONE:   g_mesh->DrawSubset(i);   break;
  case OPT_ATTR_SORT:   g_mesh_attr_sort->DrawSubset(i);   break;
  case OPT_STRIP_REORDER:   g_mesh_strip_reorder->DrawSubset(i);   break;
  case OPT_VERTEX_CACHE:   g_mesh_vertex_cache->DrawSubset(i);   break;  } }  
 RenderText();
 V(g_button_dlg.OnRender(fElapsedTime));
    V( pd3dDevice->EndScene() );}
运行效果图:

按此在新窗口浏览图片


--  作者:卷积内核
--  发布时间:12/15/2008 3:29:00 PM

--  
主程序:


#include "dxstdafx.h"
#include "resource.h"

#pragma warning(disable : 4127 4995)

#define IDC_TOGGLE_FULLSCREEN    1
#define IDC_TOGGLE_REF            2
#define IDC_CHANGE_DEVICE        3

#define OPT_NONE                0
#define OPT_ATTR_SORT            1
#define OPT_STRIP_REORDER        2
#define OPT_VERTEX_CACHE        3

#define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

ID3DXFont*                    g_font;
ID3DXSprite*                g_text_sprite;
bool                        g_show_help = true;

CDXUTDialogResourceManager    g_dlg_resource_manager;
CD3DSettingsDlg                g_settings_dlg;
CDXUTDialog                    g_button_dlg;

ID3DXMesh*                    g_mesh;
D3DMATERIAL9*                g_mesh_materials;
IDirect3DTexture9**            g_mesh_textures;
DWORD                        g_num_materials;
ID3DXBuffer*                g_adj_buffer;

ID3DXMesh*                    g_mesh_attr_sort;
ID3DXMesh*                    g_mesh_strip_reorder;
ID3DXMesh*                    g_mesh_vertex_cache;
WCHAR                        g_opt_info[256];
int                            g_render_flag = OPT_NONE;

//--------------------------------------------------------------------------------------
// Rejects any devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                  D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    // Typically want to skip backbuffer formats that don't support alpha blending

    IDirect3D9* pD3D = DXUTGetD3DObject();

    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                    D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;

    return true;
}


//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed.
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
{
    // If video card does not support hardware vertex processing, then uses sofaware vertex processing.
    if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
        pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    static bool is_first_time = true;

    if(is_first_time)
    {
        is_first_time = false;

        // if using reference device, then pop a warning message box.
        if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
            DXUTDisplaySwitchingToREFWarning();
    }

    return true;
}

//--------------------------------------------------------------------------------------
// Remove path from fullname, and convert filename from multibyte to wchar.
//--------------------------------------------------------------------------------------
void RemovePathFromFileName(LPSTR fullname, LPWSTR wfilename)
{
    WCHAR wbuf[MAX_PATH]  = {0};
    MultiByteToWideChar(CP_ACP, 0, fullname, -1, wbuf, MAX_PATH);

    LPWSTR w_last_back_slash = wcsrchr(wbuf, '\\');

    if(w_last_back_slash)
        lstrcpy(wfilename, ++w_last_back_slash);
    else
        lstrcpy(wfilename, wbuf);
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_MANAGED resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                 void* pUserContext )
{
    HRESULT    hr;

    V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
    V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

    D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                   DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);

    ID3DXBuffer* material_buffer;

    V_RETURN(D3DXLoadMeshFromXW(L"Dwarf.x", D3DXMESH_MANAGED, pd3dDevice, &g_adj_buffer, &material_buffer, NULL,
                                &g_num_materials, &g_mesh));

    D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();
    g_mesh_materials = new D3DMATERIAL9[g_num_materials];
    g_mesh_textures  = new IDirect3DTexture9*[g_num_materials];

    for(DWORD i = 0; i < g_num_materials; i++)
    {
        g_mesh_materials[i] = xmaterials[i].MatD3D;
        g_mesh_materials[i].Ambient = g_mesh_materials[i].Diffuse;

        WCHAR wfilename[256];
        RemovePathFromFileName(xmaterials[i].pTextureFilename, wfilename);

        g_mesh_textures[i] = NULL;

        if(xmaterials[i].pTextureFilename != NULL && lstrlen(wfilename) > 0)
        {
            V_RETURN(D3DXCreateTextureFromFileW(pd3dDevice, wfilename, &g_mesh_textures[i]));
        }
    }
    
    material_buffer->Release();

    lstrcpy(g_opt_info, L"optimize method: none");

    DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer();

    V_RETURN(g_mesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
                     &g_mesh_attr_sort));

    V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
                     &g_mesh_strip_reorder));
        
    V_RETURN(g_mesh->Optimize(D3DXMESHOPT_VERTEXCACHE | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL,
                     &g_mesh_vertex_cache));

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                void* pUserContext )
{
    HRESULT hr;

    V_RETURN(g_dlg_resource_manager.OnResetDevice());
    V_RETURN(g_settings_dlg.OnResetDevice());
    V_RETURN(g_font->OnResetDevice());
    V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

    // set dialog position and size

    g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
    g_button_dlg.SetSize(170, 170);

    // setup view matrix

    D3DXMATRIX mat_view;
    D3DXVECTOR3 eye(0.0f, 0.0f, -4.0f);
    D3DXVECTOR3  at(0.0f, 0.0f,  0.0f);
    D3DXVECTOR3  up(0.0f, 1.0f,  0.0f);

    D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up);
    pd3dDevice->SetTransform(D3DTS_VIEW, &mat_view);

    // set projection matrix
    D3DXMATRIX mat_proj;
    float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
    D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 100.0f);
    pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);

    pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xFFFFFFFF);

    return S_OK;
}

//--------------------------------------------------------------------------------------
// Release resources created in the OnResetDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnLostDevice();
    g_settings_dlg.OnLostDevice();
    g_font->OnLostDevice();

    release_com(g_text_sprite);
}


//--------------------------------------------------------------------------------------
// Release resources created in the OnCreateDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
    g_dlg_resource_manager.OnDestroyDevice();
    g_settings_dlg.OnDestroyDevice();    

    delete[] g_mesh_materials;
    g_mesh_materials = NULL;

    if(g_mesh_textures)
    {
        for(DWORD i = 0; i < g_num_materials; i++)
            release_com(g_mesh_textures[i]);

        delete[] g_mesh_textures;
        g_mesh_textures = NULL;
    }

    release_com(g_font);
    release_com(g_adj_buffer);
    release_com(g_mesh);
    release_com(g_mesh_attr_sort);
    release_com(g_mesh_strip_reorder);
    release_com(g_mesh_vertex_cache);
}

//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    D3DXMATRIX mat_world, mat_translation, mat_rotation;

    D3DXMatrixTranslation(&mat_translation, 0, -0.7f, 0);
    D3DXMatrixRotationY(&mat_rotation, timeGetTime() / 1000.0f);
    mat_world = mat_translation * mat_rotation;

    pd3dDevice->SetTransform(D3DTS_WORLD, &mat_world);
}

//--------------------------------------------------------------------------------------
// Render the helper information
//--------------------------------------------------------------------------------------
void RenderText()
{
    CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
    
    text_helper.Begin();

    // show frame and device states
    text_helper.SetInsertionPos(5, 5);
    text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
    text_helper.DrawTextLine( DXUTGetFrameStats(true) );
    text_helper.DrawTextLine( DXUTGetDeviceStats() );

    // show other simple information
    text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
    text_helper.DrawTextLine(g_opt_info);

    // show helper information
    
    const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

    if(g_show_help)
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 6);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
        text_helper.DrawTextLine(L"Controls (F1 to hide):");
        
        text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 4);
        text_helper.DrawTextLine(L"Quit: ESC");

        text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 3);
        text_helper.DrawTextLine(L"0, 1, 2, 3: switch optimize method");
    }
    else
    {
        text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
        text_helper.DrawTextLine(L"Press F1 for help");
    }

    text_helper.End();
}

//--------------------------------------------------------------------------------------
// Render the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.OnRender(fElapsedTime);
        return;
    }

    // Clear the render target and the zbuffer
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        for(DWORD i = 0; i < g_num_materials; i++)
        {
            pd3dDevice->SetMaterial(&g_mesh_materials[i]);
            pd3dDevice->SetTexture(0, g_mesh_textures[i]);

            switch(g_render_flag)
            {
            case OPT_NONE:
                g_mesh->DrawSubset(i);
                break;

            case OPT_ATTR_SORT:
                g_mesh_attr_sort->DrawSubset(i);
                break;

            case OPT_STRIP_REORDER:
                g_mesh_strip_reorder->DrawSubset(i);
                break;

            case OPT_VERTEX_CACHE:
                g_mesh_vertex_cache->DrawSubset(i);
                break;
            }
        }        

        RenderText();

        V(g_button_dlg.OnRender(fElapsedTime));

        V( pd3dDevice->EndScene() );
    }
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
    *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    if(g_settings_dlg.IsActive())
    {
        g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        return 0;
    }

    *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
    if(*pbNoFurtherProcessing)
        return 0;

    return 0;
}


//--------------------------------------------------------------------------------------
// Handle keybaord event
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
{
    if(is_key_down)
    {
        switch(charater)
        {
        case VK_F1:
            g_show_help = !g_show_help;
            break;

        case 48:    // press key "0"
            g_render_flag = OPT_NONE;
            lstrcpy(g_opt_info, L"optimize method: none");
            break;

        case 49:    // press key "1"
            g_render_flag = OPT_ATTR_SORT;
            lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_ATTRSORT");
            break;

        case 50:    // press key "2"
            g_render_flag = OPT_STRIP_REORDER;
            lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_STRIPREORDER");
            break;

        case 51:    // press key "3"
            g_render_flag = OPT_VERTEX_CACHE;
            lstrcpy(g_opt_info, L"optimize method: D3DXMESHOPT_VERTEXCACHE");
            break;
        }
    }
}

//--------------------------------------------------------------------------------------
// Handle events for controls
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
{
    switch(control_id)
    {
    case IDC_TOGGLE_FULLSCREEN:
        DXUTToggleFullScreen();
        break;

    case IDC_TOGGLE_REF:
        DXUTToggleREF();
        break;

    case IDC_CHANGE_DEVICE:
        g_settings_dlg.SetActive(true);
        break;
    }
}

//--------------------------------------------------------------------------------------
// Initialize dialogs
//--------------------------------------------------------------------------------------
void InitDialogs()
{
    g_settings_dlg.Init(&g_dlg_resource_manager);
    g_button_dlg.Init(&g_dlg_resource_manager);

    g_button_dlg.SetCallback(OnGUIEvent);

    int x = 35, y = 10, width = 125, height = 22;

    g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
    g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
    g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
}

//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // Set the callback functions
    DXUTSetCallbackDeviceCreated( OnCreateDevice );
    DXUTSetCallbackDeviceReset( OnResetDevice );
    DXUTSetCallbackDeviceLost( OnLostDevice );
    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackFrameRender( OnFrameRender );
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackKeyboard(OnKeyboardProc);
   
    // TODO: Perform any application-level initialization here
    InitDialogs();

    // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"OptimizedMesh" );
    DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

    // Start the render loop
    DXUTMainLoop();

    // TODO: Perform any application-level cleanup here

    return DXUTGetExitCode();
}

[B][URL=http://www.cppblog.com/Files/changingnow/OptimizedMesh.rar]下载示例工程[/URL][/B]


--  作者:秋十三
--  发布时间:1/2/2009 7:52:00 PM

--  
好啊
我喜欢
--  作者:秋十三
--  发布时间:2/16/2009 1:18:00 PM

--  
这么每人顶啊
--  作者:卷积内核
--  发布时间:2/18/2009 8:25:00 AM

--  
以下是引用秋十三在2009-2-16 13:18:00的发言:
这么每人顶啊


以为没人喜欢这方面知识,就没有继续发了,如果你喜欢我会继续完善这方面内容。共同学习、共同进步!!~~
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
218.750ms