網格模型進階技術

來源:互聯網
上載者:User

類cAnimMesh是最關鍵的一個類,所有與骨骼動畫相關的具體實現細節都封裝在該類中,該類還定義了類cAllocateHierarchy的一個對象m_alloc_hierarchy,該對象完成從檔案中載入動畫網格模型的骨骼階層、動畫資料以及其他用於繪製模型的幾何資料。

 

類cAnimMesh的定義如下所示:

class cAnimMesh
{
private:
cAllocateHierarchy*m_alloc_hierarchy;
IDirect3DDevice9*m_device;
D3DXFRAME*m_root_frame;
public:
D3DXVECTOR3m_object_center;
floatm_object_radius;
boolm_is_play_anim;
ID3DXAnimationController*m_anim_controller;
private:
HRESULTload_from_xfile(CONST WCHAR* wfilename);
void update_frame_matrices(D3DXFRAME* base_frame, CONST D3DXMATRIX* parent_matrix);
void draw_frame(CONST D3DXFRAME* frame);
void draw_mesh_container(CONST D3DXMESHCONTAINER* base_mesh_container, CONST D3DXFRAME* base_frame);
public:
HRESULT create(IDirect3DDevice9* device, CONST WCHAR* wfilename);
void render(CONST D3DXMATRIX* mat_world, double app_elapsed_time);
void destroy();
public:
cAnimMesh();
virtual ~cAnimMesh();
};

 

建構函式負責分配資源和初始化成員變數,解構函式負責釋放資源:

cAnimMesh::cAnimMesh()
{
m_is_play_anim = true;
m_device = NULL;
m_anim_controller = NULL;
m_root_frame = NULL;
m_alloc_hierarchy = new cAllocateHierarchy();
}
cAnimMesh::~cAnimMesh()
{
D3DXFrameDestroy(m_root_frame, m_alloc_hierarchy);
release_com(m_anim_controller);
delete m_alloc_hierarchy;
}

 

函數load_from_xfile()的主要任務是調用函數D3DXLoadMeshHierarchyFromX()從.x檔案中載入動畫模型,其實現如下:

HRESULT cAnimMesh::load_from_xfile(CONST WCHAR* wfilename)
{
HRESULT hr;
WCHAR wpath[MAX_PATH];
DXUTFindDXSDKMediaFileCch(wpath, sizeof(wpath) / sizeof(WCHAR), wfilename);
V_RETURN(D3DXLoadMeshHierarchyFromXW(wpath, D3DXMESH_MANAGED, m_device, m_alloc_hierarchy, NULL, 
&m_root_frame, &m_anim_controller));
V_RETURN(D3DXFrameCalculateBoundingSphere(m_root_frame, &m_object_center, &m_object_radius));
return S_OK;
}

雖然該函數的實現代碼非常簡單,但其內部過程卻是很複雜的,關鍵是要弄清除D3DXLoadMeshHierarchyFromX()函數中m_alloc_hierarchy參數的作用。D3DXLoadMeshHierarchyFromX()函數在內部隱式地通過m_alloc_hierarchy調用載入網格模型具體資料的函數(即上面提到的cAllocateHeirarchy中的CreateFrame()和CreateMeshContainer()函數),這些函數是由使用者編寫的,但卻是由Direct3D在內部於適當機制調用。

來看看D3DXLoadMeshHierarchyFromX()的具體使用說明:

Loads the first frame hierarchy from a .x file.

HRESULT D3DXLoadMeshHierarchyFromX(
LPCSTR Filename,
DWORD MeshOptions,
LPDIRECT3DDEVICE9 pDevice,
LPD3DXALLOCATEHIERARCHY pAlloc,
LPD3DXLOADUSERDATA pUserDataLoader,
LPD3DXFRAME* ppFrameHierarchy,
LPD3DXANIMATIONCONTROLLER* ppAnimController
);
Parameters
Filename
[in] Pointer to a string that specifies the filename. If the compiler settings require Unicode, the data type LPCTSTR resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See Remarks.
MeshOptions
[in] Combination of one or more flags from the D3DXMESH enumeration that specify creation options for the mesh.
pDevice
[in] Pointer to an IDirect3DDevice9 interface, the device object associated with the mesh.
pAlloc
[in] Pointer to an ID3DXAllocateHierarchy interface.
pUserDataLoader
[in] Application provided interface that allows loading of user data.
ppFrameHierarchy
[out, retval] Returns a pointer to the loaded frame hierarchy.
ppAnimController
[out, retval] Returns a pointer to the animation controller corresponding to animation in the .x file. This is created with default tracks and events.
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 values: D3DERR_INVALIDCALL, E_OUTOFMEMORY.

Remarks

The compiler setting also determines the function version. If Unicode is defined, the function call resolves to D3DXLoadMeshHierarchyFromXW. Otherwise, the function call resolves to D3DXLoadMeshHierarchyFromXA.

All the meshes in the file will be collapsed into one output mesh. If the file contains a frame hierarchy, all the transformations will be applied to the mesh.

D3DXLoadMeshHierarchyFromX loads the animation data and frame hierarchy from a .x file. It scans the .x file and builds a frame hierarchy and animation controller according to the ID3DXAllocateHierarchy-derived object passed to it through pAlloc. Loading the data requires several steps as follows:

  1. Derive ID3DXAllocateHierarchy, implementing each method. This controls how frames and meshes are allocated and freed.
  2. Derive ID3DXLoadUserData, implementing each method. If your .x file has no embedded user-defined data, or if you do not need it, you can skip this part.
  3. Create an object of your ID3DXAllocateHierarchy class, and optionally of your LoadUserData class. You do not need to call any methods of these objects yourself.
  4. Call D3DXLoadMeshHierarchyFromX, passing in your ID3DXAllocateHierarchy object and your ID3DXLoadUserData object (or NULL) to create the frame hierarchy and animation controller. All the animation sets and frames are automatically registered to the animation controller.

During the load, ID3DXAllocateHierarchy::CreateFrame and ID3DXLoadUserData::LoadFrameChildData are called back on each frame to control loading and allocation of the frame. The application defines these methods to control how frames are stored. ID3DXAllocateHierarchy::CreateMeshContainer and ID3DXLoadUserData::LoadMeshChildData are called back on each mesh object to control loading and allocation of mesh objects. ID3DXLoadUserData::LoadTopLevelData is called back for each top level object that doesn't get loaded by the other methods.

To free this data, call ID3DXAnimationController::Release to free the animation sets, and D3DXFRAMEDestroy, passing in the root node of the frame hierarchy and an object of your derived ID3DXAllocateHierarchy class. ID3DXAllocateHierarchy::DestroyFrame and ID3DXAllocateHierarchy::DestroyMeshContainer will each be called for every frame and mesh object in the frame hierarchy. Your implementation of ID3DXAllocateHierarchy::DestroyFrame should release everything allocated by ID3DXAllocateHierarchy::CreateFrame, and likewise for the mesh container methods.

 

因為在每次渲染網格模型前,只有知道每個架構的確切位置,才能在正確的位置上繪製出該架構套件含的具體網格模型,所以需要計算得到各級架構的組合變換矩陣,函數update_frame_matrices()採用遞迴的方法計算各級架構的組合變換矩陣,具體實現代碼如下:

void cAnimMesh::update_frame_matrices(D3DXFRAME* base_frame, CONST D3DXMATRIX* parent_matrix)
{
D3DXFRAME_DERIVED* frame = (D3DXFRAME_DERIVED*) base_frame;
if(parent_matrix != NULL)
D3DXMatrixMultiply(&frame->CombinedTransformMatrix, &frame->TransformationMatrix, parent_matrix);
else
frame->CombinedTransformMatrix = frame->TransformationMatrix;
if(frame->pFrameSibling != NULL)
update_frame_matrices(frame->pFrameSibling, parent_matrix);
if(frame->pFrameFirstChild != NULL)
update_frame_matrices(frame->pFrameFirstChild, &frame->CombinedTransformMatrix);
}

 

因為骨骼動畫網格模型是通過架構按照樹狀結構組織起來的,而網格模型又包含在架構之中,所以在為了渲染網格模型的同時能將其中的動畫播放出來,就需要逐個架構逐個網格模型地進行渲染,其中draw_mesh_container()負責渲染架構中包含的具體網格模型:

void cAnimMesh::draw_mesh_container(CONST D3DXMESHCONTAINER* base_mesh_container, CONST D3DXFRAME* base_frame)
{
D3DXMESHCONTAINER_DERIVED* mesh_container = (D3DXMESHCONTAINER_DERIVED*) base_mesh_container;
D3DXFRAME_DERIVED* frame = (D3DXFRAME_DERIVED*) base_frame;
m_device->SetTransform(D3DTS_WORLD, &frame->CombinedTransformMatrix);
for(UINT i = 0; i < mesh_container->NumMaterials; i++)
{
m_device->SetMaterial(&mesh_container->pMaterials[i].MatD3D);
m_device->SetTexture(0, mesh_container->ppTextures[i]);
mesh_container->MeshData.pMesh->DrawSubset(i);
}
}

該函數的實現比較簡單,在渲染每個網格之前,首先調用函數SetTransform(),根據該網格在架構的組合變換矩陣,將網格中所包含的網格模型移動到正確的位置後,再設定材質、紋理,最後進行繪製。

 

函數draw_frame()以draw_mesh_container()為基礎,採用遞迴的方法,將整個網格模型繪製出來:

void cAnimMesh::draw_frame(CONST D3DXFRAME* frame)
{
D3DXMESHCONTAINER* mesh_container = frame->pMeshContainer;
while(mesh_container != NULL)
{
draw_mesh_container(mesh_container, frame);
mesh_container = mesh_container->pNextMeshContainer;
}
if(frame->pFrameSibling != NULL)
draw_frame(frame->pFrameSibling);
if(frame->pFrameFirstChild != NULL)
draw_frame(frame->pFrameFirstChild);
}

在調用該函數時,只需將參數frame設定為網格模型的根節點就可以繪製出整個網格模型。

 

函數render()通過draw_frame()完成整個網格模型的渲染,其實現如下:

void cAnimMesh::render(CONST D3DXMATRIX* mat_world, double app_elapsed_time)
{
if(0.0f == app_elapsed_time)
return;
if(m_is_play_anim && m_anim_controller != NULL)
m_anim_controller->AdvanceTime(app_elapsed_time, NULL);
update_frame_matrices(m_root_frame, mat_world);
draw_frame(m_root_frame);
}

在渲染網格模型之前,首先使用動畫控制器m_anim_controller調用函數AdvanceTime()將網格模型動畫向前推進,然後調用函數update_frame_matrices(),根據當前網格模型的世界矩陣mat_world更新整個網格模型的層次,即計算每個架構的組合變換矩陣,最後調用draw_frame()函數渲染出整個網格模型。

 

create()函數用於根據參數指定的網格模型檔案名稱建立骨骼動畫網格模型:

HRESULT cAnimMesh::create(IDirect3DDevice9* device, CONST WCHAR* wfilename)
{
m_device = device;
HRESULT hr;
V_RETURN(load_from_xfile(wfilename));
return S_OK;
}

函數destroy()只負責銷毀對象:

void cAnimMesh::destroy()
{
delete this;
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.