基于DirectX的游戏开发中,人物和模型由针对每个对象的成千上万个多边形组成的,对纹理映射而言这是非常复杂的,假设不加索引的几何图形,而只是用三角形(DirectX的模型基础是三角形)。那将会是一场恐怖的噩梦。所以现在将简单地介绍从游戏程序外获取那些图形开发资源。
加载模型的方法多种多样,鉴于现实生活中各式各样的模型文件格式,加载的渠道也不太一致。文件格式只是在特定文件中保存信息的方式。Direct3D中的文件格式也是多种多样,如X模型文件,OBJ模型,UMF模型等。现在主要对X模型也就是DirectX模型的加载进行介绍:首先先对X模型进行些微介绍,X模型是在Direct3D中使用的模型,可以使用内置的Direct3d函数加载,渲染,和释放X模型。X文件是基于Mesh模板网格的,这种模板包括外观,纹理,法线等。X模板可以被保存为文本文件,也可以被保存为二进制文件。这意味这可以在任意的文本编辑器中打开X文件并修改其内容。下面介绍一下由两个三角形组成的X模型:
两个三角形组成的X文件模型的实例
xof 0302txt 0032 //xof意味着正在加载的是某个版本的X文件,
//后面是组版本号与次版本号32(0032)
Material UgpMat { //Material 0.
1.0; 1.0 1.0; 1.0; ; //Diffuse Color(反射颜色)
0.0; //Specular power
0.0; 0.0; 0.0; ; //Specular color(颜色三坐标意味RGB)
0.0; 0.0; 0.0;; //Emissive color
TextureFilename("ugp.bmp";) //Texture filename(纹理文件名)
}
// The square mesh data.
Mesh Square { //定义了完整网格
4; //Number of vertexs.
1.0; 1.0; 0.0; , //Vertex 1
- 1.0; 1.0; 0.0; , //Vertex 2
- 1.0; -1.0; 0.0; , //Vertex 3
1.0; -1.0; 0.0; //Vertex 4
2; //Number of triangles.
3; 0, 1, 2; //Triangle indices 1.
3 ; 0, 2, 3; //Triangle indices 2.
MeshMaterialList { //该模板指明网格中的外观使用哪种材质
1; //Number of materials.
2; //Number of faces.
0; //Face 0 use material 0.
0; ; //Face 1 use material 0.
{UgpMat} //Reference of material.
}
MeshTextureCoords { //该模板将纹理映射到网格
4;
0.0; 0.0;, //Vertex 1 tex coord,
0.0; 1.0;, //Vertex 2 tex coord.
1.0; 1.0;, //Vertex 3 tex coord.
1.0; 0.0; ; //Vertex 4 tex coord.
}
} //End of Mesh Squar |
这就是一个完整的X模型实例代码 , 它包含了 几个模块:Material模板, Mesh模板,
MeshMaterial List模板,MeshTextureCoords模板。
下面将介绍次模型的加载,加载一个老虎模型,主要可分为两种类型的:Common与非Common类的。
非Common结构
1,模型的全局变量
LPDIRECT3D9 g_pD3D = NULL; // Direct3D对象
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Direct3D设备
LPD3DXMESH g_pMesh = NULL; // mesh模型指针
D3DMATERIAL9* g_pMeshMaterials = NULL; //mesh模型所用材质指针
LPDIRECT3DTEXTURE9* g_pMeshTextures = NULL; // mesh模型所用纹理指针
DWORD g_dwNumMaterials = 0L; //mesh模型材质数量 |
2.初始化D3D流程
HRESULT InitD3D( HWND hWnd )
{
// 创建direct3D对象
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
//填写结构体创建direct3D设备,使用z深度缓冲
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
//创建D3D设备
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
// 开启z深度缓冲
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
// 开启环境光
g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );
return S_OK;
} |
3,初始化几何数据流程
HRESULT InitGeometry()
{
LPD3DXBUFFER pD3DXMtrlBuffer;
// 从文件中加载Mesh模型
if( FAILED( D3DXLoadMeshFromX( "Tiger.x", D3DXMESH_SYSTEMMEM,
g_pd3dDevice, NULL,
&pD3DXMtrlBuffer, NULL, &g_dwNumMaterials,
&g_pMesh ) ) )
{
// 如果当前文件夹中没有需要加载的X文件,则尝试在上一级目录加载
if( FAILED( D3DXLoadMeshFromX( "../Tiger.x", D3DXMESH_SYSTEMMEM,
g_pd3dDevice, NULL,
&pD3DXMtrlBuffer, NULL, &g_dwNumMaterials,
&g_pMesh ) ) )
{
MessageBox(NULL, "Could not find tiger.x", "Meshes.exe", MB_OK);
return E_FAIL;
}
}
//需要从pD3DXMtrlBuffer指向的缓冲区中释放材质信息和纹理名称
D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];
g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
for( DWORD i=0; i<g_dwNumMaterials; i++ )
{
// 复制材质
g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
// 为材质设定环境光颜色
g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse;
g_pMeshTextures[i] = NULL;
if( d3dxMaterials[i].pTextureFilename != NULL &&
lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
{
//通过纹理文件名加载纹理
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice,
d3dxMaterials[i].pTextureFilename,
&g_pMeshTextures[i] ) ) )
{
//如果纹理文件不在当前文件夹中尝试上一级文件夹
const TCHAR* strPrefix = TEXT("../");
const int lenPrefix = lstrlen( strPrefix );
TCHAR strTexture[MAX_PATH];
lstrcpyn( strTexture, strPrefix, MAX_PATH );
lstrcpyn( strTexture + lenPrefix,
d3dxMaterials[i].pTextureFilename,
MAX_PATH - lenPrefix );
// 从上一文件夹创建
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice,
strTexture,
&g_pMeshTextures[i] ) ) )
{
MessageBox(NULL, "Could not find texture map", "Meshes.exe", MB_OK);
}
}
}
}
// 释放材质缓冲区
pD3DXMtrlBuffer->Release();
return S_OK;
} |
程序刚开始使用的缓冲区ID3DXBuffer,它是数据缓冲区接口,可以储存定点项目数据,索引数据,邻近数据,材质信息等。
它有两个非常重要的接口GetBufferPointer()和GetBufferSize(),分别是返回缓冲区数据指针和缓冲区大小指针。
(这上面的代码还缺少了一些渲染之类的,和释放处理内存的步棸)
其中包含了一个结构:
HRESULT WINAPI D3DXLoadMeshFromX(
LPCTSTR pFilename,//加载的X文件名可以是相对路径名或绝对路径名
DWORD Options, //Mesh模型标识符
LPDIRECT3DDEVICE9 pD3DDevice,
LPD3DXBUFFER *ppAdjacency, //邻近三角形信息
LPD3DXBUFFER *ppMaterials, // 返回材质指针
LPD3DXBUFFER *PPEffectTnstances, // 返回特效实例指针
DWORD *pNumMaterials, // 返回材质数量
LPD3DXMESH *ppMesh // 返回被加载的Mesh模型
); |
使用Common结构
步棸 1,在派生类CMyD3DApplication的声明中添加一行成员变量声明。
CD3DMesh* m_pMesheh;
步棸2,在CMyD3DApplication构造函数里添加一行。
m_pMesh = new CD3DMesh;
步棸3,在可重写函数InitDeviceObjects()里添加一行。
m_pMesh->Create(m_pd3dDevice, “Map.X”);
步棸4,可重写函数RestoreDeviceObjects()里添加
m_pd3dMesh->RestoreDeviceObjects(m_pd3dDevice);
步棸5, 在可重写函数Render()里添加
m_pMesh->Render(M_pd3dDevice);
步棸6,在可重写函数InvalidareDeviceObjects()中添加一行
m_pMesh->InvalidareDeviceObjects();
步棸7,在可重写函数DeleteDeviceObjects()中添加一行
m_pMesh->Destroy();
编译后即可完成加载 ,再用Common时应注意在安装DirectX时的环境配置应该添加DXSDK/Sampels/c++/common/include 以及其下的/Src.
——————————————–