격자 모형의 고급 기술(13)

11097 단어

격자 모형의 고급 기술(13)


클래스 cAnimMesh는 가장 관건적인 클래스로 뼈 애니메이션과 관련된 구체적인 실현 세부 사항은 모두 이 클래스에 봉인되어 있으며, 이 클래스는 클래스 cAllocateHierarchy의 대상 m 를 정의한다alloc_이 대상은 파일에서 애니메이션 격자 모형을 불러오는 골격 차원 구조, 애니메이션 데이터 및 모형을 그리는 데 사용되는 기하학적 데이터를 완성합니다.
클래스 cAnimMesh의 정의는 다음과 같습니다.
class cAnimMesh
{
private:
cAllocateHierarchy* m_alloc_hierarchy;
IDirect3DDevice9* m_device;
D3DXFRAME* m_root_frame;
public:
D3DXVECTOR3 m_object_center;
float m_object_radius;
bool m_is_play_anim;
ID3DXAnimationController* m_anim_controller;
private:
HRESULT load_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;
}

 
함수 loadfrom_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() 함수가 내부에서 malloc_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:
  • Derive ID3DXAllocateHierarchy, implementing each method. This controls how frames and meshes are allocated and freed.
  • 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.
  • 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.
  • 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.
     
    매번 격자 모형을 렌더링하기 전에 각 프레임의 정확한 위치를 알아야만 정확한 위치에서 이 프레임에 포함된 구체적인 격자 모형을 그릴 수 있기 때문에 각급 프레임의 조합 변환 행렬, 함수 업데이트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);
    }

     
    골격 애니메이션 격자 모형은 프레임을 통해 트리 구조에 따라 조직된 것이고 격자 모형은 프레임에 포함되어 있기 때문에 격자 모형을 렌더링하는 동시에 그 중의 애니메이션을 재생하기 위해서는 각 프레임마다 격자 모형을 렌더링해야 한다. 그 중에서drawmesh_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()을 먼저 호출하고 이 격자가 프레임의 조합 변환 행렬에 따라 격자에 포함된 격자 모형을 정확한 위치로 이동한 후 재질, 무늬를 설정하여 마지막으로 그린다.
     
    함수drawframe() drawmesh_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);
    }

    이 함수를 호출할 때, 매개 변수 프레임을 격자 모형의 루트 노드로 설정하면 전체 격자 모형을 그릴 수 있습니다.
     
    함수 render ()drawframe()는 다음과 같이 전체 메쉬 모델의 렌더링을 완료합니다.
    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 호출 함수 Advance Time () 격자 모형 애니메이션을 앞으로 밀어낸 다음 함수 업데이트를 호출합니다frame_matrices(), 현재 격자 모형에 따른 세계 행렬 matworld 전체 격자 모형의 차원, 즉 각 프레임의 조합 변환 행렬을 계산하고 마지막으로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;
    }

    좋은 웹페이지 즐겨찾기