• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            D3D中網格模型的運用


            點擊下載源碼和資源

            在最底層的層次中,Direct3D并不使用網格模型,而只是使用多邊形。D3DX增強了 Direct3D系統的功能性,添加了一系列負責處理網格模型的容器和進行渲染的對象。.X文件是微軟公司所開發的,高度通用的三維模型存儲格式。它是模板驅動并完全可擴展,這就意味著可以使用它來滿足文件存儲的所有需求。一個.X文件,正如它的文件擴展名所表明的,是非常通用的。它可以是基于文本的,以便更容易進行編輯;或者是基于二進制的,這樣可以使文件更小,并且更容易地進行保護以便不被窺視。整個.X文件格式是基于模板的,非常類似于C語言結構。

            為了讀取并處理一個.X文件,可以利用COM對象的一個小集合來解析從頭到尾在.X文件中所遇到的每個數據對象。將數據對象作為一個字節的數組進行處理;僅僅是將數組轉換為一種可使用的結構,以便能夠容易地訪問到包含在對象里的數據。

            根據存儲在.X文件里的內容,這些對象可以改變。在這里,對象代表了網格模型以及網格模型相關的數據(例如骨骼結構,所謂的框架層次和動畫數據)。程序員的工作就是去解析這些對象,加載網格模型數據,創建動畫表格,并構造框架的層次。

            .X文件格式的詳細介紹請參閱XFile網格的應用(1),創建網格的具體API函數和方法請參閱XFile網格的應用(2),XFile網格的應用(3)。

            框架層次的運用

            使用框架模板(frame template)將一個或多個數據對象(通常為網格模型)進行分組,以便能夠更容易地進行處理。也可以創建一個網格模型,并使用多個框架去包含網格模型引用,這樣就能夠對一個網格模型使用許多次。一個框架層次(frame hierarchy)定義了一個場景的結構,或者網格模型的分組,每當一個框架移動時,所有嵌入其中的框架也同樣產生移動。根沒有父框架,意味著他就是層次的頂端,且不屬于任何別的框架。被連接到其他框架上的框架稱之為子框架(child frames)(也可以稱之為節點(node))。

            當一個框架移動時,它的所有子框架也隨之移動。例如如果移動上臂,前臂和手也跟著移動,而另一方面,如果移動人的手,只有手會改變位置,因為它沒有子框架(前臂是手的父框架)。每個框架都有它自己的方位,在.X文件的術語中稱之為框架變換(frame transformation)。將這種變換運用到較高層次的對象上,每個變換將被傳遞下去,從層次的頂端以各種方式到達每個子框架。

            如下所示:骨架是骨骼框架層次的一個完美實例,層次中的每塊骨骼都連接到胸部。



            框架層次是使用高級網格模型和動畫技術的要點,事實上,它們是某些運用所必需的,諸如蒙皮網格模型。使用框架層次,另外一個原因是隔離場景其中一部分,以這種方式,可以通過移動特定的框架來修改場景中的一小塊區域,而保留場景的其余部分。

            解析.X文件

            為了解析一個.X文件,需要使用 ID3DXFile對象,它的工作就是打開一個.X文件并枚舉文件中的數據對象,再將他們以一種易于訪問的方式展現給用戶。為了使用ID3DXFile組件,應該包含dxfile.h,rmfxguid.h,rmfxtmpl.h,同時還必須將dxguid.lib和d3ddxof.lib庫鏈接到工程中。

            Applications use the methods of the ID3DXFile interface to create instances of the ID3DXFileEnumObject and ID3DXFileSaveObject interfaces, and to register templates.

            ID3DXFile Members

            Method Description
            ID3DXFile::CreateEnumObject Creates an enumerator object that will read a .x file.
            ID3DXFile::CreateSaveObject Creates a save object that will be used to save data to a .x file.
            ID3DXFile::RegisterEnumTemplates Registers custom templates, given an ID3DXFileEnumObject enumeration object.
            ID3DXFile::RegisterTemplates Registers custom templates.

            Remarks

            An ID3DXFile object also contains a local template store. This local storage may be added to only with the ID3DXFile::RegisterEnumTemplates and ID3DXFile::RegisterTemplates methods.

            ID3DXFileEnumObject and ID3DXFileSaveObject objects created with ID3DXFile::CreateEnumObject and ID3DXFile::CreateSaveObject also utilize the template store of the parent ID3DXFile object.

            The ID3DXFile interface is obtained by calling the D3DXFileCreate function.

            The globally unique identifier (GUID) for the ID3DXFile interface is IID_ID3DXFile.

            The LPD3DXFILE type is defined as a pointer to the ID3DXFile interface.

            typedef interface ID3DXFile *LPD3DXFILE;

            解析一個.X文件并不像開始時所看到的那樣困難,竅門就是搜索整個對象的層次,查找想要使用的數據對象,也就是網格模型和框架的對象。 最困難的部分是要記住那些嵌入到其他對象中的對象,因而可能會遇到對象的引用(需要解決它,以便能夠訪問到原始的對象數據),而不是對象。

            如下圖所示,.X文件允許用戶將模板對象嵌入到另一個模板對象中,從而創建出一個模板層次結構。

            可以通過D3DXFileCreate來創建ID3DXFile對象:

            Creates an instance of an ID3DXFile object.

            STDAPI D3DXFileCreate(
            ID3DXFile ** lplpDirectXFile
            );

            Parameters

            lplpDirectXFile
            Address of a pointer to an ID3DXFile interface, representing the created .x file object.

            Return Values

            If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the following: E_POINTER, E_OUTOFMEMORY.

            Remarks

            After using this function, use ID3DXFile::RegisterTemplates or ID3DXFile::RegisterEnumTemplates to register templates, ID3DXFile::CreateEnumObject to create an enumerator object, or ID3DXFile::CreateSaveObject to create a save object.

            創建完ID3DXFile對象后,首先需要通過ID3DXFile::RegisterTemplates來注冊Mesh模板。

            Registers custom templates.

            HRESULT RegisterTemplates(
            LPCVOID pvData,
            SIZE_T cbSize
            );

            Parameters

            pvData
            [in] Pointer to a buffer consisting of a .x file in text or binary format that contains templates.
            cbSize
            [in] Size of the buffer pointed to by pvData, in bytes.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following: D3DXFERR_BADVALUE, D3DXFERR_PARSEERROR.

            Remarks

            The following code fragment provides an example call to RegisterTemplates And example contents for the buffer to which pvData points.

            #define XSKINEXP_TEMPLATES \
            "xof 0303txt 0032\
            template XSkinMeshHeader \
            { \
            <3CF169CE-FF7C-44ab-93C0-F78F62D172E2> \
            WORD nMaxSkinWeightsPerVertex; \
            WORD nMaxSkinWeightsPerFace; \
            WORD nBones; \
            } \
            template VertexDuplicationIndices \
            { \
            <B8D65549-D7C9-4995-89CF-53A9A8B031E3> \
            DWORD nIndices; \
            DWORD nOriginalVertices; \
            array DWORD indices[nIndices]; \
            } \
            template SkinWeights \
            { \
            <6F0D123B-BAD2-4167-A0D0-80224F25FABB> \
            STRING transformNodeName;\
            DWORD nWeights; \
            array DWORD vertexIndices[nWeights]; \
            array float weights[nWeights]; \
            Matrix4x4 matrixOffset; \
            }"
            .
            .
            .

            LPD3DXFILE pD3DXFile = NULL;

            if ( FAILED(hr = pD3DXFile->RegisterTemplates((LPVOID)XSKINEXP_TEMPLATES, sizeof( XSKINEXP_TEMPLATES ) - 1 ) ) )
            goto End;

            All templates must specify a name and a UUID.

            This method calls the ID3DXFile::RegisterEnumTemplates method, obtaining an ID3DXFileEnumObject interface pointer by calling ID3DXFile::CreateEnumObject with pvData as the first parameter.

            注冊完Mesh模板之后,需要調用ID3DXFile::CreateEnumObject來創建枚舉對象以枚舉訪問各個具體的XFILE數據對象。

            Creates an enumerator object that will read a .x file.

            HRESULT CreateEnumObject(
            LPCVOID pvSource,
            D3DXF_FILELOADOPTIONS loadflags,
            ID3DXFileEnumObject ** ppEnumObj
            );

            Parameters

            pvSource
            [out] The data source. Either:
            • A file name
            • A D3DXF_FILELOADMEMORY structure
            • A D3DXF_FILELOADRESOURCE structure
            Depending on the value of loadflags.
            loadflags
            [in] Value that specifies the source of the data. This value can be one of the D3DXF_FILELOADOPTIONS flags.

            The following table specifies file load options with .x files:

            #define Value Description
            D3DXF_FILELOAD_FromFile 0 Load data from a file.
            D3DXF_FILELOAD_FROMWFILE 1 Load data from a file.
            D3DXF_FILELOAD_FROMRESOURCE 2 Load data from a resource.
            D3DXF_FILELOAD_FROMMEMORY 3 Load data from memory.
             
            ppEnumObj
            [out] Address of a pointer to an ID3DXFileEnumObject interface, representing the created enumerator object.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following: D3DXFERR_BADVALUE, D3DXFERR_PARSEERROR.

            Remarks

            After using this method, use one of the ID3DXFileEnumObject methods to retrieve a data object.

            來看看ID3DXFileEnumObject的具體定義:

            Applications use the methods of the ID3DXFileEnumObject interface to cycle through the child file data objects in the file and to retrieve a child object by its globally unique identifier (GUID) or by its name.

            ID3DXFileEnumObject Members

            Method Description
            ID3DXFileEnumObject::GetChild Retrieves a child object in this file data object.
            ID3DXFileEnumObject::GetChildren Retrieves the number of child objects in this file data object.
            ID3DXFileEnumObject::GetDataObjectById Retrieves the data object that has the specified GUID.
            ID3DXFileEnumObject::GetDataObjectByName Retrieves the data object that has the specified name.
            ID3DXFileEnumObject::GetFile Retrieves the ID3DXFile object.

            Remarks

            The GUID for the ID3DXFileEnumObject interface is IID_ID3DXFileEnumObject.

            The LPD3DXFILEENUMOBJECT type is defined as a pointer to this interface.

            typedef interface ID3DXFileEnumObject *LPD3DXFILEENUMOBJECT;
             

            創建完ID3DXFileEnumObject對象后,首先需要通過ID3DXFileEnumObject::GetChildren來取得子對象數。

            Retrieves the number of child objects in this file data object.

            HRESULT GetChildren(
            SIZE_T * puiChildren
            );

            Parameters

            puiChildren
            [in] Address of a pointer to receive the number of child objects in this file data object.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the following value will be returned: D3DXFERR_BADVALUE.

            通過ID3DXFileEnumObject::GetChildren取得子對象數之后,可以遍歷循環所有的子對象并通過
            ID3DXFileEnumObject::GetChild來取得指向D3DXFileData的指針。

            Retrieves a child object in this file data object.

            HRESULT GetChild(
            SIZE_T id,
            ID3DXFileData ** ppObj
            );

            Parameters

            id
            [in] ID of the child object to retrieve.
            ppObj
            [out] Address of a pointer to receive the child object's interface pointer.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following: D3DXFERR_BADVALUE, D3DXFERR_NOMOREOBJECTS.

            示例代碼如下所示:

            //------------------------------------------------------------------
            // A Mesh definition structure
            //------------------------------------------------------------------
            typedef struct MESH
            {
                
            char*               m_name;             // name of mesh

                ID3DXMesh*          m_mesh;             
            // mesh object
                ID3DXMesh*          m_skinmesh;         // skin mesh object
                ID3DXSkinInfo*      m_skininfo;         // skin information

                DWORD               m_num_materials;    
            // number of materails in mesh
                D3DMATERIAL9*       m_materials;        // array of materials
                IDirect3DTexture9** m_textures;         // array of textures    

                // clear all structure data
                MESH()
                {
                    m_name  = NULL;     

                    m_mesh      = NULL;
                    m_skinmesh  = NULL;
                    m_skininfo  = NULL;

                    m_num_materials = 0;
                    m_materials     = NULL;
                    m_textures      = NULL;               
                }

                
            // free all used resources
                ~MESH()
                {        
                    delete[] m_name;
                    m_name = NULL;

                    Release_Com(m_mesh);
                    Release_Com(m_skinmesh);
                    Release_Com(m_skininfo);

                    delete[] m_materials;
                    m_materials = NULL;
                    
                    
            // release all textures resource
                    if(m_textures != NULL)
                    {
                        
            for(DWORD i = 0; i < m_num_materials; i++)
                            Release_Com(m_textures[i]);

                        delete[] m_textures;
                        m_textures = NULL;
                    }
                }

            } MESH;

            //------------------------------------------------------------------
            // Structure to contain frame information
            //------------------------------------------------------------------
            typedef struct FRAME
            {
                
            char*   m_name;     // frame's name
                MESH*   m_mesh;     // linked list of meshes    
                FRAME*  m_child;    // child frame

                FRAME()
                {
                    
            // clear all data
                    m_name = NULL;
                    m_mesh = NULL;
                    m_child = NULL;
                }

                ~FRAME()
                {
                    
            // delete all used resources, including linked list of frames.
                    delete[] m_name;    m_name    = NULL;
                    delete m_mesh;      m_mesh    = NULL;
                    delete m_child;     m_child   = NULL;        
                }

            } FRAME;

            // parent frame for .X file
            FRAME* g_parent_frame = NULL;

            //--------------------------------------------------------------------------------
            // Parse x file, and return root frame.
            //--------------------------------------------------------------------------------
            FRAME* Parse_XFile(char* filename)
            {
                ID3DXFile* xfile = NULL;
                ID3DXFileEnumObject* xfile_enum = NULL;
                ID3DXFileData* xfile_data = NULL;

                
            // create the file object
                if(FAILED(D3DXFileCreate(&xfile)))
                    
            return NULL;

                
            // register the templates
                if(FAILED(xfile->RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
                {
                    xfile->Release();
                    
            return NULL;
                }

                
            // create an enumerator object that will read a .x file
                if(FAILED(xfile->CreateEnumObject((LPVOID) filename, DXFILELOAD_FROMFILE, &xfile_enum)))
                {
                    xfile->Release();
                    
            return NULL;
                }

                
            // allocate a frame that becomes root
                FRAME* frame = new FRAME();

                SIZE_T num_child;

                
            // retrieve the number of children in this file data object
                xfile_enum->GetChildren(&num_child);

                
            // loop through all objects looking for the frames and meshes
                for(SIZE_T i = 0; i < num_child; i++)
                {
                    
            // retrieves a child object in this file data object
                    if(FAILED(xfile_enum->GetChild(i, &xfile_data)))
                        
            return NULL;

                    
            // parse xfile data
                    Parse_XFile_Data(xfile_data, frame);

                    Release_Com(xfile_data);
                }

                
            // release xfile enumerator object and xfile object
                Release_Com(xfile_enum);
                Release_Com(xfile);

                
            // return root frame
                return frame;
            }

             

            通過Parse_XFile打開.X文件并找到每個XFile數據對象后,就可以編寫一個函數Parse_XFile_Data來解析這個XFile數據對象。

            來看看ID3DXFileData的定義:

            Applications use the methods of the ID3DXFileData interface to build or to access the immediate hierarchy of the data object. Template restrictions determine the hierarchy.

            ID3DXFileData Members

            Method Description
            ID3DXFileData::GetChild Retrieves a child object in this file data object.
            ID3DXFileData::GetChildren Retrieves the number of children in this file data object.
            ID3DXFileData::GetEnum Retrieves the enumeration object in this file data object.
            ID3DXFileData::GetId Retrieves the GUID of this file data object.
            ID3DXFileData::GetName Retrieves the name of this file data object.
            ID3DXFileData::GetType Retrieves the template ID in this file data object.
            ID3DXFileData::IsReference Indicates whether this file data object is a reference object that points to another child data object.
            ID3DXFileData::Lock Accesses the .x file data.
            ID3DXFileData::Unlock Ends the lifespan of the ID3DXFileData::Lock pointer.

            Remarks

            Data types allowed by the template are called optional members. The optional members are not required, but an object might miss important information without them. These optional members are saved as children of the data object. A child can be another data object or a reference to an earlier data object.

            The GUID for the ID3DXFileData interface is IID_ID3DXFileData.

            The LPD3DXFILEDATA type is defined as a pointer to this interface.

            typedef interface ID3DXFileData *LPD3DXFILEDATA;

            首先必須通過ID3DXFileData::GetType來獲得ID3DXFileData對象的模板ID。

            Retrieves the template ID in this file data object.

            HRESULT GetType(
            CONST GUID * pType
            );

            Parameters

            pType
            [in] Pointer to the GUID representing the template in this file data object.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the following value will be returned: D3DXFERR_BADVALUE.

            接著調用ID3DXFileData::GetName來獲得ID3DXFileData對象的名稱。

            Retrieves the name of this file data object.

            HRESULT GetName(
            LPSTR szName,
            SIZE_T * puiSize
            );

            Parameters

            szName
            [in] Address of a pointer to receive the name of this file data object. If this parameter is NULL, then puiSize will return the size of the string. If szName points to valid memory, the name of this file data object will be copied into szName up to the number of characters given by puiSize.
            puiSize
            [in, out] Pointer to the size of the string that represents the name of this file data object. This parameter can be NULL if szName provides a reference to the name. This parameter will return the size of the string if szName is NULL.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the following value will be returned: D3DXFERR_BADVALUE.

            Remarks

            For this method to succeed, either szName or puiSize must be non-NULL.

            代碼示例如下:

                ID3DXFileData*  sub_xfile_data = NULL;
                ID3DXBuffer*    adjacency = NULL;

                GUID  type;
                
            char* name = NULL;
                DWORD size;

                MESH* mesh = NULL;
                ID3DXBuffer* material_buffer = NULL;
                D3DXMATERIAL* materials = NULL;

                
            // get the template type
                // retrieves the globally unique identifier (GUID) of the object's template
                if(FAILED(xfile_data->GetType(&type)))
                    
            return;

                
            // get the template name (if any)
                // retrieves a pointer to a microsoft directX file object's name
                if(FAILED(xfile_data->GetName(NULL, &size)))
                    
            return;

                
            if(size != 0)
                {
                    
            if((name = new char[size]) != NULL)
                        xfile_data->GetName(name, &size);
                }

                
            // give template a default name if none found
                if(name == NULL)
                {
                    
            if((name = new char[9]) == NULL)
                        
            return;

                    strcpy(name, "Template");
                }

            取得ID3DXFileData對象的類型和名稱后,就可以根據ID3DXFileData對象的類型分別進行不同的處理。


            如果類型是框架引用(TID_D3DRMFrame),則新建一個框架對象,并將新框架對象添加到父框架對象的子對象列表中 ,并將當前框架對象設置為新框架對象。
            如果類型是Mesh對象(TID_D3DRMMesh),則加載Mesh網格并將該網格添加到父框架的Mesh成員中。
            如果是其他類型,比如(TID_D3DRMAnimationSet,TID_D3DRMAnimation,TID_D3DRMAnimationKey),則不做任何的處理。

            如下所示:

                // set sub frame
                FRAME* sub_frame = parent_frame;

                
            // process the templates
                FRAME* frame = NULL;

                
            if(type == TID_D3DRMFrame)  // it is a frame
                {
                    
            // create a new frame structure
                    frame = new FRAME();

                    
            // store the name
                    frame->m_name = name;
                    name = NULL;

                    
            // add to parent frame
                    parent_frame->m_child = frame;

                    
            // set sub frame parent
                    sub_frame = frame;
                }
                
            else if(type == TID_D3DRMMesh)  // it is a mesh
                {
                    
            // create a new mesh structure
                    mesh = new MESH();

                    
            // store the name
                    mesh->m_name = name;
                    name = NULL;

                    
            // load mesh data (as a skinned mesh)
                    // loads a skin mesh from microsoft directX .x file data object
                    if(FAILED(D3DXLoadSkinMeshFromXof(xfile_data, 0, g_d3d_device, &adjacency, &material_buffer, NULL,
                        &mesh->m_num_materials, &mesh->m_skininfo, &mesh->m_mesh)))
                    {
                        delete[] name;
                        delete mesh;
                        
            return;
                    }

                    Release_Com(adjacency);

                    
            // clone skin mesh if bones exist
                    if(mesh->m_skininfo != NULL && mesh->m_skininfo->GetNumBones() != 0)
                    {
                        
            // clones a mesh using a flexible vertex format (FVF) code
                        if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), g_d3d_device, &mesh->m_skinmesh)))
                        {
                            mesh->m_skininfo->Release();
                            mesh->m_skininfo = NULL;
                        }
                    }

                    
            // load materials or create a default one if none
                    if(mesh->m_num_materials == 0)
                    {
                        
            // create a default one
                        mesh->m_materials = new D3DMATERIAL9[1];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[1];

                        ZeroMemory(mesh->m_materials, 
            sizeof(D3DMATERIAL9));

                        mesh->m_materials[0].Diffuse.r = 1.0;
                        mesh->m_materials[0].Diffuse.g = 1.0;
                        mesh->m_materials[0].Diffuse.b = 1.0;
                        mesh->m_materials[0].Diffuse.a = 1.0;
                        mesh->m_materials[0].Ambient   = mesh->m_materials[0].Diffuse;
                        mesh->m_materials[0].Specular  = mesh->m_materials[0].Diffuse;

                        mesh->m_textures[0] = NULL;

                        mesh->m_num_materials = 1;
                    }
                    
            else
                    {
                        
            // load the materials
                        materials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();

                        mesh->m_materials = 
            new D3DMATERIAL9[mesh->m_num_materials];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[mesh->m_num_materials];

                        
            // set materials and textures for mesh
                        for(DWORD i = 0; i < mesh->m_num_materials; i++)
                        {
                            mesh->m_materials[i] = materials[i].MatD3D;
                            mesh->m_materials[i].Ambient = mesh->m_materials[i].Diffuse;

                            
            // build a texture path and load it
                            if(FAILED(D3DXCreateTextureFromFile(g_d3d_device, materials[i].pTextureFilename, &mesh->m_textures[i])))
                                mesh->m_textures[i] = NULL;
                        }
                    }

            接著必須遍歷處理所有的ID3DXFileData子對象,首先需要調用ID3DXFileData::GetChildren來獲得ID3DXFileData子對象數。

            Retrieves the number of children in this file data object.

            HRESULT GetChildren(
            SIZE_T * puiChildren
            );

            Parameters

            puiChildren
            [in] Address of a pointer to receive the number of children in this file data object.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the following value will be returned: D3DXFERR_BADVALUE.

            接著調用ID3DXFileData::GetChild獲得ID3DXFileData子對象。

            Retrieves a child object in this file data object.

            HRESULT GetChild(
            SIZE_T uiChild,
            ID3DXFileData ** ppChild
            );

            Parameters

            uiChild
            [in] ID of the child object to retrieve.
            ppChild
            [in] Address of a pointer to receive the child object's interface pointer.

            Return Values

            If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following values: D3DXFERR_BADVALUE, D3DXFERR_NOMOREOBJECTS.

            然后遞歸調用Parse_XFile_Data來處理每個ID3DXFileData子對象,如下所示:

                SIZE_T num_child;
                xfile_data->GetChildren(&num_child);

                
            // scan for embedded templates
                for(SIZE_T i = 0; i < num_child; i++)
                {
                    xfile_data->GetChild(i, &sub_xfile_data);

                    
            // process embedded xfile data, recursive call.
                    Parse_XFile_Data(sub_xfile_data, sub_frame);

                    Release_Com(sub_xfile_data);
                }


            Parse_XFile_Data完整代碼示例如下:

             

            //--------------------------------------------------------------------------------
            // Parse specified xfiel data, recursive function.
            //--------------------------------------------------------------------------------
            void Parse_XFile_Data(ID3DXFileData* xfile_data, FRAME* parent_frame)
            {
                ID3DXFileData*  sub_xfile_data = NULL;
                ID3DXBuffer*    adjacency = NULL;

                GUID  type;
                
            char* name = NULL;
                DWORD size;

                MESH* mesh = NULL;
                ID3DXBuffer* material_buffer = NULL;
                D3DXMATERIAL* materials = NULL;

                
            // get the template type
                // retrieves the globally unique identifier (GUID) of the object's template
                if(FAILED(xfile_data->GetType(&type)))
                    
            return;

                
            // get the template name (if any)
                // retrieves a pointer to a microsoft directX file object's name
                if(FAILED(xfile_data->GetName(NULL, &size)))
                    
            return;

                
            if(size != 0)
                {
                    
            if((name = new char[size]) != NULL)
                        xfile_data->GetName(name, &size);
                }

                
            // give template a default name if none found
                if(name == NULL)
                {
                    
            if((name = new char[9]) == NULL)
                        
            return;

                    strcpy(name, "Template");
                }

                
            // set sub frame
                FRAME* sub_frame = parent_frame;

                
            // process the templates
                FRAME* frame = NULL;

                
            if(type == TID_D3DRMFrame)  // it is a frame
                {
                    
            // create a new frame structure
                    frame = new FRAME();

                    
            // store the name
                    frame->m_name = name;
                    name = NULL;

                    
            // add to parent frame
                    parent_frame->m_child = frame;

                    
            // set sub frame parent
                    sub_frame = frame;
                }
                
            else if(type == TID_D3DRMMesh)  // it is a mesh
                {
                    
            // create a new mesh structure
                    mesh = new MESH();

                    
            // store the name
                    mesh->m_name = name;
                    name = NULL;

                    
            // load mesh data (as a skinned mesh)
                    // loads a skin mesh from microsoft directX .x file data object
                    if(FAILED(D3DXLoadSkinMeshFromXof(xfile_data, 0, g_d3d_device, &adjacency, &material_buffer, NULL,
                        &mesh->m_num_materials, &mesh->m_skininfo, &mesh->m_mesh)))
                    {
                        delete[] name;
                        delete mesh;
                        
            return;
                    }

                    Release_Com(adjacency);

                    
            // clone skin mesh if bones exist
                    if(mesh->m_skininfo != NULL && mesh->m_skininfo->GetNumBones() != 0)
                    {
                        
            // clones a mesh using a flexible vertex format (FVF) code
                        if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), g_d3d_device, &mesh->m_skinmesh)))
                        {
                            mesh->m_skininfo->Release();
                            mesh->m_skininfo = NULL;
                        }
                    }

                    
            // load materials or create a default one if none
                    if(mesh->m_num_materials == 0)
                    {
                        
            // create a default one
                        mesh->m_materials = new D3DMATERIAL9[1];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[1];

                        ZeroMemory(mesh->m_materials, 
            sizeof(D3DMATERIAL9));

                        mesh->m_materials[0].Diffuse.r = 1.0;
                        mesh->m_materials[0].Diffuse.g = 1.0;
                        mesh->m_materials[0].Diffuse.b = 1.0;
                        mesh->m_materials[0].Diffuse.a = 1.0;
                        mesh->m_materials[0].Ambient   = mesh->m_materials[0].Diffuse;
                        mesh->m_materials[0].Specular  = mesh->m_materials[0].Diffuse;

                        mesh->m_textures[0] = NULL;

                        mesh->m_num_materials = 1;
                    }
                    
            else
                    {
                        
            // load the materials
                        materials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();

                        mesh->m_materials = 
            new D3DMATERIAL9[mesh->m_num_materials];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[mesh->m_num_materials];

                        
            // set materials and textures for mesh
                        for(DWORD i = 0; i < mesh->m_num_materials; i++)
                        {
                            mesh->m_materials[i] = materials[i].MatD3D;
                            mesh->m_materials[i].Ambient = mesh->m_materials[i].Diffuse;

                            
            // build a texture path and load it
                            if(FAILED(D3DXCreateTextureFromFile(g_d3d_device, materials[i].pTextureFilename, &mesh->m_textures[i])))
                                mesh->m_textures[i] = NULL;
                        }
                    }

                    Release_Com(material_buffer);

                    
            // set mesh to parent frame
                    parent_frame->m_mesh = mesh;
                }   
            // end if(type == TID_D3DRMMesh)
                else if(type == TID_D3DRMAnimationSet || type == TID_D3DRMAnimation || type == TID_D3DRMAnimationKey)
                {
                    
            // skip animation sets and animations
                    delete[] name;
                    
            return;
                }

                
            // release name buffer
                delete[] name;

                SIZE_T num_child;
                xfile_data->GetChildren(&num_child);

                
            // scan for embedded templates
                for(SIZE_T i = 0; i < num_child; i++)
                {
                    xfile_data->GetChild(i, &sub_xfile_data);

                    
            // process embedded xfile data, recursive call.
                    Parse_XFile_Data(sub_xfile_data, sub_frame);

                    Release_Com(sub_xfile_data);
                }
            }

            Parse_XFile和Parse_XFile_Data協同工作以解析.X文件里的每個數據對象,Parse_XFile功能函數打開.X文件并枚舉它,以查找層次結構中最頂層的對象,每個被找到的對象都將被傳遞給Parse_XFile_Data功能函數。 Parse_XFile_Data功能函數負責處理數據對象,它從獲取對象的類型以及對象的實例名(如果有的話)開始進行處理。從那里,可以處理對象數據,然后遞歸地調用功能函數以便枚舉所有的子對象,這個處理過程持續不斷,直到所有的數據對象都被處理。

            網格模型和D3DX

            基本上,在Direct3D中使用到兩種類型的網格模型,標準網格模型(standard mesh)和蒙皮網格模型(skinned mesh)。所謂的標準網格模型,除了可以使用紋理映射以增強外觀外,它沒有什么花哨的功能。蒙皮網格模型的獨特之處在于它們是可變形的 (deformable),也就是說,網格模型可以在運行當中動態地改變它的形狀。為網格模型的變形做準備,必須在三維建模程序中將網格模型的頂點附屬到一個虛構的骨骼集中,在任何骨骼移動的時候,附屬其上的頂點也將跟著移動。

            ID3DXBuffer對象

            ID3DXBuffer 對象用于存儲并檢索數據的緩沖區,D3DX使用ID3DXBuffer對象去存儲網格模型所涉及的信息,例如材質和紋理映射的列表。 ID3DXBuffer僅有兩個功能函數。第1個功能函數是ID3DXBuffer::GetBufferPointer,可以使用它去獲取一個只想包含在對象緩沖區里的數據的指針。 GetBufferPointer功能函數的調用將返回一個可以強制轉換成任何數據類型的指針:

            Retrieves a pointer to the data in the buffer.

            LPVOID GetBufferPointer(VOID);

            第2個功能函數是ID3DXBuffer:: GetBufferSize,它返回存儲數據所需的字節數。

            Retrieves the total size of the data in the buffer.

            DWORD GetBufferSize(VOID);

            標準網格模型

            一個標準的網格模型十分簡單,它僅包含一個單一網格模型的定義,使用D3DX來處理標準網格模型尤其容易,因為D3DX僅要求使用一個簡短的代碼序列去裝載并顯示標準網格模型,標準網格模型有一個 ID3DXMESH對象表示,它的任務就是存儲并繪制一個單一的網格模型。

            在實例化一個ID3DXMESH對象后,使用下面的功能函數從.X文件中加載網格模型的對象。

            Loads a mesh from an ID3DXFileData object.

            HRESULT D3DXLoadMeshFromXof(
            LPD3DXFILEDATA pxofMesh,
            DWORD Options,
            LPDIRECT3DDEVICE9 pDevice,
            LPD3DXBUFFER * ppAdjacency,
            LPD3DXBUFFER * ppMaterials,
            LPD3DXBUFFER * ppEffectInstances,
            DWORD * pNumMaterials,
            LPD3DXMESH * ppMesh
            );

            Parameters

            pxofMesh
            [in] Pointer to an ID3DXFileData interface, representing the file data object to load.
            Options
            [out] Combination of one or more flags from the D3DXMESH enumeration, specifying creation options for the mesh.
            pDevice
            [in] Pointer to an IDirect3DDevice9 interface, the device object associated with the mesh.
            ppAdjacency
            [out] Pointer to a buffer that contains adjacency data. The adjacency data contains an array of three DWORDs per face that specify the three neighbors for each face in the mesh. For more information about accessing the buffer, see ID3DXBuffer.
            ppMaterials
            [in, out] Address of a pointer to an ID3DXBuffer interface. When the method returns, this parameter is filled with an array of D3DXMATERIAL structures.
            ppEffectInstances
            [out] Pointer to a buffer containing an array of effect instances, one per attribute group in the returned mesh. An effect instance is a particular instance of state information used to initialize an effect. See D3DXEFFECTINSTANCE. For more information about accessing the buffer, see ID3DXBuffer.
            pNumMaterials
            [in, out] Pointer to the number of D3DXMATERIAL structures in the ppMaterials array, when the method returns.
            ppMesh
            [out, retval] Address of a pointer to an ID3DXMesh interface, representing the loaded mesh.

            Return Values

            If the function succeeds, the return value is D3D_OK. If the function fails, the return value can be one of the following: D3DERR_INVALIDCALL.

            D3DXERR_INVALIDDATA E_OUTOFMEMORY

            Remarks

            For mesh files that do not contain effect instance information, default effect instances will be generated from the material information in the .x file. A default effect instance will have default values that correspond to the members of the D3DMATERIAL9 structure.

            The default texture name is also filled in, but is handled differently. The name will be Texture0@Name, which corresponds to an effect variable by the name of "Texture0" with an annotation called "Name." This will contain the string file name for the texture.


            D3DXLoadMeshFromXof函數里的大多數參數是在執行期間由D3DX來填入的,用戶只需提供所加載的.X文件名,一個預初始化的ID3DXBuffer和ID3DXMesh對象,以及一個DWORD變量去存儲在網格模型中所使用的材質的數量。

            渲染網格模型

            ID3DXMesh 對象的核心是一個稱之為 DrawSubset的渲染功能函數,它的工作是渲染網格模型的一個子集。一個子集(subset)就是一個網格模型的一個部分,它根據渲染的不同情況被分隔開來,例如不同材質或紋理的子集??梢詫⒁粋€網格模型分割成許多子集,程序員的工作就是去領會每個子集所代表的是什么,并渲染它。

            如下所示:使用子集分隔網格模型的不同部分。



            在加載好一個.X文件后,便獲得了一個網格模型對象以及它的材質。網格模型的子集與那些材質相關聯,所以如果在一個網格模型里有5種材質,那么網格模型就包含了5個要繪制的子集。子集的布置允許用戶能夠容易地渲染一個網格模型,只需要簡單地搜索每種材質,設置它,然后渲染子集,重復這些步驟直到繪制完整個網格實例。為了定位世界中的網格模型,需要在進行繪制之前設置世界變換矩陣。

            示例代碼如下:

                   // render the mesh
                    for(DWORD i = 0; i < mesh->m_num_materials; i++)
                    {
                        
            // set the materials properties for the device
                        g_d3d_device->SetMaterial(&mesh->m_materials[i]);

                        
            // assigns a texture to a stage for a device
                        g_d3d_device->SetTexture(0, mesh->m_textures[i]);

                        
            // draw a subset of a mesh
                        mesh_to_draw->DrawSubset(i);
                    }
             

            蒙皮網格模型

            Direct3D中一個最令人興奮的就是蒙皮網格模型,一個蒙皮網格模型可以動態地改變形狀。通過連接那些構造“骨骼”底層結構中網格模型的各自頂點,或框架層次來實現它。一個蒙皮網格模型使用骨骼去定義它的輪廓,當骨骼移動時,網格模型改變形狀以便與之相匹配。骨骼在一個.X文件里被表示為一個框架層次,當構造網格模型時,以一種父與子的形式來連接框架。當一個父框架被重新定向時,所有附屬其上的子框架繼承父框架的變換,并兼有它們自身的變換,這使得動畫的實現更加容易,只需移動一個框架,其所有附屬框架也將相應地移動。

            要加載并使用一個蒙皮網格模型,可以直接處理.X文件的數據對象。枚舉包含在一個.X文件里的網格模型的數據對象時,需要調用各種不同的D3DX網格模型加載功能函數去處理那些對象數據。當加載蒙皮網格模型時,要用到的一個功能函數就是 D3DXLoadSkinMeshFromXof。這個功能函數的作用就是從.X文件里讀取網格模型的數據對象,創建一個包含網格模型的 ID3DXMesh對象,同時創建一個ID3DXSkinInfo對象,該對象描述了網格模型變形所需要的骨骼到頂點的連接數據。

            來看看ID3DXSkinInfo的具體定義:

            Applications use the methods of the ID3DXSkinInfo interface to manipulate bone matrices, which are used to skin vertex data for animation. This interface is no longer strictly tied to ID3DXMesh and can be used to skin any set of vertex data.

            ID3DXSkinInfo Members

            Method Description
            ID3DXSkinInfo::Clone Clones a skin info object.
            ID3DXSkinInfo::ConvertToBlendedMesh Takes a mesh and returns a new mesh with per-vertex blend weights and a bone combination table. The table describes which bones affect which subsets of the mesh.
            ID3DXSkinInfo::ConvertToIndexedBlendedMesh Takes a mesh and returns a new mesh with per-vertex blend weights, indices, and a bone combination table. The table describes which bone palettes affect which subsets of the mesh.
            ID3DXSkinInfo::FindBoneVertexInfluenceIndex Retrieves the index of the bone influence affecting a single vertex.
            ID3DXSkinInfo::GetBoneInfluence Gets the vertices and weights that a bone influences.
            ID3DXSkinInfo::GetBoneName Gets the bone name, from the bone index.
            ID3DXSkinInfo::GetBoneOffsetMatrix Gets the bone offset matrix.
            ID3DXSkinInfo::GetBoneVertexInfluence Retrieves the blend factor and vertex affected by a specified bone influence.
            ID3DXSkinInfo::GetDeclaration Gets the vertex declaration.
            ID3DXSkinInfo::GetFVF Gets the fixed function vertex value.
            ID3DXSkinInfo::GetMaxFaceInfluences Gets the maximum face influences in a triangle mesh with the specified index buffer.
            ID3DXSkinInfo::GetMaxVertexInfluences Gets the maximum number of influences for any vertex in the mesh.
            ID3DXSkinInfo::GetMinBoneInfluence Gets the minimum bone influence. Influence values smaller than this are ignored.
            ID3DXSkinInfo::GetNumBoneInfluences Gets the number of influences for a bone.
            ID3DXSkinInfo::GetNumBones Gets the number of bones.
            ID3DXSkinInfo::Remap Updates bone influence information to match vertices after they are reordered. This method should be called if the target vertex buffer has been reordered externally.
            ID3DXSkinInfo::SetBoneInfluence Sets the influence value for a bone.
            ID3DXSkinInfo::SetBoneName Sets the bone name.
            ID3DXSkinInfo::SetBoneOffsetMatrix Sets the bone offset matrix.
            ID3DXSkinInfo::SetBoneVertexInfluence Sets an influence value of a bone on a single vertex.
            ID3DXSkinInfo::SetDeclaration Sets the vertex declaration.
            ID3DXSkinInfo::SetFVF Sets the flexible vertex format (FVF) type.
            ID3DXSkinInfo::SetMinBoneInfluence Sets the minimum bone influence. Influence values smaller than this are ignored.
            ID3DXSkinInfo::UpdateSkinnedMesh Applies software skinning to the target vertices based on the current matrices.

            Remarks

            Create a ID3DXSkinInfo interface with D3DXCreateSkinInfo, D3DXCreateSkinInfoFromBlendedMesh, or D3DXCreateSkinInfoFVF.

            The LPD3DXSKININFO type is defined as a pointer to the ID3DXSkinInfo interface.

            typedef struct ID3DXSkinInfo *LPD3DXSKININFO;


            要使用蒙皮網格模型,需要創建兩個網格模型容器。第一個網格模型負責從.X文件進行加載的工作,它確實是一個標準的網格模型,使用了一個ID3DXMesh對象去包含網格模型的信息。在這里要做的就是去克隆(復制)該網格模型,以便渲染變形后的蒙皮網格模型。

            為了創建這個克隆的網格模型,調用網格模型的CloneMeshFVF功能函數:

            Clones a mesh using a flexible vertex format (FVF) code.

            HRESULT CloneMeshFVF(
            DWORD Options,
            DWORD FVF,
            LPDIRECT3DDEVICE9 pDevice,
            LPD3DXMESH * ppCloneMesh
            );

            Parameters

            Options
            [in] A combination of one or more D3DXMESH flags specifying creation options for the mesh.
            FVF
            [in] Combination of FVF codes, which specifies the vertex format for the vertices in the output mesh. For the values of the codes, see D3DFVF.
            pDevice
            [in] Pointer to an IDirect3DDevice9 interface representing the device object associated with the mesh.
            ppCloneMesh
            [out, retval] Address of a pointer to an ID3DXMesh interface, representing the cloned mesh.

            Return Values

            If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be one of the following: D3DERR_INVALIDCALL, E_OUTOFMEMORY.

            Remarks

            ID3DXBaseMesh::CloneMeshFVF is used to reformat and change the vertex data layout. This is done by creating a new mesh object. For example, use it to to add space for normals, texture coordinates, colors, weights, etc. that were not present before.

            ID3DXBaseMesh::UpdateSemantics updates the vertex declaration with different semantic information without changing the layout of the vertex buffer. This method does not modify the contents of the vertex buffer. For example, use it to relabel a 3D texture coordinate as a binormal or tangent or vice versa.


            可以這么使用這個函數:

                    // clone skin mesh if bones exist
                    if(mesh->m_skininfo != NULL && mesh->m_skininfo->GetNumBones() != 0)
                    {
                        
            // clones a mesh using a flexible vertex format (FVF) code
                        if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), g_d3d_device, &mesh->m_skinmesh)))
                        {
                            mesh->m_skininfo->Release();
                            mesh->m_skininfo = NULL;
                        }
                    }

            要修改骨骼的變換,必須構造一個D3DXMATRIX對象的數組(每個骨骼都有一個矩陣)。因此,如果蒙皮網格模型使用了10塊骨骼,那么就需要 10個D3DXMATRIX對象去包含每塊骨骼的變換。現在開始存儲每塊骨骼的各種各樣的變換,需要記住的重要事情就是,每塊骨骼都繼承了它的父框架的變換,因此,改變一個骨骼的定位時,存在某種程度的連鎖效應。

            一旦使用了變換,就能更新蒙皮網格模型的頂點并渲染網格模型,為了更新蒙皮網格模型,需要鎖定初始網格模型和蒙皮網格模型的(所克隆的輔助網格模型)頂點緩沖區:
             
            void* source = NULL;
            void* dest = NULL;

            // locks a vertex buffer and obtains a pointer to the vertex buffer memory
            mesh->m_mesh->LockVertexBuffer(0, &source);
            mesh->m_skinmesh->LockVertexBuffer(0, &dest);

            一旦鎖定,調用ID3DXSkinInfo::UpdateSkinnedMesh功能函數去變換蒙皮網格模型里的所有頂點,以便匹配在D3DXMATRIX數組里所設置的骨骼的方向。

            來看看ID3DXSkinInfo::UpdateSkinnedMesh的具體使用信息:

            Applies software skinning to the target vertices based on the current matrices.

            HRESULT UpdateSkinnedMesh(
            CONST D3DXMATRIX * pBoneTransforms,
            CONST D3DXMATRIX * pBoneInvTransposeTransforms,
            LPCVOID pVerticesSrc,
            PVOID pVerticesDst
            );

            Parameters

            pBoneTransforms
            [in] Bone transform matrix.
            pBoneInvTransposeTransforms
            [in] Inverse transpose of the bone transform matrix.
            pVerticesSrc
            [in] Pointer to the buffer containing the source vertices.
            pVerticesDst
            [in] Pointer to the buffer containing the destination vertices.

            Return Values

            If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.

            Remarks

            When used to skin vertices with two position elements, this method skins the second position element with the inverse of the bone instead of the bone itself.


             可以這么使用 ID3DXSkinInfo::UpdateSkinnedMesh。

            // update skinned mesh, applies software skinning to the target vertices based on the current matrices.
             mesh->m_skininfo->UpdateSkinnedMesh(matrices, NULL, source, dest);

            最后,解鎖頂點緩沖區:
             
            // unlock buffers
            mesh->m_skinmesh->UnlockVertexBuffer();
            mesh->m_mesh->UnlockVertexBuffer();
             

            以下代碼給出了如何繪制蒙皮網格:

            //--------------------------------------------------------------------------------
            // Draw current frame, recursive function.
            //--------------------------------------------------------------------------------
            void Draw_Frame(FRAME* frame)
            {
                MESH* mesh;
                D3DXMATRIX* matrices = NULL;
                ID3DXMesh* mesh_to_draw;

                
            // return if no frame
                if(frame == NULL)
                    
            return;

                
            // draw meshes if any in frame
                if((mesh = frame->m_mesh) != NULL)
                {
                    
            // setup pointer to mesh to draw
                    mesh_to_draw = mesh->m_mesh;

                    
            // generate mesh from skinned mesh to draw with
                    if(mesh->m_skinmesh != NULL && mesh->m_skininfo != NULL)
                    {
                        DWORD num_bones = mesh->m_skininfo->GetNumBones();

                        
            // allocate an array of matrices to orient bones
                        matrices = new D3DXMATRIX[num_bones];

                        
            // set all bones orientation to identity
                        for(DWORD i = 0; i < num_bones; i++)
                            D3DXMatrixIdentity(&matrices[i]);

                        
            // lock source and destination vertex buffers

                        
            void* source = NULL;
                        
            void* dest = NULL;

                        
            // locks a vertex buffer and obtains a pointer to the vertex buffer memory
                        mesh->m_mesh->LockVertexBuffer(0, &source);
                        mesh->m_skinmesh->LockVertexBuffer(0, &dest);

                        
            // update skinned mesh, applies software skinning to the target vertices based on the current matrices.
                        mesh->m_skininfo->UpdateSkinnedMesh(matrices, NULL, source, dest);

                        
            // unlock buffers
                        mesh->m_skinmesh->UnlockVertexBuffer();
                        mesh->m_mesh->UnlockVertexBuffer();

                        
            // point to skin mesh to draw
                        mesh_to_draw = mesh->m_skinmesh;
                    }

                    
            // render the mesh
                    for(DWORD i = 0; i < mesh->m_num_materials; i++)
                    {
                        
            // set the materials properties for the device
                        g_d3d_device->SetMaterial(&mesh->m_materials[i]);

                        
            // assigns a texture to a stage for a device
                        g_d3d_device->SetTexture(0, mesh->m_textures[i]);

                        
            // draw a subset of a mesh
                        mesh_to_draw->DrawSubset(i);
                    }

                    
            // free array of matrices
                    delete[] matrices;
                    matrices = NULL;
                }

                
            // draw child frames, recursively call.
                Draw_Frame(frame->m_child);
            }


            現在給出完整的示例代碼:

             
            /***************************************************************************************
            PURPOSE:
                XFile/Skinned Mesh Demo
             ***************************************************************************************/


            #include <windows.h>
            #include <stdio.h>
            #include "d3d9.h"
            #include "d3dx9.h"
            #include "DxFile.h"
            #include "RmxfGuid.h"
            #include "RmxfTmpl.h"

            #pragma comment(lib, "dxguid.lib")
            #pragma comment(lib, "winmm.lib")
            #pragma comment(lib, "d3d9.lib")
            #pragma comment(lib, "d3dx9.lib")
            #pragma comment(lib, "d3dxof.lib")

            #pragma warning(disable : 4305 4996)

            #define WINDOW_WIDTH    400
            #define WINDOW_HEIGHT   400

            #define Safe_Release(p) if(p) (p)->Release();
            #define Release_Com(p)  if(p)  { (p)->Release(); (p) = NULL; }

            // window handles, class and caption text.
            HWND g_hwnd;
            HINSTANCE g_inst;
            static char g_class_name[] = "XFileClass";
            static char g_caption[]    = "XFile Demo";

            // the Direct3D and device object
            IDirect3D9* g_d3d = NULL;
            IDirect3DDevice9* g_d3d_device = NULL;

            //------------------------------------------------------------------
            // A Mesh definition structure
            //------------------------------------------------------------------
            typedef struct MESH
            {
                
            char*               m_name;             // name of mesh

                ID3DXMesh*          m_mesh;             
            // mesh object
                ID3DXMesh*          m_skinmesh;         // skin mesh object
                ID3DXSkinInfo*      m_skininfo;         // skin information

                DWORD               m_num_materials;    
            // number of materails in mesh
                D3DMATERIAL9*       m_materials;        // array of materials
                IDirect3DTexture9** m_textures;         // array of textures    

                // clear all structure data
                MESH()
                {
                    m_name  = NULL;     

                    m_mesh      = NULL;
                    m_skinmesh  = NULL;
                    m_skininfo  = NULL;

                    m_num_materials = 0;
                    m_materials     = NULL;
                    m_textures      = NULL;               
                }

                
            // free all used resources
                ~MESH()
                {        
                    delete[] m_name;
                    m_name = NULL;

                    Release_Com(m_mesh);
                    Release_Com(m_skinmesh);
                    Release_Com(m_skininfo);

                    delete[] m_materials;
                    m_materials = NULL;
                    
                    
            // release all textures resource
                    if(m_textures != NULL)
                    {
                        
            for(DWORD i = 0; i < m_num_materials; i++)
                            Release_Com(m_textures[i]);

                        delete[] m_textures;
                        m_textures = NULL;
                    }
                }

            } MESH;

            //------------------------------------------------------------------
            // Structure to contain frame information
            //------------------------------------------------------------------
            typedef struct FRAME
            {
                
            char*   m_name;     // frame's name
                MESH*   m_mesh;     // linked list of meshes    
                FRAME*  m_child;    // child frame

                FRAME()
                {
                    
            // clear all data
                    m_name = NULL;
                    m_mesh = NULL;
                    m_child = NULL;
                }

                ~FRAME()
                {
                    
            // delete all used resources, including linked list of frames.
                    delete[] m_name;    m_name    = NULL;
                    delete m_mesh;      m_mesh    = NULL;
                    delete m_child;     m_child   = NULL;        
                }

            } FRAME;

            // parent frame for .X file
            FRAME* g_parent_frame = NULL;

            //--------------------------------------------------------------------------------
            // Window procedure.
            //--------------------------------------------------------------------------------
            long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
            {
                
            switch(msg)
                {
                
            case WM_DESTROY:
                    PostQuitMessage(0);
                    
            return 0;
                }

                
            return (long) DefWindowProc(hwnd, msg, wParam, lParam);
            }

            //--------------------------------------------------------------------------------
            // Parse specified xfiel data, recursive function.
            //--------------------------------------------------------------------------------
            void Parse_XFile_Data(ID3DXFileData* xfile_data, FRAME* parent_frame)
            {
                ID3DXFileData*  sub_xfile_data = NULL;
                ID3DXBuffer*    adjacency = NULL;

                GUID  type;
                
            char* name = NULL;
                DWORD size;

                MESH* mesh = NULL;
                ID3DXBuffer* material_buffer = NULL;
                D3DXMATERIAL* materials = NULL;

                
            // get the template type
                // retrieves the globally unique identifier (GUID) of the object's template
                if(FAILED(xfile_data->GetType(&type)))
                    
            return;

                
            // get the template name (if any)
                // retrieves a pointer to a microsoft directX file object's name
                if(FAILED(xfile_data->GetName(NULL, &size)))
                    
            return;

                
            if(size != 0)
                {
                    
            if((name = new char[size]) != NULL)
                        xfile_data->GetName(name, &size);
                }

                
            // give template a default name if none found
                if(name == NULL)
                {
                    
            if((name = new char[9]) == NULL)
                        
            return;

                    strcpy(name, "Template");
                }

                
            // set sub frame
                FRAME* sub_frame = parent_frame;

                
            // process the templates
                FRAME* frame = NULL;

                
            if(type == TID_D3DRMFrame)  // it is a frame
                {
                    
            // create a new frame structure
                    frame = new FRAME();

                    
            // store the name
                    frame->m_name = name;
                    name = NULL;

                    
            // add to parent frame
                    parent_frame->m_child = frame;

                    
            // set sub frame parent
                    sub_frame = frame;
                }
                
            else if(type == TID_D3DRMMesh)  // it is a mesh
                {
                    
            // create a new mesh structure
                    mesh = new MESH();

                    
            // store the name
                    mesh->m_name = name;
                    name = NULL;

                    
            // load mesh data (as a skinned mesh)
                    // loads a skin mesh from microsoft directX .x file data object
                    if(FAILED(D3DXLoadSkinMeshFromXof(xfile_data, 0, g_d3d_device, &adjacency, &material_buffer, NULL,
                        &mesh->m_num_materials, &mesh->m_skininfo, &mesh->m_mesh)))
                    {
                        delete[] name;
                        delete mesh;
                        
            return;
                    }

                    Release_Com(adjacency);

                    
            // clone skin mesh if bones exist
                    if(mesh->m_skininfo != NULL && mesh->m_skininfo->GetNumBones() != 0)
                    {
                        
            // clones a mesh using a flexible vertex format (FVF) code
                        if(FAILED(mesh->m_mesh->CloneMeshFVF(0, mesh->m_mesh->GetFVF(), g_d3d_device, &mesh->m_skinmesh)))
                        {
                            mesh->m_skininfo->Release();
                            mesh->m_skininfo = NULL;
                        }
                    }

                    
            // load materials or create a default one if none
                    if(mesh->m_num_materials == 0)
                    {
                        
            // create a default one
                        mesh->m_materials = new D3DMATERIAL9[1];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[1];

                        ZeroMemory(mesh->m_materials, 
            sizeof(D3DMATERIAL9));

                        mesh->m_materials[0].Diffuse.r = 1.0;
                        mesh->m_materials[0].Diffuse.g = 1.0;
                        mesh->m_materials[0].Diffuse.b = 1.0;
                        mesh->m_materials[0].Diffuse.a = 1.0;
                        mesh->m_materials[0].Ambient   = mesh->m_materials[0].Diffuse;
                        mesh->m_materials[0].Specular  = mesh->m_materials[0].Diffuse;

                        mesh->m_textures[0] = NULL;

                        mesh->m_num_materials = 1;
                    }
                    
            else
                    {
                        
            // load the materials
                        materials = (D3DXMATERIAL*) material_buffer->GetBufferPointer();

                        mesh->m_materials = 
            new D3DMATERIAL9[mesh->m_num_materials];
                        mesh->m_textures  = 
            new LPDIRECT3DTEXTURE9[mesh->m_num_materials];

                        
            // set materials and textures for mesh
                        for(DWORD i = 0; i < mesh->m_num_materials; i++)
                        {
                            mesh->m_materials[i] = materials[i].MatD3D;
                            mesh->m_materials[i].Ambient = mesh->m_materials[i].Diffuse;

                            
            // build a texture path and load it
                            if(FAILED(D3DXCreateTextureFromFile(g_d3d_device, materials[i].pTextureFilename, &mesh->m_textures[i])))
                                mesh->m_textures[i] = NULL;
                        }
                    }

                    Release_Com(material_buffer);

                    
            // set mesh to parent frame
                    parent_frame->m_mesh = mesh;
                }   
            // end if(type == TID_D3DRMMesh)
                else if(type == TID_D3DRMAnimationSet || type == TID_D3DRMAnimation || type == TID_D3DRMAnimationKey)
                {
                    
            // skip animation sets and animations
                    delete[] name;
                    
            return;
                }

                
            // release name buffer
                delete[] name;

                SIZE_T num_child;
                xfile_data->GetChildren(&num_child);

                
            // scan for embedded templates
                for(SIZE_T i = 0; i < num_child; i++)
                {
                    xfile_data->GetChild(i, &sub_xfile_data);

                    
            // process embedded xfile data, recursive call.
                    Parse_XFile_Data(sub_xfile_data, sub_frame);

                    Release_Com(sub_xfile_data);
                }
            }

            //--------------------------------------------------------------------------------
            // Parse x file, and return root frame.
            //--------------------------------------------------------------------------------
            FRAME* Parse_XFile(char* filename)
            {
                ID3DXFile* xfile = NULL;
                ID3DXFileEnumObject* xfile_enum = NULL;
                ID3DXFileData* xfile_data = NULL;

                
            // create the file object
                if(FAILED(D3DXFileCreate(&xfile)))
                    
            return NULL;

                
            // register the templates
                if(FAILED(xfile->RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES)))
                {
                    xfile->Release();
                    
            return NULL;
                }

                
            // create an enumerator object that will read a .x file
                if(FAILED(xfile->CreateEnumObject((LPVOID) filename, DXFILELOAD_FROMFILE, &xfile_enum)))
                {
                    xfile->Release();
                    
            return NULL;
                }

                
            // allocate a frame that becomes root
                FRAME* frame = new FRAME();

                SIZE_T num_child;

                
            // retrieve the number of children in this file data object
                xfile_enum->GetChildren(&num_child);

                
            // loop through all objects looking for the frames and meshes
                for(SIZE_T i = 0; i < num_child; i++)
                {
                    
            // retrieves a child object in this file data object
                    if(FAILED(xfile_enum->GetChild(i, &xfile_data)))
                        
            return NULL;

                    
            // parse xfile data
                    Parse_XFile_Data(xfile_data, frame);

                    Release_Com(xfile_data);
                }

                
            // release xfile enumerator object and xfile object
                Release_Com(xfile_enum);
                Release_Com(xfile);

                
            // return root frame
                return frame;
            }

            //--------------------------------------------------------------------------------
            // Initialize d3d, d3d device, vertex buffer; set render state for d3d;
            // set perspective matrix and view matrix, load xfile.
            //--------------------------------------------------------------------------------
            BOOL Do_Init()
            {
                D3DPRESENT_PARAMETERS present_param;
                D3DDISPLAYMODE  display_mode;
                D3DXMATRIX mat_proj, mat_view;

                
            // do a windowed mode initialization of Direct3D
                if((g_d3d = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
                    
            return FALSE;

                
            // retrieves the current display mode of the adapter
                if(FAILED(g_d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &display_mode)))
                    
            return FALSE;

                ZeroMemory(&present_param, 
            sizeof(present_param));

                
            // initialize d3d presentation parameter
                present_param.Windowed               = TRUE;
                present_param.SwapEffect             = D3DSWAPEFFECT_DISCARD;
                present_param.BackBufferFormat       = display_mode.Format;
                present_param.EnableAutoDepthStencil = TRUE;
                present_param.AutoDepthStencilFormat = D3DFMT_D16;

                
            // creates a device to represent the display adapter
                if(FAILED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hwnd,
                                              D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_param, &g_d3d_device)))
                    
            return FALSE;     

                
            // set render state

                // disable d3d lighting
                g_d3d_device->SetRenderState(D3DRS_LIGHTING, FALSE);
                
            // enable z-buffer
                g_d3d_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

                
            // create and set the projection matrix

                // builds a left-handed perspective projection matrix based on a field of view
                D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4.0, 1.33333, 1.0, 1000.0);

                
            // sets a single device transformation-related state
                g_d3d_device->SetTransform(D3DTS_PROJECTION, &mat_proj);

                
            // create and set the view matrix
                D3DXMatrixLookAtLH(&mat_view, 
                                   &D3DXVECTOR3(0.0, 50.0, -150.0),
                                   &D3DXVECTOR3(0.0, 50.0,  0.0), 
                                   &D3DXVECTOR3(0.0, 1.0,   0.0));

                g_d3d_device->SetTransform(D3DTS_VIEW, &mat_view);

                
            // load a skinned mesh from an .X file
                g_parent_frame = Parse_XFile("warrior.x");

                
            return TRUE;
            }

            //--------------------------------------------------------------------------------
            // Release all d3d resource.
            //--------------------------------------------------------------------------------
            BOOL Do_Shutdown()
            {
                delete g_parent_frame;

                Safe_Release(g_d3d_device);
                Safe_Release(g_d3d);

                
            return TRUE;
            }

            //--------------------------------------------------------------------------------
            // Draw current frame, recursive function.
            //--------------------------------------------------------------------------------
            void Draw_Frame(FRAME* frame)
            {
                MESH* mesh;
                D3DXMATRIX* matrices = NULL;
                ID3DXMesh* mesh_to_draw;

                
            // return if no frame
                if(frame == NULL)
                    
            return;

                
            // draw meshes if any in frame
                if((mesh = frame->m_mesh) != NULL)
                {
                    
            // setup pointer to mesh to draw
                    mesh_to_draw = mesh->m_mesh;

                    
            // generate mesh from skinned mesh to draw with
                    if(mesh->m_skinmesh != NULL && mesh->m_skininfo != NULL)
                    {
                        DWORD num_bones = mesh->m_skininfo->GetNumBones();

                        
            // allocate an array of matrices to orient bones
                        matrices = new D3DXMATRIX[num_bones];

                        
            // set all bones orientation to identity
                        for(DWORD i = 0; i < num_bones; i++)
                            D3DXMatrixIdentity(&matrices[i]);

                        
            // lock source and destination vertex buffers

                        
            void* source = NULL;
                        
            void* dest = NULL;

                        
            // locks a vertex buffer and obtains a pointer to the vertex buffer memory
                        mesh->m_mesh->LockVertexBuffer(0, &source);
                        mesh->m_skinmesh->LockVertexBuffer(0, &dest);

                        
            // update skinned mesh, applies software skinning to the target vertices based on the current matrices.
                        mesh->m_skininfo->UpdateSkinnedMesh(matrices, NULL, source, dest);

                        
            // unlock buffers
                        mesh->m_skinmesh->UnlockVertexBuffer();
                        mesh->m_mesh->UnlockVertexBuffer();

                        
            // point to skin mesh to draw
                        mesh_to_draw = mesh->m_skinmesh;
                    }

                    
            // render the mesh
                    for(DWORD i = 0; i < mesh->m_num_materials; i++)
                    {
                        
            // set the materials properties for the device
                        g_d3d_device->SetMaterial(&mesh->m_materials[i]);

                        
            // assigns a texture to a stage for a device
                        g_d3d_device->SetTexture(0, mesh->m_textures[i]);

                        
            // draw a subset of a mesh
                        mesh_to_draw->DrawSubset(i);
                    }

                    
            // free array of matrices
                    delete[] matrices;
                    matrices = NULL;
                }

                
            // draw child frames, recursively call.
                Draw_Frame(frame->m_child);
            }

            //--------------------------------------------------------------------------------
            // Render a frame.
            //--------------------------------------------------------------------------------
            BOOL Do_Frame()
            {
                D3DXMATRIX mat_world;

                
            // clear device back buffer
                g_d3d_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0, 64, 128, 255), 1.0f, 0);

                
            // Begin scene
                if(SUCCEEDED(g_d3d_device->BeginScene()))
                {
                    
            // create and set the world transformation matrix
                    // rotate object along y-axis
                    D3DXMatrixRotationY(&mat_world, (float) (timeGetTime() / 1000.0));
                    
                    g_d3d_device->SetTransform(D3DTS_WORLD, &mat_world);              

                    
            // draw frames
                    Draw_Frame(g_parent_frame);

                    
            // end the scene
                    g_d3d_device->EndScene();
                }

                
            // present the contents of the next buffer in the sequence of back buffers owned by the device
                g_d3d_device->Present(NULL, NULL, NULL, NULL);

                
            // release texture
                g_d3d_device->SetTexture(0, NULL);

                
            return TRUE;
            }

            //--------------------------------------------------------------------------------
            // Main function, routine entry.
            //--------------------------------------------------------------------------------
            int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
            {
                WNDCLASSEX  win_class;
                MSG         msg;

                g_inst = inst;

                
            // create window class and register it
                win_class.cbSize        = sizeof(win_class);
                win_class.style         = CS_CLASSDC;
                win_class.lpfnWndProc   = Window_Proc;
                win_class.cbClsExtra    = 0;
                win_class.cbWndExtra    = 0;
                win_class.hInstance     = inst;
                win_class.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
                win_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
                win_class.hbrBackground = NULL;
                win_class.lpszMenuName  = NULL;
                win_class.lpszClassName = g_class_name;
                win_class.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

                
            if(! RegisterClassEx(&win_class))
                    
            return FALSE;

                
            // create the main window
                g_hwnd = CreateWindow(g_class_name, g_caption, WS_CAPTION | WS_SYSMENU, 0, 0,
                                      WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, inst, NULL);

                
            if(g_hwnd == NULL)
                    
            return FALSE;

                ShowWindow(g_hwnd, SW_NORMAL);
                UpdateWindow(g_hwnd);

                
            // initialize game
                if(Do_Init() == FALSE)
                    
            return FALSE;

                
            // start message pump, waiting for signal to quit.
                ZeroMemory(&msg, sizeof(MSG));

                
            while(msg.message != WM_QUIT)
                {
                    
            if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                    
                    
            // draw a frame
                    if(Do_Frame() == FALSE)
                        
            break;
                }

                
            // run shutdown function
                Do_Shutdown();

                UnregisterClass(g_class_name, inst);
                
                
            return (int) msg.wParam;
            }


            運行效果:


             

            posted on 2007-07-22 23:27 lovedday 閱讀(4980) 評論(2)  編輯 收藏 引用 所屬分類: ■ DirectX 9 Program

            評論

            # re: D3D中網格模型的運用 2007-09-25 20:15 niyongfu

            請問你用的directx sdk是那一個版本啊~~
            我的和這個程序不兼容啊  回復  更多評論   

            # re: D3D中網格模型的運用 2007-09-25 22:28 lovedday

            Microsoft DirectX SDK (April 2007)

            到這個網頁給出的鏈接下載:

            http://www.shnenglu.com/lovedday/archive/2007/05/15/24156.html  回復  更多評論   

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            三级韩国一区久久二区综合| 欧美一级久久久久久久大| 欧美久久久久久精选9999| AV无码久久久久不卡蜜桃| 国产色综合久久无码有码| 日本精品久久久久影院日本| 88久久精品无码一区二区毛片 | 久久婷婷人人澡人人| 一本一道久久精品综合| 久久精品嫩草影院| 久久se精品一区二区| 天天爽天天爽天天片a久久网| 精品久久久久久综合日本| 欧美一区二区三区久久综合| 精品熟女少妇av免费久久| 97精品久久天干天天天按摩| 7777久久亚洲中文字幕| 久久精品国产精品亚洲精品| 国产精品免费久久久久影院| 久久精品国产一区二区 | 久久久久免费视频| 国产三级精品久久| 久久综合伊人77777麻豆| 欧美亚洲国产精品久久久久| 亚洲午夜久久久久妓女影院| 久久精品毛片免费观看| 伊人色综合久久天天| 国产精品久久久久一区二区三区 | 久久久久亚洲AV成人片| 香蕉久久一区二区不卡无毒影院| 国产精品99久久久久久猫咪 | 中文成人无码精品久久久不卡| 久久久久久精品无码人妻| 久久丫精品国产亚洲av| 国产精品99久久久久久猫咪| 中文精品99久久国产| 国产三级久久久精品麻豆三级 | 久久99热这里只有精品国产| 精品国产日韩久久亚洲| jizzjizz国产精品久久| 香蕉aa三级久久毛片|