DirectX游戏编程入门——第二一部分(游戏编程工具箱) ——渲染3D模型文件
本系列文章由 net_assassin 整理编写,转载请注明出处。
http://blog.csdn.net/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);