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