/***********************************
*作者:蔡军生
*出处:http://blog.csdn.net/caimouse/
************************************/
*作者:蔡军生
*出处:http://blog.csdn.net/caimouse/
************************************/
加载网格模型文件
在游戏里,最常的东西是什么呢?肯定是各种怪物和场境。比如在《传奇世界》就有很多猪和青铜兽。在3D游戏里,要显示一个地图,就需要加载网格模型文件来显示。比如像《半条命》里的练习场,就是一个3D模型文件。因此,游戏要显示的东西,大多是从文件里加载模型来显示的。游戏显示的模型都是比较复杂的,比前面所用到的三角形、立方体等模型,要复杂很多。如果每个模型都是用程序来实时创建,速度也是很慢的。目前大多数模型是使用建模型软件来创建,然后保存为文件,再程序来加载显示。比较流行的建模软件有3DS MAX、Maya等,美工就可以使用它们来创建地图中的场境、怪物的模型。在开发一个游戏里,美工的人员往往占了绝大部份,几个G的游戏,图片和模型占了绝大多数空间。
X文件格式
美工做出来的模型和图片,可能是各式各样的,格式也不一致,并且分离的。这样就需要把它们转换成统一的文件格式,方便游戏引擎加载,当然这种文件格式也是作了优化的工作。比如《半条命》里的mdl文件,就是作了很多预计算,并且优化了顶点和三角形列表。对于初学者来说,越简单的文件格式,就越容易学习。因此,就采用了D3D里的X文件格式。X文件格式的功能也是非常强大的,它可以自定义各种数据结构,可以支持静态模型,也可以支持动画。X文件格式可以文本方式保存,也可以二进制方式保存。使用X文件格式特别方便,因为D3D里已经完全支持读取和输出X文件格式,同时D3D也提供给3DS MAX、Maya等插件输出X文件格式。
如果觉得X文件格式不好,当然也可以自己定义一种更好的文件格式,但就需要自己去写加载、保存、优化和导出程序。
下面就来看看怎么样加载一个X文件的模型显示,显示的效果如下:
本电子书、MM3D引擎源程序、例子源程序共49元一套
联系人:蔡军生
联系方式:
QQ: 9073204
EMAIL: caimouse1976 at sina.com
加载X文件步骤
在3D游戏里,大部份的动作,就是加载不同的模型文件。在这里先从最简单的学起,从原理性学起,再多,再复杂的东西都是一样的。在这里只是加载了一个简单的立方体,它的文件名称是Cube_txt.x。立即来看看程序是怎么样加载的呢?
3D游戏从入门到精通-30
加载复杂网格模型
上面都是简单的网格例子,并且只能作为演示作用,没有多少实用价值,下面来加载一个更复杂的网格模型。在我们玩过的游戏里,绝大多数都有室内场境的地方,比如到武器店里买东西,就需要有一个室内场境。在我们最常见的房子,大多数都是长方形的,也就是有6个面的立方体,而在这六个面贴上纹理,就是室内环境了。由于我没有美工,只能拿现成的网格模型来加载显示,模型文件放在目录G:/MM3D/Engine/bin/models里,其中room.x是网格模型文件,DoorDiff.dds、FireplaceDiff.dds、oldwood.dds、wallpaper.dds都是纹理图片。实现的效果图如下:
本电子书、MM3D引擎源程序、例子源程序共49元一套
联系人:蔡军生
联系方式:
QQ: 9073204
EMAIL: caimouse1976 at sina.com
在这个场境里,主要有四部份组成,地板是由贴木板纹理的模型组成。四周的墙是由花纹纹理的模型组成。还有一个门模型,以及火墙模型。在这个例子里,比上面一个复杂的地方,就是多了纹理贴图。
先看看加载网格模型的函数,看看怎么样实现加载网格和纹理。
//
//加载网格模型。
//蔡军生 2006/09/15
//
HRESULT CCAIRoom::LoadMeshFromFile(void)
{
//网格模型路径。
char chPath[MAX_PATH];
if ( !GetModuleFileName( NULL, chPath, MAX_PATH ) )
{
return S_FALSE;
}
std::string strName(chPath);
std::basic_string <char>::size_type stPos = strName.find_last_of("//");
if(stPos != std::string::npos)
{
strName = strName.substr(0,stPos);
}
std::string strPath = strName;
const std::string strFile("//bin//models//room.x");
strName += strFile;
//加载X文件。
LPD3DXBUFFER pAdjacencyBuffer = NULL;
LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
HRESULT hr = D3DXLoadMeshFromX( strName.c_str(), D3DXMESH_MANAGED,
m_pd3dDevice, &pAdjacencyBuffer,
&pD3DXMtrlBuffer, NULL, &m_dwNumRoomMaterials,
&m_pMeshRoom );
if (FAILED(hr))
{
return DXTRACE_ERR( "D3DXLoadMeshFromX", hr );
}
// 优化网格显示。
if( FAILED( hr = m_pMeshRoom->OptimizeInplace(
D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ) ) )
{
if (pAdjacencyBuffer)
{
pAdjacencyBuffer->Release();
}
if (pD3DXMtrlBuffer)
{
pD3DXMtrlBuffer->Release();
}
return DXTRACE_ERR("OptimizeInplace",hr);
}
//是否有材料。
if (pD3DXMtrlBuffer && m_dwNumRoomMaterials > 0)
{
//
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
m_pMeshRoomMaterials = new D3DMATERIAL9[m_dwNumRoomMaterials];
if (!m_pMeshRoomMaterials)
{
//
pD3DXMtrlBuffer->Release();
return E_OUTOFMEMORY;
}
//保存材料和纹理。
for( DWORD i = 0; i < m_dwNumRoomMaterials; i++ )
{
//
m_pMeshRoomMaterials[i] = d3dxMaterials[i].MatD3D;
m_pMeshRoomMaterials[i].Ambient = m_pMeshRoomMaterials[i].Diffuse;
//
if( d3dxMaterials[i].pTextureFilename != NULL &&
lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
{
//
LPDIRECT3DTEXTURE9 pMeshTextures = NULL;
std::string strTemp = strPath + "//bin//models//";
strTemp += d3dxMaterials[i].pTextureFilename;
hr = D3DXCreateTextureFromFile( m_pd3dDevice,
strTemp.c_str(),
&pMeshTextures );
if (SUCCEEDED(hr))
{
m_vMeshRoomTextures.push_back(pMeshTextures);
}
else
{
m_vMeshRoomTextures.push_back(NULL);
}
OutputDebugString("Texture/n");
}
else
{
m_vMeshRoomTextures.push_back(NULL);
}
}
}
//
if (pD3DXMtrlBuffer)
{
pD3DXMtrlBuffer->Release();
}
if (pAdjacencyBuffer)
{
pAdjacencyBuffer->Release();
}
return S_OK;
}