西游達人》(Q版)
《鐵甲風暴》(1代)
蛋糕達人》(Q版)

動漫游戲設計專業(脫產)

動漫游戲程序專業(脫產)
手機游戲程序專業(脫產)
假期動漫特訓班  (業余)
點擊和我咨詢 咨詢馬老師
點擊和我咨詢 咨詢林老師
點擊和我咨詢 咨詢馬老師
咨詢電話:0760-88618861
詳細信息查看


游戲中如何加載人物,場景模型

網格的處理:
在最底層,Direct3D只能處理多邊形,不能處理網格.D3DX給Direct3D系統增添了一些用來處理網格的對象.
在最底層,網格可能是由成千上萬個頂點組成的,維護起來相當煩瑣.幸好,Direct3D有一個自帶的文件格式用來存儲于網格相關的數據,包括:頂點,表面,法線向量和紋理.這個文件格式就是 .X 文件.
.X文件簡介:
.X文件是微軟開發的用來描述3D模型的數據文件.它是由許多模板組成的,并且是可以擴展的,這就意味著我們可以用它來存儲所有的3D模型.
一個.X文件可以是文本形式的--為了讓我們更方便的維護它,或者是二進制文件--為了使得文件更小,也為了更好的保護我們的重要數據..X文件的格式是基于模板的,這使得它看起來有點象C語言中的結構體.
模板解析:
我們用模板來存儲一組數據,一般來說,.X文件中的模板是用來存儲一些關于網格的信息.比如說,有的模板用來定義頂點,多邊形,紋理映射,法線向量等.大多數的模板被包含在其它的網格里,組成了一個模板層次結構:比如說,一個用來定義頂點法線向量的模板可以被包含在一個網格模板中.同樣,網格模板可以被包含在一個框架模板中(用來引用一些具體的模板).
我們可以像實例化C語言中結構體那樣來實例化一個模板.同樣,這里也需要有個"模板引用",這個功能可以讓我們只定義一個模板,但在多處使用(與C語言中的變量聲明類似).比如說,我們定義了一個網格,在所有用到它的地方我們不是一遍又一遍地聲明同一網格,而是只聲明它的一個引用即可.
D3DX使得網格的使用更加簡單,我們不用關心里面的每一個模板,只需要關心里面的網格模板和框架模板.
使用框架層次:
我們使用框架模板來來把一些相關的網格組合起來,使得管理更加簡單.我們可以只創建一個網格對象而在多個框架模板中引用它.這就使得我們實現了數據的重用.
比如說,我們有一個臺球的模型網格,因為我們總共需要15個臺球,所以我們就來創建15個模板,每個模板中都包含一個對原始臺球網格引用.然后我們把每個模板都"固定"在球桌的范圍內(通過使用框架轉換矩陣模板),使得每個臺球實例在框架也即球桌的范圍內移動.從本質上講,我們只是從一個網格模型創建了15個實例而已.
除了可以使用框架來創建一個網格模型的多個實例外,我們還可以用它們來創建一個分層次的框架結構.一個分層次的框架結構定義了一個場景或者是一組網格.當整個框架移動時,里面所有的框架都會相應移動.
比如說,我們可以把人的骨架想象成一個分層次的框架(如下圖所示):



框架層次的的最上方是胸,從胸往下,我們可以用一塊塊骨頭連接起來,胸連著脊,脊連著腿,腿連著腳.沿著這個順序,所用的骨骼都按一定順序排列好.
這樣我們就有了一個"根"框架---胸骨框架.根框架沒有父框架,意思是說它位于整個框架層次的最上面,不從屬于任何一個框架.被連接到其它框架的框架被稱作"子框架".
當一個框架移動時,它的所有子節點都要跟著移動.比如說,你要移動上臂,你的下臂跟手都要移動,這我們都很容易理解.然而,如果我們移動我們的手,則只有手會移動.因為它沒有子節點.
每個框架都有自己的朝向,在.X文件中的術語叫做框架轉換.對于在一個框架層次中轉換的情況,對一個較高層次的框架進行轉換時,它的所有子節點都要跟著轉換.
框架層次對于網格的高級應用和動畫技術是非常重要的,在后面的學習中我們將發現這一點.
另外一個使用框架層次的原因是可以將一些特定的場景分離開,然后只對這一小部分場景進行改變,這在游戲中是經常需要的.比如說,我們有一個框架來顯示房子,另外一個框架來顯示門,我們可以通過只修改房子的那一框架而不必改變顯示房子的那個框架.
.X文件剖析:
剖析一個.X文件對于我們來說是非常重要的,因為我們需要知道文件中的一些重要數據.我們使用IDirectXFile等一組對象來實現對.X文件的剖析---通過枚舉其中的模板來實現.
剖析.X文件并沒有你想象的那么難,通過掃描整個框架層次,尋找我們要用的模板.最困難的部分是模板是可以嵌套的,所以在枚舉的過程我們除了遇到模板外,還有可能遇到模板引用(還記得嗎?),如果枚舉到的是模板引用,我們要找到其原始數據.下圖為大家展示了模板之間的嵌套關系:


下面的這些代碼用來打開和分析.X文件.盡管有一些晦澀,不妨先看看:
BOOL ParseXFile(char *Filename)
{
IDirectXFile *pDXFile = NULL;
IDirectXFileEnumObject *pDXEnum = NULL;
IDirectXFileData *pDXData = NULL;
// Create the .X file object
if(FAILED(DirectXFileCreate(&pDXFile)))
return FALSE;
// Register the templates in use
// Use the standard retained mode templates from Direct3D
if(FAILED(pDXFile->RegisterTemplates((LPVOID) D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES))) {
pDXFile->Release();
return FALSE;
}
// Create an enumeration object
if(FAILED(pDXFile->CreateEnumObject((LPVOID)Filename, DXFILELOAD_FROMFILE, &pDXEnum))) {
pDXFile->Release();
return FALSE;
}
// Enumerate all top-level templates
while(SUCCEEDED(pDXEnum->GetNextDataObject(&pDXData))) {
ParseXFileData(pDXData);
ReleaseCOM(pDXData);
}
// Release objects
ReleaseCOM(pDXEnum);
ReleaseCOM(pDXFile);
// Return a success
return TRUE;
}
void ParseXFileData(IDirectXFileData *pData)
{
IDirectXFileObject *pSubObj = NULL;
IDirectXFileData *pSubData = NULL;
IDirectXFileDataReference *pDataRef = NULL;
const GUID *pType = NULL;
char *pName = NULL;
DWORD dwSize;
char *pBuffer;
// Get the template type
if(FAILED(pData->GetType(&pType)))
return;
// Get the template name (if any)
if(FAILED(pData->GetName(NULL, &dwSize)))
return;
if(dwSize) {
if((pName = new char[dwSize]) != NULL)
pData->GetName(pName, &dwSize);
}
// Give template a default name if none found
if(pName == NULL) {
if((pName = new char[9]) == NULL)
return;
strcpy(pName, “Template”);
}
// See what the template was and deal with it
// This is where you’ll jump in with your own code
// Scan for embedded templates
while(SUCCEEDED(pData->GetNextObject(&pSubObj))) {
// Process embedded references
if(SUCCEEDED(pSubObj->QueryInterface( IID_IDirectXFileDataReference, (void**)&pDataRef))) {
if(SUCCEEDED(pDataRef->Resolve(&pSubData))) {
ParseXFileData(pSubData);
ReleaseCOM(pSubData);
}
ReleaseCOM(pDataRef);
}
// Process non-referenced embedded templates
if(SUCCEEDED(pSubObj->QueryInterface( IID_IDirectXFileData, (void**)&pSubData))) {
ParseXFileData(pSubData);
ReleaseCOM(pSubData);
}
ReleaseCOM(pSubObj);
}
// Release name buffer
delete pName;
}

ParseXFile()跟ParseXFileData()這兩個函數共同完成了.X文件中每個模板的分析.ParseXFile()打開一個.X文件,并且枚舉處在模板層次中最高層的模板,每當找到一個模板,就交給ParseXFileData()來處理.

ParseXFileData()處理模板數據.首先,它得到模板類型和模板實例名稱.然后就處理模板數據,再就處理子節點的數據,直到所有的數據都處理完畢.
用D3DX處理網格:
D3DX是DirectX自帶的一組函數庫,使得我們可以站在巨人的肩膀上,同時也使得對網格的處理更加簡單.我們主要處理兩種網格:Standard 類型和skinned 網格.Standard網格就是普通網格,只有紋理使得它看起來比較好看,再也沒有其它修飾,而skinned網格則不同,它是可以"動"的,也就是說運行時它的一部分是會動的.為了達到"動"的目的,我們必須把網格的頂點都連接到一組"骨骼"上,只要"骨骼"動時,頂點就會相應的變化其位置.下面先讓我們來了一個這兩種類型的網格都會使用到的對象 ID3DXBuffer.

ID3DXBuffer 概述:
一個網格中的數據量有時候是驚人的,特別是如果網格里面還包含有動畫方面的信息,那么該如何管理這些重要的信息呢?D3DX利用ID3DXBuffer對象來保存和檢索數據,網格中關于頂點,紋理,材質的信息都被保存到ID3DXBuffer中.
ID3DXBuffer只有兩個成員函數,這使得對它的使用非常清晰,第一個函數:
void *ID3DXBuffer::GetBufferPointer();
這個函數是返回裝載數據緩沖區的指針,這個函數返回的是一個void類型的指針,我們可以根據自己的需要進行轉換.
第二個函數是:
DWORD ID3DXBuffer::GetBufferSize()
這個函數能夠返回數據緩沖區的大小.

下面讓我們來看看如何來創建ID3DXBuffer對象:
HRESULT D3DXCreateBuffer(
DWORD NumBytes, //數據緩沖區的大小
ID3DXBuffer **ppvBuffer); //ID3DXBuffer對象指針
來看一個具體的例子:
ID3DXBuffer *pBuffer;
// 創建緩沖區
if(SUCCEEDED(D3DXCreateBuffer(1024, &pBuffer)))
{
// 返回緩沖區指針
char *pPtr = pBuffer->GetBufferPoint();
// 清空緩沖區
memset(pPtr, 0, pBuffer->GetBufferSize());
// 釋放緩沖區
pBuffer->Release();
}

Standard網格:
前面我們簡述了Standard網格,Standard網格是最簡單的網格,所以這也是我們學習的最好起點.使用D3DX來處理Standard網格就更加簡單.一會我們就會發現用D3DX來處理一個網格僅僅需要幾行代碼就可以勝任.首先來看如何來裝載網格:
HRESULT D3DXLoadMeshFromX(
LPCTSTR pFilename, //要裝載的網格文件名稱
DWORD Options, //裝載方式,稍后介紹
LPDIRECT3DDEVICE9 pD3DDevice, //預先定義的設備對象
LPD3DXBUFFER * ppAdjacency, //用于存放面法線的緩沖區對象
LPD3DXBUFFER * ppMaterials, //用于存放材質的緩沖區對象
LPD3DXBUFFER * ppEffectInstances, //用于存放關于特效的緩沖區
DWORD * pNumMaterials, //材質的個數
LPD3DXMESH * ppMesh //所要創建的ID3DXMesh對象
);

有了上面的說明我們就大致了解了如何使用這個函數,給出所要加載的網格文件名稱,和相應的ID3DXBuffer,ID3DXMesh對象,還有用來記錄材質個數的DWORD變量,就完成了網格的加載.
如果我們所要加載的.X文件中含有多個網格模型,它將把所有的網格模型都組合成一個網格,下面來看一段代碼:
// g_pD3DDevice 已經定義了的設備對象
ID3DXBuffer *pD3DXMaterials;
DWORD g_dwNumMaterials;
ID3DXMesh *g_pD3DXMesh;
if(FAILED(D3DXLoadMeshFromX(“mesh.x”, D3DXMESH_SYSTEMMEM, g_pD3DDevice, NULL, &pD3DXMaterials, &g_dwNumMaterials,
&g_pD3DXMesh)))
{
// 錯誤處理
}

當成功加載了網格之后,下面的代碼來分析關于材質和紋理的數據信息:

D3DXMATERIAL *pMaterials = NULL;
D3DMATERIAL8 *g_pMaterialList = NULL;
IDirect3DTexture8 **g_pTextureList;
// 獲得材質鏈表指針
pMaterials = (D3DXMATERIAL*)pD3DXMaterials->GetBufferPointer();
if(pMaterials != NULL) {
// 申請用來存放材質數據的緩沖區
g_pMaterialList = new D3DMATERIAL8[dwNumMaterials];
// 申請用來存放紋理數據的緩沖區
g_pTextureList = new IDirect3DTexture8[dwNumMaterials];
// 紋理數據的保存
for(DWORD i=0;ig_pMaterialList[i] = pMaterials[i].MatD3D;
// 設置材質的屬性,以決定如何跟光交互
g_pMaterialList[i].Ambient = g_pMaterialList[i].Diffuse;
// 保存紋理數據數據
if(FAILED(D3DXCreateTextureFromFileA(g_pD3DDevice, g_pMaterials[i]->pTextureFilename, &g_pTextureList[i])))
g_pTextureList[i] = NULL;
}
//釋放材質緩沖區
pD3DXMaterials->Release();
} else {
//如果沒有材質的話,就創建默認的材質
g_dwNumMaterials = 1;
//設置材質屬性
g_pMaterialList = new D3DMATERIAL8[1];
g_pMaterialList[i].Diffuse.r = 1.0f;
g_pMaterialList[i].Diffuse.g = 1.0f;
g_pMaterialList[i].Diffuse.b = 1.0f;
g_pMaterialList[i].Diffuse.a = 1.0f;
g_pMaterialList[i].Ambient = g_pMaterialList[i].Diffuse;
// 創建空的紋理
g_pTextureList = new IDirect3DTexture8[1];
g_pTextureList[0] = NULL;
}
執行完上面的代碼后,我們就得到了用于渲染的材質,紋理數據,接下來的工作就是來渲染我們的網格.
網格的渲染:
網格渲染其實也很簡單,ID3DXMesh有一個專門負責渲染的函數:DrawSubset,它用來渲染一些網格的子集,說白了也就是網格的一部分,一個網格可能由于紋理的變化而分成多個部分,就是通過來渲染這一些小區域來完成整個網格的渲染,關鍵是我們自己要明白是如何劃分的,下面的圖可以幫助我們理解:

點擊數:5510

關閉窗口


 
站點首頁 | 漫龍招聘 | 關于我們 | 聯系我們
Copyright 2008-2015 吉東動漫科技有限公司  All Rights Reserved 粵ICP備14058066號
地址:中山市東區亨尾橫街19號(團益學校門口左側)    咨詢電話:0760--88618861 / 88662656 
山东时时开奖结果