这个类的定义和实现分别位于DXUTMesh.h和DXUTMesh.cpp中,其定义如下:
// Name: class CDXUTMesh
// Desc: Class for loading and rendering file-based meshes
// -----------------------------------------------------------------------------
class CDXUTMesh
{
public :
WCHAR m_strName[ 512 ];
LPD3DXMESH m_pMesh; // Managed mesh
// Cache of data in m_pMesh for easy access
IDirect3DVertexBuffer9 * m_pVB;
IDirect3DIndexBuffer9 * m_pIB;
IDirect3DVertexDeclaration9 * m_pDecl;
DWORD m_dwNumVertices;
DWORD m_dwNumFaces;
DWORD m_dwBytesPerVertex;
DWORD m_dwNumMaterials; // Materials for the mesh
D3DMATERIAL9 * m_pMaterials;
CHAR ( * m_strMaterials)[MAX_PATH];
IDirect3DBaseTexture9 ** m_pTextures;
bool m_bUseMaterials;
public :
// Rendering
HRESULT Render( LPDIRECT3DDEVICE9 pd3dDevice,
bool bDrawOpaqueSubsets = true ,
bool bDrawAlphaSubsets = true );
HRESULT Render( ID3DXEffect * pEffect,
D3DXHANDLE hTexture = NULL,
D3DXHANDLE hDiffuse = NULL,
D3DXHANDLE hAmbient = NULL,
D3DXHANDLE hSpecular = NULL,
D3DXHANDLE hEmissive = NULL,
D3DXHANDLE hPower = NULL,
bool bDrawOpaqueSubsets = true ,
bool bDrawAlphaSubsets = true );
// Mesh access
LPD3DXMESH GetMesh() { return m_pMesh; }
// Rendering options
void UseMeshMaterials( bool bFlag ) { m_bUseMaterials = bFlag; }
HRESULT SetFVF( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwFVF );
HRESULT SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, const D3DVERTEXELEMENT9 * pDecl,
bool bAutoComputeNormals = true , bool bAutoComputeTangents = true ,
bool bSplitVertexForOptimalTangents = false );
// Initializing
HRESULT RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice );
HRESULT InvalidateDeviceObjects();
// Creation/destruction
HRESULT Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename );
HRESULT Create( LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXFILEDATA pFileData );
HRESULT Create(LPDIRECT3DDEVICE9 pd3dDevice, ID3DXMesh * pInMesh, D3DXMATERIAL * pd3dxMaterials, DWORD dwMaterials);
HRESULT CreateMaterials(LPCWSTR strPath, IDirect3DDevice9 * pd3dDevice,
D3DXMATERIAL * d3dxMtrls, DWORD dwNumMaterials);
HRESULT Destroy();
CDXUTMesh( LPCWSTR strName = L " CDXUTMeshFile_Mesh " );
virtual ~ CDXUTMesh();
};
该类中包含的成员函数按其作用可分为6类。
第一类是构造和析构函数,函数CDXUTMesh()和~CDXUTMesh()分别是该类的构造函数和析构函数,其作用分别是进行一些初始化工作以及在类CDXUTMesh的对象被销毁时完成最后的销毁工作。
CDXUTMesh::CDXUTMesh( LPCWSTR strName )
{
StringCchCopy( m_strName, 512, strName );
m_pMesh = NULL;
m_pMaterials = NULL;
m_pTextures = NULL;
m_bUseMaterials = TRUE;
m_pVB = NULL;
m_pIB = NULL;
m_pDecl = NULL;
m_strMaterials = NULL;
m_dwNumMaterials = 0;
m_dwNumVertices = 0;
m_dwNumFaces = 0;
m_dwBytesPerVertex = 0;
}
CDXUTMesh::~CDXUTMesh()
{
Destroy();
}
第二类是获取网格函数,它仅包含一个函数GetMesh(),实现也非常简单,即返回类CDXUTMesh的成员变量m_pMesh。
LPD3DXMESH GetMesh() { return m_pMesh; }
第三类是设备恢复和丢失时所采取的操作函数,这里所包含的两个成员函数RestoreDeviceObjects()和InvalidateDeviceObjects()分别是在设备恢复和丢失时调用,用于恢复和释放相应的资源。
HRESULT CDXUTMesh::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
{
return S_OK;
}
HRESULT CDXUTMesh::InvalidateDeviceObjects()
{
SAFE_RELEASE( m_pIB );
SAFE_RELEASE( m_pVB );
SAFE_RELEASE( m_pDecl );
return S_OK;
}
第四类是创建和销毁函数,这里首先重载了3个创建网格模型函数Create(),它们依次用于从指定的.x文件创建网格模型,从接口ID3DXFileData创建网格模型,从输入的网格模型中创建新的网格模型。函数CreateMaterials()用于创建网格模型中所需的材质和纹理。函数Destroy()用来在程序退出时销毁指定的资源。
来看第一个Create()函数的实现:
{
WCHAR strPath[MAX_PATH];
LPD3DXBUFFER pAdjacencyBuffer = NULL;
LPD3DXBUFFER pMtrlBuffer = NULL;
HRESULT hr;
// Cleanup previous mesh if any
Destroy();
// Find the path for the file, and convert it to ANSI (for the D3DX API)
DXUTFindDXSDKMediaFileCch( strPath, sizeof (strPath) / sizeof (WCHAR), strFilename );
// Load the mesh
if (FAILED(hr = D3DXLoadMeshFromXW(strPath, D3DXMESH_MANAGED, pd3dDevice, & pAdjacencyBuffer, & pMtrlBuffer, NULL,
& m_dwNumMaterials, & m_pMesh)))
{
return hr;
}
// Optimize the mesh for performance
if ( FAILED( hr = m_pMesh -> OptimizeInplace(
D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD * ) pAdjacencyBuffer -> GetBufferPointer(), NULL, NULL, NULL)))
{
SAFE_RELEASE( pAdjacencyBuffer );
SAFE_RELEASE( pMtrlBuffer );
return hr;
}
// Set strPath to the path of the mesh file
WCHAR * pLastBSlash = wcsrchr( strPath, L ' // ' );
if ( pLastBSlash )
* (pLastBSlash + 1 ) = L ' /0 ' ;
else
* strPath = L ' /0 ' ;
D3DXMATERIAL * d3dxMtrls = (D3DXMATERIAL * ) pMtrlBuffer -> GetBufferPointer();
hr = CreateMaterials( strPath, pd3dDevice, d3dxMtrls, m_dwNumMaterials );
SAFE_RELEASE( pAdjacencyBuffer );
SAFE_RELEASE( pMtrlBuffer );
// Extract data from m_pMesh for easy access
D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
m_dwNumVertices = m_pMesh -> GetNumVertices();
m_dwNumFaces = m_pMesh -> GetNumFaces();
m_dwBytesPerVertex = m_pMesh -> GetNumBytesPerVertex();
m_pMesh -> GetIndexBuffer( & m_pIB );
m_pMesh -> GetVertexBuffer( & m_pVB );
m_pMesh -> GetDeclaration( decl );
pd3dDevice -> CreateVertexDeclaration( decl, & m_pDecl );
return hr;
}
函数首先销毁旧的资源,并调用DXUTFindDXSDKMediaFileCch()通过文件名查找文件所在的路径,接着调用D3DXLoadMeshFromXW()从文件中加载网格模型。
DXUTFindDXSDKMediaFileCch()的实现分析请参阅DXUT源码分析 ---- 媒体文件查找函数。
WCHAR strPath[MAX_PATH];
LPD3DXBUFFER pAdjacencyBuffer = NULL;
LPD3DXBUFFER pMtrlBuffer = NULL;
HRESULT hr;
// Cleanup previous mesh if any
Destroy();
// Find the path for the file, and convert it to ANSI (for the D3DX API)
DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), strFilename );
// Load the mesh
if(FAILED(hr = D3DXLoadMeshFromXW(strPath, D3DXMESH_MANAGED, pd3dDevice, &pAdjacencyBuffer, &pMtrlBuffer, NULL,
&m_dwNumMaterials, &m_pMesh)))
{
return hr;
}
接着调用OptimizeInplace()对网格模型进行优化,该函数调用时第一个参数的含义如下:
D3DXMESHOPT_COMPACT — 从mesh中移除没有用的顶点和索引项。
D3DXMESHOPT_ATTRSORT — 根据属性给三角形排序并调整属性表,这将使DrawSubset执行更有效。
D3DXMESHOPT_VERTEXCACHE — 增加顶点缓存的命中率。
// Optimize the mesh for performance
if( FAILED( hr = m_pMesh->OptimizeInplace(
D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
(DWORD*) pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL)))
{
SAFE_RELEASE( pAdjacencyBuffer );
SAFE_RELEASE( pMtrlBuffer );
return hr;
}
接下来,函数将模型文件所在的路径存储在strPath,如果没有路径,则strPath置为NULL。
// Set strPath to the path of the mesh file
WCHAR* pLastBSlash = wcsrchr( strPath, L'//' );
if( pLastBSlash )
*(pLastBSlash + 1) = L'/0';
else
*strPath = L'/0';
接下来,函数调用CreateMaterials()创建存储材质和纹理的内存,并释放邻接信息缓存和材质缓存。
D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*) pMtrlBuffer->GetBufferPointer();
hr = CreateMaterials( strPath, pd3dDevice, d3dxMtrls, m_dwNumMaterials );
SAFE_RELEASE( pAdjacencyBuffer );
SAFE_RELEASE( pMtrlBuffer );
最后,函数获取模型的顶点数,面数,每个顶点所占的字节大小,顶点索引缓存,顶点缓存,顶点声明,以方便以后访问。
// Extract data from m_pMesh for easy access
m_dwNumVertices = m_pMesh->GetNumVertices();
m_dwNumFaces = m_pMesh->GetNumFaces();
m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex();
m_pMesh->GetIndexBuffer( &m_pIB );
m_pMesh->GetVertexBuffer( &m_pVB );
m_pMesh->GetDeclaration( decl );
pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl );
return hr;