CDXUTMesh.docx
《CDXUTMesh.docx》由会员分享,可在线阅读,更多相关《CDXUTMesh.docx(45页珍藏版)》请在冰点文库上搜索。
CDXUTMesh
DXUT源码分析----类CDXUTMesh
(1)
类CDXUTMesh主要用于从一个指定的网格模型中加载数据、渲染模型以及销毁网格模型,它将整个网格模型作为一个整体进行操作,没有考虑网格模型内部的框架层次,对于不包含动画信息的网格模型,使用该类是一个比较好的选择。
这个类的定义和实现分别位于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(LPCWSTRstrName)
{
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。
LPD3DXMESHGetMesh(){returnm_pMesh;}
第三类是设备恢复和丢失时所采取的操作函数,这里所包含的两个成员函数RestoreDeviceObjects()和InvalidateDeviceObjects()分别是在设备恢复和丢失时调用,用于恢复和释放相应的资源。
HRESULTCDXUTMesh:
:
RestoreDeviceObjects(LPDIRECT3DDEVICE9pd3dDevice)
{
returnS_OK;
}
HRESULTCDXUTMesh:
:
InvalidateDeviceObjects()
{
SAFE_RELEASE(m_pIB);
SAFE_RELEASE(m_pVB);
SAFE_RELEASE(m_pDecl);
returnS_OK;
}
第四类是创建和销毁函数,这里首先重载了3个创建网格模型函数Create(),它们依次用于从指定的.x文件创建网格模型,从接口ID3DXFileData创建网格模型,从输入的网格模型中创建新的网格模型。
函数CreateMaterials()用于创建网格模型中所需的材质和纹理。
函数Destroy()用来在程序退出时销毁指定的资源。
来看第一个Create()函数的实现:
HRESULT CDXUTMesh:
:
Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename )
{
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源码分析----媒体文件查找函数。
WCHARstrPath[MAX_PATH];
LPD3DXBUFFERpAdjacencyBuffer=NULL;
LPD3DXBUFFERpMtrlBuffer=NULL;
HRESULThr;
//Cleanuppreviousmeshifany
Destroy();
//Findthepathforthefile,andconvertittoANSI(fortheD3DXAPI)
DXUTFindDXSDKMediaFileCch(strPath,sizeof(strPath)/sizeof(WCHAR),strFilename);
//Loadthemesh
if(FAILED(hr=D3DXLoadMeshFromXW(strPath,D3DXMESH_MANAGED,pd3dDevice,&pAdjacencyBuffer,&pMtrlBuffer,NULL,
&m_dwNumMaterials,&m_pMesh)))
{
returnhr;
}
接着调用OptimizeInplace()对网格模型进行优化,该函数调用时第一个参数的含义如下:
D3DXMESHOPT_COMPACT—从mesh中移除没有用的顶点和索引项。
D3DXMESHOPT_ATTRSORT—根据属性给三角形排序并调整属性表,这将使DrawSubset执行更有效。
D3DXMESHOPT_VERTEXCACHE—增加顶点缓存的命中率。
//Optimizethemeshforperformance
if(FAILED(hr=m_pMesh->OptimizeInplace(
D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE,
(DWORD*)pAdjacencyBuffer->GetBufferPointer(),NULL,NULL,NULL)))
{
SAFE_RELEASE(pAdjacencyBuffer);
SAFE_RELEASE(pMtrlBuffer);
returnhr;
}
接下来,函数将模型文件所在的路径存储在strPath,如果没有路径,则strPath置为NULL。
//SetstrPathtothepathofthemeshfile
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);
最后,函数获取模型的顶点数,面数,每个顶点所占的字节大小,顶点索引缓存,顶点缓存,顶点声明,以方便以后访问。
//Extractdatafromm_pMeshforeasyaccess
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);
returnhr;
DXUT源码分析----类CDXUTMesh
(2)
函数CreateMaterials()用于创建网格模型中所需的材质和纹理,我们来看看CreateMaterials()的实现:
HRESULT CDXUTMesh:
:
CreateMaterials( LPCWSTR strPath, IDirect3DDevice9 *pd3dDevice,
D3DXMATERIAL* d3dxMtrls, DWORD dwNumMaterials )
{
// Get material info for the mesh, get the array of materials out of the buffer.
m_dwNumMaterials = dwNumMaterials;
if( d3dxMtrls && m_dwNumMaterials > 0 )
{
// Allocate memory for the materials and textures
m_pMaterials = new D3DMATERIAL9[m_dwNumMaterials];
if( m_pMaterials == NULL )
return E_OUTOFMEMORY;
m_pTextures = new LPDIRECT3DBASETEXTURE9[m_dwNumMaterials];
if( m_pTextures == NULL )
return E_OUTOFMEMORY;
m_strMaterials = new CHAR[m_dwNumMaterials][MAX_PATH];
if( m_strMaterials == NULL )
return E_OUTOFMEMORY;
// Copy each material and create its texture
for( DWORD i=0; i {
// Copy the material
m_pMaterials[i] = d3dxMtrls[i].MatD3D;
m_pMaterials[i].Ambient = m_pMaterials[i].Diffuse; // add by me
m_pTextures[i] = NULL;
// Create a texture
if( d3dxMtrls[i].pTextureFilename )
{
StringCchCopyA( m_strMaterials[i], MAX_PATH, d3dxMtrls[i].pTextureFilename );
WCHAR strTexture[MAX_PATH];
WCHAR strTextureTemp[MAX_PATH];
D3DXIMAGE_INFO ImgInfo;
// First attempt to look for texture