天行健 君子当自强而不息

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 = truebool 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()函数的实现:

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源码分析 ---- 媒体文件查找函数

    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;

posted on 2008-05-31 08:58 lovedday 阅读(1221) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论