2006年6月13日

Meshes Part I

我们调用D3DXCreate*函数已经使用ID3DXMesh工作了;在这章我们将更多的了解这个接口的细节。这章是主要的测试数据和方法和ID3DXMesh接口关联。

注意到ID3DXMesh接口继承自它的父类, ID3DXBaseMesh.重要的是知道因为其他Mesh接口像ID3DXPMesh(渐近Mesh也是继承自ID3DXBaseMesh).因此话题主要在这章也相关的其他类型的Mesh.

目标

学习ID3DXMesh对象的内在的数据组织形式

学习怎样创建一个ID3DXMesh接口

学习资源组织一个ID3DXMesh

学习怎样渲染一个ID3DXMesh

几何信息

ID3DXBaseMesh接口包含顶点缓冲存储Mesh和索引缓冲的定义怎样将三角形整合到一起。我们可以获取这些缓冲的指针:

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

这里有个例子告诉怎样使用:

IDirect3DVertexBuffer9* vb = 0;
Mesh->GetVertexBuffer(&vb);
IDirect3DIndexBuffer9* ib = 0;
Mesh->GetIndexBuffer(&ib);

注意:你的信息,ID3DXMesh接口支持原始类型的三角形带信息。

作为选择,如果我们想所顶缓冲区读或写,我们可以使用下面一对方法。注意这些方法将锁定整个顶点/索引区。

HRESULT ID3DXMesh::LockVertexBuffer(DWORD Flags,BYTE** ppData);
HRESULT ID3dXMesh::LockIndexBuffer(DWORD Flags,BYTE** ppData);

Flags参数描述怎样锁定完成。 锁定Flags的解释在第三章最初步介绍缓冲区。ppData参数是锁定函数返回的指针。

当完成锁定后要记得调用相应的解锁:

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

下面最后附加的方法使用获得几何关联的信息:

DWORD GetFVF(); - 返回DWORD描述的顶点

DWORD GetNumVertices(); - 返回顶点缓冲的数量

DWORD GetNumBytesPerVertex(); - 返回每个顶点的数量

DWORD GetNumFaces(); - 返回Mesh中三角形面的数目。

10.2 Subsets和属性缓冲

一个Mesh可以存储一个或多个自集。一个自己是在Mesh中可以被渲染使用相同属性的一个组。属性我们意味着材质,纹理,和渲染状态。图10.1说明怎样描绘也许决定许多子集。

我们为每个子集给一个实际的整数标识一个子集。这个值可以被许多值可以存储一个DWORD.例如,图10.1我们标签为0,1,2,3.

每个三角形在mesh是一个在三角形活动的属性ID.例如 图10.1三角形包装了地面房屋将有一个指出它们自己的子集的ID subset 0.同样的三角形组织墙在房屋有一个属性ID等于1指出subset 1.

属性IDs存储在mesh's属性缓冲,有DWORD数组。从每个面有整个在属性缓冲,在属性缓冲有一系列元素是等于Mesh中的面。整个属性缓冲和三角形定义通过索引缓冲一对一对应;换句话说,entry i在属性缓存符合使用三角形i在索引缓冲。三角型i定义下面三个索引缓冲的索引。

A = i.3

B = i.3 + 1

C = i.3 + 2

图10.2展示这个对应:

图10.2:对应在三角形和属性缓冲之间。我们看到三角形0存在于子集0中,三角形1存在于子集4中,和三角形n存在于子集2。

我们可以所定它然后访问属性缓冲,下面一个小片段以说明:

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

10.3 绘画 Drawing

ID3DXMesh接口提供了DrawSubset(DWORD AttribId)方法来绘制被AttribId参数指定的特殊的三角形集。例如,绘图所有的三角形0,我们可以写:

Mesh->DrawSubset(0);

绘制整个Mesh,我们必须绘制所有的子集的mesh.它方便的在0,1,2,...,n-1,这里n是子集数,有符合材质和纹理关系用subset i.这个允许我们渲染整个mesh使用简单的循环:

for(int i=0;i< numSubsets;i++)

{

Device->SetMaterial(mtrls[i]);

Device->SetTexture(0,textures[i]);

Mesh->DrawSubset(i);

}

10.4 优化

顶点和索引Mesh可以被组织在一起更有效率。当我们这样做时,我们说我们优化一个mesh,我们使用下面的方法:

HRESULT ID3DXMesh::OptimizeInplace(

DWORD Flags,CONST DWORD* pAdjacencyIn,DWORD* pAdjacencyOut,DWORD* pFaceRemap,LPD3XBUFFER* ppVertexRemap);

Flags - 优化标志告诉优化种类的执行。这些可以被一个或更多的下面:

D3DXMESHOPT_COMPACT---移除不常用的索引和顶点。

D3DXMESHOPT_ATTRSORT - 排序三角形的属性和产生属性表。这个允许DrawSubset更有效率(看第10.5节)

D3DXMESHOPT_VERTEXCACHE-增加顶点缓存比率

D3DXMESHOPT_STRIPREORDER-改造索引以用三角形带可以更好的

D3DXMESHOPT_IGNOREVERTS - 仅仅优化索引信息;忽略顶点

注意: D3DXMESHOPT_VERTEXCACHE和 D3DXMESHOPT_STRIPREORDER标识不可以一起用。

pAdjacencyIn - 邻接指针不优化的mesh

pAdjacencyOut - 用邻接信息优化填充在DWORD的指针。这数组必须有ID3DXMesh::GetNumFaces() * 3元素。如果你们不需要这个信息,pass 0.

pFaceRemap - 指针是DWORD数组被填充在remap信息。数组将被ID3DXMesh::GetNumFaces()获取大小。当mesh被优化时,它的面也许被一定到索引缓冲。面remap信息告诉哪里有原始的面被移动; that is, the i entry in pFAceRemap holds the face index identifying where the i original face has moved.如果你不需要这个信息,可以为0

ppVerexRemap - ID3DXBuffer地址指针(看第11.1章)将使用顶点remap信息跳虫。这个缓冲将包含ID3DXMesh::GetNumVertices()顶点。当一个Mesh被优化,它的顶点也许被移动在顶点缓冲周围。顶点remap信息告诉哪里有最初的顶点被移动;因此,i实体在 ppVertexRemap holds the vertex index identifying where the i 原始顶点信息有被移动。如果你不需要这个信息,置0.

DWORD adjacencyInfo[Mesh->GetNumFaces() * 3];

Mesh->GenerateAdjacency(0.0f,adjacencyInfo);

DWORD optimizedAdjacencyInfo[Mesh->GetNumFaces() * 3];

Mesh->OptimizeIplace(

D3DXMESHOPT_ATTRSORT |

D3DXMESHOPT_COMPACT |

D3DXMESHOPT_VERTEXCACHE,

adjacencyInfo,

optimizeAdjacencyInfo,

0,0);

类似的方法是Optimize方法,输出一个优化的版本调用Mesh对象比实际优化调用的mesh对象。

HRESULT ID3DXMesh::Optimize(

DWORD Flags,CONST DWORD* pAdjacencyIn,DWORD* pAdjacencyOut,DWORD* pFaceRemap,LPD3DXBUFFER* ppVertexRemap,LPD3DXMESH* ppOptMesh);

10.5 属性表

当mesh被用D3DXMESHOPT_ATTRSORT标识优化时,几何在mesh是被短的属性所以几何特殊的子集存在邻近的块在顶点/索引缓冲(看图10.3).

图10.3:注意几何和属性缓冲信息排序被属性用几何的特殊子集邻近的。我们现在可以容易的标识哪里是自集的开始或结束。注意每个"Tri"块在顶点缓冲区描述三个索引。

附加的排序几何,D3DXMESHOPT_ATTRSORT优化构造一个属性表。属性表是一D3DXATTRIBUTERANGE结构。每个实体在属性表符合通信做子集的mesh和指定内存里的顶点/索引缓冲块,哪里几何提供子集reside.这个D3DXATTRIBUTERANGE结构被定义为:

typedef struct D3DXATTRIBUTERANGE{

DWORD AttribId;

DWORD FaceStart;

DWORD FaceCount;

DWORD VertexStart;

DWORD VertexCount;

}D3DXATTRIBUTERANGE;

AttribId - 子集ID

FaceStart - 偏离索引缓冲(FaceStart * 3)标识开始的三角型是联合使用子集

FaceCount - 这个数的面(三角形)爱这个子集

VertexStart - 一个偏离在顶点缓冲标识在顶点的联系的开始。

VertexCount - 子集数量

我们可以容易看D3DXATTRIBUTERANGE结构工作的图形效果。属性表为每个图10.3将有三个实体-一个符合用每个子集。

用属性表构造,渲染一个完成每个子集有效率的,仅仅快速的查找在属性表是找到所有的几何的特殊的子集。注意没有一个属性表,渲染子集请求线性查找整个属性缓冲找到几何存在的子集我们绘图。

访问mesh的属性表,我们使用下面的方法:

HRESULT ID3DXMesh::GetAttributeTable(D3DXATTRIBUTERANGE* pAttribTable,DWORD* pAttribTableSize);

这个方法可以做两个东西:它可以返回在属性表或者填充D3DXATTRIBUTERANGE结构使用属性数据的数组。

在属性表中获取数据元素,我们设置第一个参数为0:

DWORD numSubsets = 0;

Mesh->GetAtrributeTable(0,&numSubsets);

一个我们知道元素数,我们可以填充一个D3DXATTRIBUTERANGE数组用实际属性表写为:

D3DXATTRIBUTERANGE table = new D3DXATTRIBUTERANGE[numSubsets];

Mesh->GetAttributeTable(table,&nmSubsets);

我们可以直接设置属性表使用ID3DXMesh::SetAttributeTable方法。下面例子设置一个属性表用12子集:

D3DXATTRIBUTERANGE attributeTable[12];

Mesh->SetAttributeTable(attributeTable,12);

10.6 邻接信息

为了主要的Mesh操作,像优化,它必要的知道三角形是邻接的三角形。一个mesh的邻接数组存储这些信息。‘

邻接数组是DWORD数组,每个整个包含一个索引标识在mesh中的三角形。例如,一个实体 i 提供三角形被索引。

A = i.3

B = i.3 + 1

C = i.3 + 2

注意一饿实体ULONG_MAX = 4292967295它的值日指出了特殊了edge没有一个邻接的三角形。我们也可以使用 -1来这样表示因为分配-1到一个DWORD 结果在 ULONG_MAX.看,回忆DWORD是一个unsigned 32-bit的整数。

从每个三角形三个edges,它可以有三个邻接三角形(看图10.4).

因此,邻接数组必须有(ID3DXBaseMesh::GetNumFaces() * 3)元素- 三种可能的邻接数组提供给每个mesh三角形。

许多的D3DX mesh创建函数可以输出邻接信息,但是下面方法也可以被使用:

HRESULT ID3DXMesh::GenerateAdjacency(FLOAT fEpsilon,DWORD* pAdjacency);

fEpsilon - 一个希腊字母指定当两个指针关闭足够的距离它们将被视为同样的。例如,如果距离在两个距离之间少于epsilon,我们视为他们同样的。

pAdjacency - 指针是一个DWORDs他饿被填充用邻接信息。

例如:

DWORD adjacencyInfo[Mesh->GetNumFaces() * 3];

Mesh->GenerateAdjacency(0.001f,adacencyInfo);

10.7 Cloning - 复制

有一天我们需要从另一个mesh复制数据。这个实现使用ID3DXBaseMesh::CloneMeshFVF方法。

HRESULT ID3DXMesh::CloneMeshFVF(

DWORD Options,DWORD FVF,LPDIRECT3DDEVICE9 pDevice,

LPD3DXMESH* ppCloneMesh);

Options - 一个或更多创建标识使用创建复制mesh.看D3DXMESH枚举类型在SDK 文档提供全部的Flags选项。一些公共的flags是:

D3DXMESH_32BIT - mesh将使用32bit的浮点。

D3DXMESH_MANAGED - mesh将在内存池放管理。

D3DXMESH_WRITEONLY - mesh的数据将仅仅是写和不读去

D3DXMESH_DYNAMIC - mesh的缓冲将被动态的创建。

FVF - 灵活顶点格式使用创建复制的mesh

pDevice - 设备使用复制mesh的设备

ppCloneMesh - 输出复制的mesh

注意这个方法允许创建选项和目的mesh的灵活顶点格式从这些源mesh.例如,假设我们mesh有灵活顶点格式D3DFVF_XYZ和我们喜欢创建复制使用灵活顶点格式 D3DFVF_XYZ|D3DFVF_NORMAL.我们将写:

Mesh->CloneMeshFVF(

Mesh->GetOption(),D3DFVF_XYZ|D3DFVF_NORMAL,Device,&clone);

10.8迄今我们创建mesh对象使用D3DXCreate*函数。然而我们也可以创建一个"空的" mesh使用D3DXCreateMeshFVF函数。用空mesh,我们意味我们指定我们想要的mesh可以hold;然后D3DXCreateMeshFVF分配适当的顶点大小,索引,和属性缓冲。一旦我们有mesh的缓冲分配,我们用手填充在mesh的数据内容(确切的说,我们必须写顶点,索引和顶点缓冲的属性,索引缓冲,和属性缓冲,个别的).

或者说,创建一个空的mesh我们使用D3DXCreateMeshFVF函数

HRESULT D3DXCreateMeshFVF(DWORD NumFaces,DWORD NumVertices,DWORD Options,DWORD FVF,

LPDIRECT3DDEVICE9 pDevice,LPD3DXMESH* ppMesh);

NumFaces - 一定数量的面的mesh将有。这个必须大于0.

NumVertices - mesh的顶点数将有; 。这个必须大于0。

Options - 一个或者更多的创造标志将使用创建mesh.看D3DXMESH在SDK文档将枚举全部类型完整的。一些公共的选项是:

D3DXMESH_32BIT - mesh将使用32位的索引。

D3DXMESH_MANAGED - mesh将使用内存池管理

D3DXMESH_WRITEONLY - mesh的数据将仅仅被写不可以读

D3DXMESH_DYNAMIC - mesh的缓冲将通过动态创建。

FVF - 灵活顶点格式存储在mesh中。

pDevice - 和mesh关联的设备

ppMesh - 输出创建的mesh

例子创建, 在下一章节回顾,具体的例子怎样手工填充mesh的数据内容使用创建mesh的函数。

作为选择,你可以使用D3DXCreateMesh函数创建空的mesh.它的原型是:

HRESULT D3DXCreateMesh(

DWORD NumFaces,

DWORD NumVertices,

DWORD Options,

CONST LPD3DVERTEXELEMENT9* pDeclaration,

LPDIRECT3DDEVICE9 pDevice,

LPD3DXMESH* ppMesh);

这个参数是类似D3DXCreateMeshFVF,认为四个。取代指定的FVF;我们指定一个D3DVERTEXELEMENT9元素结构描述顶点格式。例如,我们许可它只读研究D3DVERTEXELEMENT9结构,下面关联的函数价值提及:

HRESULT D3DXDeclaratorFromFVF(DWORD FVF,D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE]);

注意: D3DVEREXELEMENT9是在第17章讨论。

这个函数输出D3DVERTEXELEMENT9结构是FVF作为输入。注意MAX_FVF_DECL_SIZE作为定义:

typedef enum{

MAX_FVF_DECL_SIZE = 18;

}MAX_FVF_DECL_SIZE;

10.9 例子应用:创建和渲染一个mesh

例子应用程序渲染一个mesh的盒子(看图10.5).

它示范了我们这章讨论的大部分功能,包括下面的操作:

创建以后个空的mesh

用立方几何填充一个mesh

在每个存在的mesh指定子集

产生邻接的mesh信息

优化mesh

绘制mesh

注意我们省略了不相关的代码例子中讨论的。你可以同样的文件中找到代码。这个例子叫做D3DXCreateMeshFVF.

另外,为了容易的调试和研究mesh的组成,我们实现下面函数堆在它的内在的内容到文件:

void dumpVertices(std::ofstream& outFile,ID3DXMesh* mesh);
void dumpVertices(std::ofstream& outFile,ID3DXMesh* mesh);
void dumpAttributeBuffer(std::ofstream& outFile,ID3DXMesh* mesh);
void dumpAttributeBuffer(std::ofstream& outFile,ID3DXMesh* mesh);
void dumpAttributeTable(std::ofstream& outFile,ID3DXMesh* mesh);

这些函数的命名描述了它们的功能。自从这些直接的实现,我们忽略了这里讨论他们(在共同的文件中讨论它们的代码)。然而,我们将在这章节后展示一个dumpAttributeTable的例子。

开始我们的回顾例子,我们下面示范例全局变量:

ID3DXMesh* Mesh = 0;
const DWORD NumSubsets = 3;
IDirect3DTexture9* Textures[3] = {0,0,0};
std::ofstream OutFile;

这里我们展示了我们之后创建的指针。我们也将定义一系列的mesh-三个。在这个例子里,每个子集被使用不同的纹理渲染;数组Textures包含每个子集的纹理,像i index在被i mesh的subset索引分配。最后,变量的OutFile是被使用mesh输出文件内容。我们通过dump*函数审查这个对象。

大半的例子处理工作在Setup函数。我们最初创建一个空的mesh:

bool Setup()
{
HRESULT hr = 0;
hr = D3DXCreateMeshFVF(12,24,D3DXMESH_MANAGED,Vertex::FVF,Device,&Mesh);

这里我们使用12个面和24个顶点分配了mesh,总计需要描述一个box.

在这点上,mesh是空的,所以我们写顶点和索引来描述一个盒子的顶点缓冲和索引缓冲分

锁定顶点/索引缓冲和手工写很容易的完成:

Vertex* v = 0;

Mesh->LockVertexBuffer(0,(void**)&v);

一旦mesh的几何已经写好,我们必须不要忘记指定在哪个存在三角形上的子集。回忆在属于mesh的每个三角形存储在属性缓冲区。在这个例子,我们指定最初我们在索引缓冲定义的存在的0,在下四饿三角形存在子集的1,而且在最后四个三角形(12总共)存在在子集2里。我们在下面的代码里明确:

DWORD* attributeBuffer = 0;

Mesh->LockAttributeBuffer(0,&attributeBuffer);

for(int a = 0;a<4;a++)

attributeBuffer[a] = 0;

for(int b = 4;b<8;b++)

attributeBuffer[b] = 1;

for(int c = 8;c<12;c++)

attributeBuffer[c] = 2;

Mesh->UnlockAttributeBuffer();

现在我们有创建包含有效数据的mesh.我们将在这点渲染,但是让我们先优化它。注意琐细的mesh盒子,没有真的增加优化的数据,但是虽然如此我们获取使用ID3DXMesh接口方法的练习。为了优化mesh,我们首先需要计算mesh的邻接信息:

std::vector<DWORD> adjacencyBuffer(Mesh->GetNumFaces() * 3);
Mesh->GenerateAdjacency(0.0f,&adjacencyBuffer[0]);

然后我们可以像这样的优化:

hr = Mesh->OptimizeInplace(

D3DXMESHOPT_ATTRSORT |D3DXMESHOPT_COMPACT|D3DXMESHOPT_VERTEXCACHE,&adjacencyBuffer[0],0,0,0);

在这点,设置mesh来完成和我们读去渲染它。但是有一个最后锁定代码在Setup函数有相应的。它使用先前的dump*函数输出mesh文件内在的内容。可以检测在数据mesh帮助调试和学习mesh的结构。

OutFile.open("Mesh Dump.txt");
dumpVertices(OutFile,Mesh);
dumpIndices(OutFile,Mesh);
dumpAttributeTable(OutFile,Mesh);
dumpAttributeBuffer(OutFile,Mesh);
dumpAdjacencyBuffer(OufFile,Mesh);
OutFile.close();
return true;

例如,dumpAttributeTable函数写在属性表到文件。它这样实现:

void dumpAttributeTable(std::ofstram& outFile,ID3DXMesh* mesh)

{

outFile << "Attribute Table:"<<std::endl;

outFile << "------------------"<<std::endl<<std::endl;

DWORD numEntries = 0;

mesh->GetAttributeTable(0,&numEntries);

std::vector<D3DXATTRIBUTERANGE> table(nmEntries);

mesh->GetAttributeTable(&table[0],&numEntries);

for(int i=0;i<numEntries;i++){

outFile << "Entry " << i <<std::end;

outFile << "-------" << std::endl;

outFile <<"Subset ID: "<<talbe[i].AttribId <<std::endl;

outFile <<"Face Start: "<< table[i].FaceStart <<std::endl;

outFile <<"Face Count: "<<table[i].FaceCount<<std::endl;

outFile <<"Vertex Start: "<<table[i].VertgexStart<<std::endl;

outFile <<"Vertex Count:" <<table[i].VertexCount<<std::endl;

outFile<<std::endl;

outFile<<std::endl<<std::endl;

}

下面文本来自于Mesh Dump.txt文件的例子应用程序和符合数据写在dumpAttributeTable.

我们可以看到这里匹配的数据在我们指定的mesh-三个子集使用每个子集四个三角形。我们建议你检查这个例子文件的全部输出。它可以发现在同样文件的文件夹里。

最后,我们可以容易的使用下面的代码渲染一个mesh;实质上我们正确的循环通过每个子集,设置交叉的纹理,然后绘制子集。在目的0,1,2, n-1我们指定子集,哪里是子集数。

bool Display(float timeDelta)

{

if(Device)

{

Device->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x00000000,1.0f,0);

Device->BeginScene();

for(int i=0;i<NumSubsets;i++){

Device->SetTexture(0,Textures[i]);

Mesh->DrawSubset(i);

}

Device->EndScene();

Device->Present(0,0,0,0);

}

return true;

}

10.10 摘要

一个mesh包含顶点,索引和属性缓冲。顶点缓冲和索引缓冲把握整个mesh的几何顶点(顶点和三角形).属性缓冲在每个三角形中包含符合的实体和指定属于哪个三角形。

mesh可以使用OptimizeInpalce或Optimize方法优化。优化改造mesh更有效率的mesh几何。D3DXMESHOPT_ATTRSORT产生一个属性表。属性表可以允许mesh在整个子集使用简单的查找属性表的方法来渲染整个子集。

mesh的邻接信息是DWORD 数组包含在mesh三角形里三个实体。三个实体符合三角形指定三角形的邻接三角形。

肩窝们可以创建一个空的mesh使用D3DXCreateMeshFVF函数。我们可以使用适当的锁定方法(LockVerexBuffer,LockIndexBuffer,和LockAttributteBuffer)。

第11章

Mesh II

在这章我们继续我们学习mesh关联的接口,结构,和D3DX库提供的函数。章的最后在此基础上构造,我们可以引进更多有趣的技术,像加载渲染复杂3D模型存储在磁盘上的和控制我们模型的细节的渐近模型接口。

目标

学习加载XFile使用ID3DXMesh对象

增加使用渐近模型的理解和怎样使用渐近模型 - ID3DXPMesh

学习关于跳跃范围,为什么它们有用,和怎样使用D3DX函数创建它们。

11.1 ID3dXBuffer

一个小的引用在章后,但是不详细描述它。我们看这个接口的想法我们利用D3DX库,因此接口调用的概述。ID3DXBuffer接口是一个普通的数据结构使用D3DX存储数据在内存中接近的块。它仅仅有两个方法:

LPVOID GetBufferPoint(); - 返回开始数据的指针

DWORD GetBufferSize(); - 在字节上返回缓冲的大小

维持一般类的结构,它使用空指针。这意味着它可以我们了解到数据被存储的实现。例如,D3DXLoadMeshFromX使用一个ID3DXBuffer返回mesh临近的信息。自从临近信息是存储在DWORD数组里,当我们希望使用邻近信息从缓冲里我们转化为DWORD.

例如:

DWORD* info = (DWORD*)adjacencyInfo->GetBufferPointer();
D3DXMATERIAL* mtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPoint();

自从一个ID3DXBuffer是一个COM对象,它必须当你使用消除内存泄露:

adjacencyInfo->Release();

mtrlBuffer->Release();

我们可以创建一空的ID3DXBuffer使用下面的函数:

HRESULT D3DXCreateBuffer(DWORD NumBytes,LPD3DXBUFFER *ppBuffer);

下面的创建可以四个整数

ID3DXBuffer* buffer = 0;

D3DXCreateBufffer(4 * sizeof(int),&buffer);

11.2 XFiles

迄今,我们有工作使用简单的几何对象,像球,圆桶,立方体等,使用D3DXCreate*函数。如果你有努力构造自己的手工指定顶点,你有,毫无疑问,发现非常单调乏味。减轻无聊的构造3D对象模型任务,叫做3D建模软件已经被开发。这些建模软用户构造复杂和真实mesh在可视化和交互的环境,制造完成的模型非常容易。例如流行的开发游戏的3DS Max LightWave3D和Maya

这些建模工具,当然,可以导出创建mesh数据(几何,材质,动画和其他可能有用的数据)为文件。因此,我们可以写文件读取选去mesh数据和使用它在我们的3D应用程序。这个可确认可行的方案。然而,甚至更多方便的解决方案存在。有特殊的mesh文件格式叫做XFile格式(使用.x扩展名).许多3D建模工具可以从存在的导出为.x.现在, XFiles很方便的被DirectX定义的格式,因此D3DX库读取支持XFiles.讲究是说,D3DX库提供了函数读取和加载XFiles.因此,我们避免使用写我们自己的加载/保存如我们用这个格式。

注意:你可以下载DirectX 9 SDK Extra - Direct3D Tools包从MSDN 已经有.x导出插件给流行的3D建模工具,LightWave和Maya.

11.2.1 加载一个X文件

我们使用下面的函数加载mesh数据存储XFile.注意这个方法创建一个ID3DXMesh对象和加载几何数据到XFile。

XFile材质

焦点在第七个D3DXLoadMeshFromX返回数据材质mesh 包含的,和第五饿参数D3DXMATERIAL机构包含材质数据。 D3DXMATERIAL结构被下面的定义:

typedef struct D3DXMETERIAL{
D3DMATERIAL9 MatD3D;
LPSTR pTextureFilename; 
}D3DXMATERIAL;

它是个简单的结构;它包含基本的D3DMATERIAL9结构和指针为空的结束字符指定的结合纹理名字。一个XFile不嵌入纹理数据;而是一个是引用图片的文件名包含实际纹理数据。因此,之后我们加载一个XFile使用D3DXLoadMeshFromX,我们必须加载文理的纹理文件名字。我们展示怎样在下一章做。

它浪费D3DXLoadMeshFromX函数加载XFile数据因此i实体返回D3DXMATERIAL相应数组i子集。因此,子集为0,1,2,...,n-1,。这允许mesh被简单的循环的反复的每个子集渲染。

11.2.3简单的应用: XFile