DOC

CDXUTMesh

By Ernest Taylor,2014-09-16 01:55
7 views 0
CDXUTMesh

DXUT源码分析 ---- CDXUTMesh1

    CDXUTMesh主要用于从一个指定的网格模型中加载数据、渲染模型以及销毁网格模型,它将

    整个网格模型作为一个整体进行操作,没有考虑网格模型内部的框架层次,对于不包含动画信息

    的网格模型,使用该类是一个比较好的选择。

    这个类的定义和实现分别位于DXUTMesh.hDXUTMesh.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()函数的实现!

    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, &pA

    djacencyBuffer, &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 D3

    DX API)

     DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHA

    R), strFilename );

     // Load the mesh

     if(FAILED(hr = D3DXLoadMeshFromXW(strPath, D3DXMESH_MANAGED, pd3d

    Device, &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 | D3DXMESH

    OPT_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->GetBufferP

    ointer();

     hr = CreateMaterials( strPath, pd3dDevice, d3dxMtrls, m_dwNumMate

    rials );

     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;

    DXUT源码分析 ---- CDXUTMesh2

    函数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;

Report this document

For any questions or suggestions please email
cust-service@docsford.com