點(diǎn)擊下載源碼和資源
在最底層的層次中,Direct3D并不使用網(wǎng)格模型,而只是使用多邊形。D3DX增強(qiáng)了
Direct3D系統(tǒng)的功能性,添加了一系列負(fù)責(zé)處理網(wǎng)格模型的容器和進(jìn)行渲染的對(duì)象。.X文件是微軟公司所開(kāi)發(fā)的,高度通用的三維模型存儲(chǔ)格式。它是模板驅(qū)動(dòng)并完全可擴(kuò)展,這就意味著可以使用它來(lái)滿(mǎn)足文件存儲(chǔ)的所有需求。一個(gè).X文件,正如它的文件擴(kuò)展名所表明的,是非常通用的。它可以是基于文本的,以便更容易進(jìn)行編輯;或者是基于二進(jìn)制的,這樣可以使文件更小,并且更容易地進(jìn)行保護(hù)以便不被窺視。整個(gè).X文件格式是基于模板的,非常類(lèi)似于C語(yǔ)言結(jié)構(gòu)。
為了讀取并處理一個(gè).X文件,可以利用COM對(duì)象的一個(gè)小集合來(lái)解析從頭到尾在.X文件中所遇到的每個(gè)數(shù)據(jù)對(duì)象。將數(shù)據(jù)對(duì)象作為一個(gè)字節(jié)的數(shù)組進(jìn)行處理;僅僅是將數(shù)組轉(zhuǎn)換為一種可使用的結(jié)構(gòu),以便能夠容易地訪問(wèn)到包含在對(duì)象里的數(shù)據(jù)。
根據(jù)存儲(chǔ)在.X文件里的內(nèi)容,這些對(duì)象可以改變。在這里,對(duì)象代表了網(wǎng)格模型以及網(wǎng)格模型相關(guān)的數(shù)據(jù)(例如骨骼結(jié)構(gòu),所謂的框架層次和動(dòng)畫(huà)數(shù)據(jù))。程序員的工作就是去解析這些對(duì)象,加載網(wǎng)格模型數(shù)據(jù),創(chuàng)建動(dòng)畫(huà)表格,并構(gòu)造框架的層次。
.X文件格式的詳細(xì)介紹請(qǐng)參閱
XFile網(wǎng)格的應(yīng)用(1),創(chuàng)建網(wǎng)格的具體API函數(shù)和方法請(qǐng)參閱
XFile網(wǎng)格的應(yīng)用(2),
XFile網(wǎng)格的應(yīng)用(3)。
框架層次的運(yùn)用
使用框架模板(frame
template)將一個(gè)或多個(gè)數(shù)據(jù)對(duì)象(通常為網(wǎng)格模型)進(jìn)行分組,以便能夠更容易地進(jìn)行處理。也可以創(chuàng)建一個(gè)網(wǎng)格模型,并使用多個(gè)框架去包含網(wǎng)格模型引用,這樣就能夠?qū)σ粋€(gè)網(wǎng)格模型使用許多次。一個(gè)框架層次(frame
hierarchy)定義了一個(gè)場(chǎng)景的結(jié)構(gòu),或者網(wǎng)格模型的分組,每當(dāng)一個(gè)框架移動(dòng)時(shí),所有嵌入其中的框架也同樣產(chǎn)生移動(dòng)。根沒(méi)有父框架,意味著他就是層次的頂端,且不屬于任何別的框架。被連接到其他框架上的框架稱(chēng)之為子框架(child
frames)(也可以稱(chēng)之為節(jié)點(diǎn)(node))。
當(dāng)一個(gè)框架移動(dòng)時(shí),它的所有子框架也隨之移動(dòng)。例如如果移動(dòng)上臂,前臂和手也跟著移動(dòng),而另一方面,如果移動(dòng)人的手,只有手會(huì)改變位置,因?yàn)樗鼪](méi)有子框架(前臂是手的父框架)。每個(gè)框架都有它自己的方位,在.X文件的術(shù)語(yǔ)中稱(chēng)之為框架變換(frame
transformation)。將這種變換運(yùn)用到較高層次的對(duì)象上,每個(gè)變換將被傳遞下去,從層次的頂端以各種方式到達(dá)每個(gè)子框架。
如下所示:骨架是骨骼框架層次的一個(gè)完美實(shí)例,層次中的每塊骨骼都連接到胸部。
框架層次是使用高級(jí)網(wǎng)格模型和動(dòng)畫(huà)技術(shù)的要點(diǎn),事實(shí)上,它們是某些運(yùn)用所必需的,諸如蒙皮網(wǎng)格模型。使用框架層次,另外一個(gè)原因是隔離場(chǎng)景其中一部分,以這種方式,可以通過(guò)移動(dòng)特定的框架來(lái)修改場(chǎng)景中的一小塊區(qū)域,而保留場(chǎng)景的其余部分。
解析.X文件
為了解析一個(gè).X文件,需要使用
ID3DXFile對(duì)象,它的工作就是打開(kāi)一個(gè).X文件并枚舉文件中的數(shù)據(jù)對(duì)象,再將他們以一種易于訪問(wèn)的方式展現(xiàn)給用戶(hù)。為了使用ID3DXFile組件,應(yīng)該包含dxfile.h,rmfxguid.h,rmfxtmpl.h,同時(shí)還必須將dxguid.lib和d3ddxof.lib庫(kù)鏈接到工程中。
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;
解析一個(gè).X文件并不像開(kāi)始時(shí)所看到的那樣困難,竅門(mén)就是搜索整個(gè)對(duì)象的層次,查找想要使用的數(shù)據(jù)對(duì)象,也就是網(wǎng)格模型和框架的對(duì)象。
最困難的部分是要記住那些嵌入到其他對(duì)象中的對(duì)象,因而可能會(huì)遇到對(duì)象的引用(需要解決它,以便能夠訪問(wèn)到原始的對(duì)象數(shù)據(jù)),而不是對(duì)象。
如下圖所示,.X文件允許用戶(hù)將模板對(duì)象嵌入到另一個(gè)模板對(duì)象中,從而創(chuàng)建出一個(gè)模板層次結(jié)構(gòu)。

可以通過(guò)D3DXFileCreate來(lái)創(chuàng)建ID3DXFile對(duì)象:
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.
創(chuàng)建完ID3DXFile對(duì)象后,首先需要通過(guò)ID3DXFile::RegisterTemplates來(lái)注冊(cè)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.
注冊(cè)完Mesh模板之后,需要調(diào)用ID3DXFile::CreateEnumObject來(lái)創(chuàng)建枚舉對(duì)象以枚舉訪問(wèn)各個(gè)具體的XFILE數(shù)據(jù)對(duì)象。
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.
來(lái)看看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;
創(chuàng)建完ID3DXFileEnumObject對(duì)象后,首先需要通過(guò)ID3DXFileEnumObject::GetChildren來(lái)取得子對(duì)象數(shù)。
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.
通過(guò)ID3DXFileEnumObject::GetChildren取得子對(duì)象數(shù)之后,可以遍歷循環(huán)所有的子對(duì)象并通過(guò)
ID3DXFileEnumObject::GetChild來(lái)取得指向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;
}
通過(guò)Parse_XFile打開(kāi).X文件并找到每個(gè)XFile數(shù)據(jù)對(duì)象后,就可以編寫(xiě)一個(gè)函數(shù)Parse_XFile_Data來(lái)解析這個(gè)XFile數(shù)據(jù)對(duì)象。
來(lái)看看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;
首先必須通過(guò)ID3DXFileData::GetType來(lái)獲得ID3DXFileData對(duì)象的模板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.
接著調(diào)用ID3DXFileData::GetName來(lái)獲得ID3DXFileData對(duì)象的名稱(chēng)。
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對(duì)象的類(lèi)型和名稱(chēng)后,就可以根據(jù)ID3DXFileData對(duì)象的類(lèi)型分別進(jìn)行不同的處理。
如果類(lèi)型是框架引用(TID_D3DRMFrame),則新建一個(gè)框架對(duì)象,并將新框架對(duì)象添加到父框架對(duì)象的子對(duì)象列表中
,并將當(dāng)前框架對(duì)象設(shè)置為新框架對(duì)象。
如果類(lèi)型是Mesh對(duì)象(TID_D3DRMMesh),則加載Mesh網(wǎng)格并將該網(wǎng)格添加到父框架的Mesh成員中。
如果是其他類(lèi)型,比如(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子對(duì)象,首先需要調(diào)用ID3DXFileData::GetChildren來(lái)獲得ID3DXFileData子對(duì)象數(shù)。
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.
接著調(diào)用ID3DXFileData::GetChild獲得ID3DXFileData子對(duì)象。
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.
然后遞歸調(diào)用Parse_XFile_Data來(lái)處理每個(gè)ID3DXFileData子對(duì)象,如下所示:
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協(xié)同工作以解析.X文件里的每個(gè)數(shù)據(jù)對(duì)象,Parse_XFile功能函數(shù)打開(kāi).X文件并枚舉它,以查找層次結(jié)構(gòu)中最頂層的對(duì)象,每個(gè)被找到的對(duì)象都將被傳遞給Parse_XFile_Data功能函數(shù)。
Parse_XFile_Data功能函數(shù)負(fù)責(zé)處理數(shù)據(jù)對(duì)象,它從獲取對(duì)象的類(lèi)型以及對(duì)象的實(shí)例名(如果有的話(huà))開(kāi)始進(jìn)行處理。從那里,可以處理對(duì)象數(shù)據(jù),然后遞歸地調(diào)用功能函數(shù)以便枚舉所有的子對(duì)象,這個(gè)處理過(guò)程持續(xù)不斷,直到所有的數(shù)據(jù)對(duì)象都被處理。
網(wǎng)格模型和D3DX
基本上,在Direct3D中使用到兩種類(lèi)型的網(wǎng)格模型,標(biāo)準(zhǔn)網(wǎng)格模型(standard mesh)和蒙皮網(wǎng)格模型(skinned
mesh)。所謂的標(biāo)準(zhǔn)網(wǎng)格模型,除了可以使用紋理映射以增強(qiáng)外觀外,它沒(méi)有什么花哨的功能。蒙皮網(wǎng)格模型的獨(dú)特之處在于它們是可變形的
(deformable),也就是說(shuō),網(wǎng)格模型可以在運(yùn)行當(dāng)中動(dòng)態(tài)地改變它的形狀。為網(wǎng)格模型的變形做準(zhǔn)備,必須在三維建模程序中將網(wǎng)格模型的頂點(diǎn)附屬到一個(gè)虛構(gòu)的骨骼集中,在任何骨骼移動(dòng)的時(shí)候,附屬其上的頂點(diǎn)也將跟著移動(dòng)。
ID3DXBuffer對(duì)象
ID3DXBuffer 對(duì)象用于存儲(chǔ)并檢索數(shù)據(jù)的緩沖區(qū),D3DX使用ID3DXBuffer對(duì)象去存儲(chǔ)網(wǎng)格模型所涉及的信息,例如材質(zhì)和紋理映射的列表。
ID3DXBuffer僅有兩個(gè)功能函數(shù)。第1個(gè)功能函數(shù)是ID3DXBuffer::GetBufferPointer,可以使用它去獲取一個(gè)只想包含在對(duì)象緩沖區(qū)里的數(shù)據(jù)的指針。
GetBufferPointer功能函數(shù)的調(diào)用將返回一個(gè)可以強(qiáng)制轉(zhuǎn)換成任何數(shù)據(jù)類(lèi)型的指針:
Retrieves a pointer to the data in the buffer.
LPVOID GetBufferPointer(VOID);
第2個(gè)功能函數(shù)是ID3DXBuffer:: GetBufferSize,它返回存儲(chǔ)數(shù)據(jù)所需的字節(jié)數(shù)。
Retrieves the total size of the data in the buffer.
DWORD GetBufferSize(VOID);
標(biāo)準(zhǔn)網(wǎng)格模型
一個(gè)標(biāo)準(zhǔn)的網(wǎng)格模型十分簡(jiǎn)單,它僅包含一個(gè)單一網(wǎng)格模型的定義,使用D3DX來(lái)處理標(biāo)準(zhǔn)網(wǎng)格模型尤其容易,因?yàn)镈3DX僅要求使用一個(gè)簡(jiǎn)短的代碼序列去裝載并顯示標(biāo)準(zhǔn)網(wǎng)格模型,標(biāo)準(zhǔn)網(wǎng)格模型有一個(gè)
ID3DXMESH對(duì)象表示,它的任務(wù)就是存儲(chǔ)并繪制一個(gè)單一的網(wǎng)格模型。
在實(shí)例化一個(gè)ID3DXMESH對(duì)象后,使用下面的功能函數(shù)從.X文件中加載網(wǎng)格模型的對(duì)象。
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函數(shù)里的大多數(shù)參數(shù)是在執(zhí)行期間由D3DX來(lái)填入的,用戶(hù)只需提供所加載的.X文件名,一個(gè)預(yù)初始化的ID3DXBuffer和ID3DXMesh對(duì)象,以及一個(gè)DWORD變量去存儲(chǔ)在網(wǎng)格模型中所使用的材質(zhì)的數(shù)量。
渲染網(wǎng)格模型
ID3DXMesh 對(duì)象的核心是一個(gè)稱(chēng)之為
DrawSubset的渲染功能函數(shù),它的工作是渲染網(wǎng)格模型的一個(gè)子集。一個(gè)子集(subset)就是一個(gè)網(wǎng)格模型的一個(gè)部分,它根據(jù)渲染的不同情況被分隔開(kāi)來(lái),例如不同材質(zhì)或紋理的子集。可以將一個(gè)網(wǎng)格模型分割成許多子集,程序員的工作就是去領(lǐng)會(huì)每個(gè)子集所代表的是什么,并渲染它。
如下所示:使用子集分隔網(wǎng)格模型的不同部分。

在加載好一個(gè).X文件后,便獲得了一個(gè)網(wǎng)格模型對(duì)象以及它的材質(zhì)。網(wǎng)格模型的子集與那些材質(zhì)相關(guān)聯(lián),所以如果在一個(gè)網(wǎng)格模型里有5種材質(zhì),那么網(wǎng)格模型就包含了5個(gè)要繪制的子集。子集的布置允許用戶(hù)能夠容易地渲染一個(gè)網(wǎng)格模型,只需要簡(jiǎn)單地搜索每種材質(zhì),設(shè)置它,然后渲染子集,重復(fù)這些步驟直到繪制完整個(gè)網(wǎng)格實(shí)例。為了定位世界中的網(wǎng)格模型,需要在進(jìn)行繪制之前設(shè)置世界變換矩陣。
示例代碼如下:
// 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);
}
蒙皮網(wǎng)格模型
Direct3D中一個(gè)最令人興奮的就是蒙皮網(wǎng)格模型,一個(gè)蒙皮網(wǎng)格模型可以動(dòng)態(tài)地改變形狀。通過(guò)連接那些構(gòu)造“骨骼”底層結(jié)構(gòu)中網(wǎng)格模型的各自頂點(diǎn),或框架層次來(lái)實(shí)現(xiàn)它。一個(gè)蒙皮網(wǎng)格模型使用骨骼去定義它的輪廓,當(dāng)骨骼移動(dòng)時(shí),網(wǎng)格模型改變形狀以便與之相匹配。骨骼在一個(gè).X文件里被表示為一個(gè)框架層次,當(dāng)構(gòu)造網(wǎng)格模型時(shí),以一種父與子的形式來(lái)連接框架。當(dāng)一個(gè)父框架被重新定向時(shí),所有附屬其上的子框架繼承父框架的變換,并兼有它們自身的變換,這使得動(dòng)畫(huà)的實(shí)現(xiàn)更加容易,只需移動(dòng)一個(gè)框架,其所有附屬框架也將相應(yīng)地移動(dòng)。
要加載并使用一個(gè)蒙皮網(wǎng)格模型,可以直接處理.X文件的數(shù)據(jù)對(duì)象。枚舉包含在一個(gè).X文件里的網(wǎng)格模型的數(shù)據(jù)對(duì)象時(shí),需要調(diào)用各種不同的D3DX網(wǎng)格模型加載功能函數(shù)去處理那些對(duì)象數(shù)據(jù)。當(dāng)加載蒙皮網(wǎng)格模型時(shí),要用到的一個(gè)功能函數(shù)就是
D3DXLoadSkinMeshFromXof。這個(gè)功能函數(shù)的作用就是從.X文件里讀取網(wǎng)格模型的數(shù)據(jù)對(duì)象,創(chuàng)建一個(gè)包含網(wǎng)格模型的
ID3DXMesh對(duì)象,同時(shí)創(chuàng)建一個(gè)ID3DXSkinInfo對(duì)象,該對(duì)象描述了網(wǎng)格模型變形所需要的骨骼到頂點(diǎn)的連接數(shù)據(jù)。
來(lái)看看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;
要使用蒙皮網(wǎng)格模型,需要?jiǎng)?chuàng)建兩個(gè)網(wǎng)格模型容器。第一個(gè)網(wǎng)格模型負(fù)責(zé)從.X文件進(jìn)行加載的工作,它確實(shí)是一個(gè)標(biāo)準(zhǔn)的網(wǎng)格模型,使用了一個(gè)ID3DXMesh對(duì)象去包含網(wǎng)格模型的信息。在這里要做的就是去克隆(復(fù)制)該網(wǎng)格模型,以便渲染變形后的蒙皮網(wǎng)格模型。
為了創(chuàng)建這個(gè)克隆的網(wǎng)格模型,調(diào)用網(wǎng)格模型的CloneMeshFVF功能函數(shù):
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.
可以這么使用這個(gè)函數(shù):
// 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;
}
}
要修改骨骼的變換,必須構(gòu)造一個(gè)D3DXMATRIX對(duì)象的數(shù)組(每個(gè)骨骼都有一個(gè)矩陣)。因此,如果蒙皮網(wǎng)格模型使用了10塊骨骼,那么就需要
10個(gè)D3DXMATRIX對(duì)象去包含每塊骨骼的變換。現(xiàn)在開(kāi)始存儲(chǔ)每塊骨骼的各種各樣的變換,需要記住的重要事情就是,每塊骨骼都繼承了它的父框架的變換,因此,改變一個(gè)骨骼的定位時(shí),存在某種程度的連鎖效應(yīng)。
一旦使用了變換,就能更新蒙皮網(wǎng)格模型的頂點(diǎn)并渲染網(wǎng)格模型,為了更新蒙皮網(wǎng)格模型,需要鎖定初始網(wǎng)格模型和蒙皮網(wǎng)格模型的(所克隆的輔助網(wǎng)格模型)頂點(diǎn)緩沖區(qū):
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);
一旦鎖定,調(diào)用ID3DXSkinInfo::UpdateSkinnedMesh功能函數(shù)去變換蒙皮網(wǎng)格模型里的所有頂點(diǎn),以便匹配在D3DXMATRIX數(shù)組里所設(shè)置的骨骼的方向。
來(lái)看看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);
最后,解鎖頂點(diǎn)緩沖區(qū):
// unlock buffers
mesh->m_skinmesh->UnlockVertexBuffer();
mesh->m_mesh->UnlockVertexBuffer();
以下代碼給出了如何繪制蒙皮網(wǎng)格:
//--------------------------------------------------------------------------------
// 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);
}
現(xiàn)在給出完整的示例代碼:
/***************************************************************************************
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;
}
運(yùn)行效果: