本系列文章由 net_assassin 整理编写,转载请注明出处。
http://blog.youkuaiyun.com/net_assassin/article/category/1100363
作者:net_assassin 邮箱: net_assassin@hotmail.com 期待着与志同道合的朋友们相互交流
上一章我们学习了使用原始的顶点缓冲区从头创建及渲染带有纹理的3D立方体的方法。这是很好的学习体验,但手工编写代码能做出来的网格(由顶点组成的3D对象)也就只能像立方体这样的东西。
本章要前讲:
- 运行时使用特殊的Direct3D函数(这个函数生成诸如立方体、球体和圆柱体这样的网格形状)来创建后援3D网格的方法。
- 从 .X 文件中将网格装载到内存并使用纹理来渲染它的方法。
创建及渲染后援网格
创建后援网格
- 立方体
- 球体
- 圆柱体
- 面包圈(圆环)
- 茶壶
- 创建立方体
D3DXCreateBox(d3ddev,1.0f,1.0f,1.0f,&mesh,NULL);
- 创建球体
D3DXCreateSphere(d3ddev,1.0f,20,20,&mesh,NULL);
- 创建圆柱体
D3DXCreateCylinder(d3ddev,1.0f,1.0f,2.0f,20,20,&mesh,NULL);
- 创建面包圈
D3DXCreateTorus(d3ddev,0.5f,1.0f,20,20,&mesh,NULL);
- 创建茶壶
D3DXCreateTeapot(d3ddev,&mesh,NULL);
D3DXCreateBox(d3ddev,1.0f,1.0f,1.0f,&mesh,NULL);D3DXCreateSphere(d3ddev,1.0f,20,20,&mesh,NULL);D3DXCreateCylinder(d3ddev,1.0f,1.0f,2.0f,20,20,&mesh,NULL);D3DXCreateTorus(d3ddev,0.5f,1.0f,20,20,&mesh,NULL);D3DXCreateTeapot(d3ddev,&mesh,NULL);渲染后援网格
装载并渲染模型文件
装载.X文件
- 定义新的MODEL 结构 首先,我们需要一个新的结构来处理要装载的模型文件:
struct MODEL { LPD3DXMESH mesh; D3DMATERIAL9* materials; LPDIRECT3DTEXTURE9* textures; DWORD material_count; }
- 装载网格 装载模型文件的关键在于D3DXLoadMeshFromX函数:
HRESULT WINAPI D3DXLoadMeshFromX( LPCTSTR pFilename, DWORD Options, LPDIRECT3DDEVICE9 pDevice, LPD3DXBUFFER * ppAdjacency, LPD3DXBUFFER * ppMaterials, LPD3DXBUFFER * ppEffectInstances, DWORD *pNumMaterials, LPD3DXMESH * ppMesh )
材质缓冲区用于装载材质:
LPD3DXBUFFER matbuffer;
MODEL *model = (MODEL*)malloc ( sizeof ( MODEL ));
result = D3DXLoadMeshFromX(
filename,
D3DXMESH_SYSTEMMEM,
d3ddev,
NULL,
&matbuffer,
NULL,
&model->material_count,
&model->mesh
);
3. 装载材质和纹理
材质存储于材质缓冲区中,不过,在渲染模型之前需要将他们转换成Direct3D材质和纹理。
以下是从材质缓冲区中将材质和纹理复制到各个材质和纹理数组中的方法:
首先,创建数组:
D3DXMATERIAL * d3dxMaterials = (LPD3DXMATERIAL) matbuffer->GetBufferPointer();
model->materials = new D3DMATERIAL9[model->material_count];
model->textures = new LPDIRECT3DTEXTURE9[model->material_count];
下一步,迭代材质并将它们从材质缓冲区中取出:
//create the materials and textures
for(DWORD i=0; i<model->material_count; i++)
{
//grab the material
model->materials[i] = d3dxMaterials[i].MatD3D;
//set ambient color for material
model->materials[i].Ambient = model->materials[i].Diffuse;
model->textures[i] = NULL;
if (d3dxMaterials[i].pTextureFilename != NULL)
{
string filename = d3dxMaterials[i].pTextureFilename;
if( FindFile(&filename) )
{
result = D3DXCreateTextureFromFile(d3ddev, filename.c_str(), &model->textures[i]);
if (result != D3D_OK)
{
MessageBox(NULL, "Could not find texture file", "Error", MB_OK);
return false;
}
}
}
}
在网格中遇到一个文件名时,为了定位纹理文件,需要三个函数一起工作:
FindFile
DoesFileExist
SplitPath
渲染完整的模型
//any materials in this mesh?
if (model->material_count == 0)
{
model->mesh->DrawSubset(0);
}
else {
//draw each mesh subset
for( DWORD i=0; i < model->material_count; i++ )
{
// Set the material and texture for this subset
d3ddev->SetMaterial( &model->materials[i] );
if (model->textures[i])
{
if (model->textures[i]->GetType() == D3DRTYPE_TEXTURE)
{
D3DSURFACE_DESC desc;
model->textures[i]->GetLevelDesc(0, &desc);
if (desc.Width > 0)
{
d3ddev->SetTexture( 0, model->textures[i] );
}
}
}
// Draw the mesh subset
model->mesh->DrawSubset( i );
}
}
从内存中删除一个模型
//remove materials from memory
if( model->materials != NULL )
delete[] model->materials;
//remove textures from memory
if (model->textures != NULL)
{
for( DWORD i = 0; i < model->material_count; i++)
{
if (model->textures[i] != NULL)
model->textures[i]->Release();
}
delete[] model->textures;
}
//remove mesh from memory
if (model->mesh != NULL)
model->mesh->Release();
//remove model struct from memory
if (model != NULL)
free(model);

本文介绍如何使用Direct3D动态创建并渲染包括立方体、球体、圆柱体等在内的多种3D模型,以及如何从.X文件中加载模型。详细解释了创建后援模型的方法、渲染过程、装载模型文件的步骤,并提供了可重用的函数实例。
3164





