上一次,封装了一个简单的骨骼动画类,但是,这个类有很多问题。第一,只能播放一个默认的动画,第二,一个动画的实例里面包含了所有的资源,而我们只是绘制的时候需要资源,实例本身并不需要都包含资源,所以只需要一个指针指向资源,绘制的时候通过这个指针渲染一下就好了,所以,这次在进行一次封装,实现一个支持多实例,多动画的骨骼动画类。
/*! * \file AllocateHierarchy.h * * \author puppet_master * \date 九月 2015 * * \微软SDK自带的关于骨骼动画的类,用于骨骼动画的创建以及绘制更新 * \注:程序不直接使用该类,而是将此类二次封装后再使用。 */ #ifndef __ALLOCATEHIERARCHY_H_ #define __ALLOCATEHIERARCHY_H_ //-------------------------------------------------------------------------------------- // Name: struct D3DXFRAME_DERIVED // Desc: //-------------------------------------------------------------------------------------- struct D3DXFRAME_DERIVED : public D3DXFRAME { D3DXMATRIXA16 CombinedTransformationMatrix; }; //-------------------------------------------------------------------------------------- // Name: struct D3DXMESHCONTAINER_DERIVED // Desc: Structure derived from D3DXMESHCONTAINER so we can add some app-specific // info that will be stored with each mesh //-------------------------------------------------------------------------------------- struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER { //纹理信息 LPDIRECT3DTEXTURE9* ppTextures; //纹理数组 //网格信息 LPD3DXMESH pOrigMesh; //原始网格 LPD3DXATTRIBUTERANGE pAttributeTable; //属性表 DWORD NumAttributeGroups; //属性组数量(子网格数量) DWORD NumInfl; //每个顶点最多受几个骨骼影响 LPD3DXBUFFER pBoneCombinationBuf; //骨骼结合缓存 D3DXMATRIX** ppBoneMatrixPtrs; //骨骼组合变换矩阵 D3DXMATRIX* pBoneOffsetMatrices; //骨骼初始变换矩阵 DWORD NumPaletteEntries; //骨骼数量上限 bool UseSoftwareVP; //是否使用软件顶点处理 DWORD iAttributeSW; // used to denote the split between SW and HW if necessary for non-indexed skinning }; //-------------------------------------------------------------------------------------- // Name: class CAllocateHierarchy // Desc: Custom version of ID3DXAllocateHierarchy with custom methods to create // frames and meshcontainers. //用来从.X文件中加载网格以及动画数据 //-------------------------------------------------------------------------------------- class CAllocateHierarchy : public ID3DXAllocateHierarchy { private: HRESULT AllocateName( LPCSTR Name, LPSTR* pNewName ); HRESULT GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer ); public: STDMETHOD( CreateFrame )( THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame ); STDMETHOD( CreateMeshContainer )( THIS_ LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer ); STDMETHOD( DestroyFrame )( THIS_ LPD3DXFRAME pFrameToFree ); STDMETHOD( DestroyMeshContainer )( THIS_ LPD3DXMESHCONTAINER pMeshContainerBase ); CAllocateHierarchy() { } }; #endif
#include "stdafx.h" #include "AllocateHierarchy.h" HRESULT CAllocateHierarchy::AllocateName( LPCSTR Name, LPSTR* pNewName ) { UINT cbLength; if( Name != NULL ) { cbLength = ( UINT )strlen( Name ) + 1; *pNewName = new CHAR[cbLength]; if( *pNewName == NULL ) return E_OUTOFMEMORY; memcpy( *pNewName, Name, cbLength * sizeof( CHAR ) ); } else { *pNewName = NULL; } return S_OK; } //-------------------------------------------------------------------------------------- // Called either by CreateMeshContainer when loading a skin mesh, or when // changing methods. This function uses the pSkinInfo of the mesh // container to generate the desired drawable mesh and bone combination // table. //-------------------------------------------------------------------------------------- HRESULT CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer ) { D3DCAPS9 d3dCaps; pd3dDevice->GetDeviceCaps( &d3dCaps ); if( pMeshContainer->pSkinInfo == NULL ) return S_OK; SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf ); if (FAILED(pMeshContainer->pSkinInfo->ConvertToBlendedMesh( pMeshContainer->pOrigMesh, D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE, pMeshContainer->pAdjacency, NULL, NULL, NULL, &pMeshContainer->NumInfl, &pMeshContainer->NumAttributeGroups, &pMeshContainer->pBoneCombinationBuf, &pMeshContainer->MeshData.pMesh))) return E_FAIL; return S_OK; } //-------------------------------------------------------------------------------------- // Name: CAllocateHierarchy::CreateFrame() // Desc: 创建框架,分配内存&初始化 //-------------------------------------------------------------------------------------- HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME* ppNewFrame ) { HRESULT hr = S_OK; D3DXFRAME_DERIVED* pFrame; *ppNewFrame = NULL; pFrame = new D3DXFRAME_DERIVED; if( pFrame == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = AllocateName( Name, &pFrame->Name ); if( FAILED( hr ) ) goto e_Exit; // initialize other data members of the frame D3DXMatrixIdentity( &pFrame->TransformationMatrix ); D3DXMatrixIdentity( &pFrame->CombinedTransformationMatrix ); pFrame->pMeshContainer = NULL; pFrame->pFrameSibling = NULL; pFrame->pFrameFirstChild = NULL; *ppNewFrame = pFrame; pFrame = NULL; e_Exit: delete pFrame; return hr; } //-------------------------------------------------------------------------------------- // Name: CAllocateHierarchy::CreateMeshContainer() // Desc: 创建网格容器对象,保存网格模型数据 //-------------------------------------------------------------------------------------- HRESULT CAllocateHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer ) { HRESULT hr; D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; LPDIRECT3DDEVICE9 pd3dDevice = NULL; LPD3DXMESH pMesh = NULL; *ppNewMeshContainer = NULL; // this sample does not handle patch meshes, so fail when one is found if( pMeshData->Type != D3DXMESHTYPE_MESH ) { hr = E_FAIL; goto e_Exit; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; // this sample does not FVF compatible meshes, so fail when one is found if( pMesh->GetFVF() == 0 ) { hr = E_FAIL; goto e_Exit; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new D3DXMESHCONTAINER_DERIVED; if( pMeshContainer == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } memset( pMeshContainer, 0, sizeof( D3DXMESHCONTAINER_DERIVED ) ); // make sure and copy the name. All memory as input belongs to caller, interfaces can be addref'd though hr = AllocateName( Name, &pMeshContainer->Name ); if( FAILED( hr ) ) goto e_Exit; pMesh->GetDevice( &pd3dDevice ); NumFaces = pMesh->GetNumFaces(); // if no normals are in the mesh, add them if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // clone the mesh to make room for the normals hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pd3dDevice, &pMeshContainer->MeshData.pMesh ); if( FAILED( hr ) ) goto e_Exit; // get the new pMesh pointer back out of the mesh container to use // NOTE: we do not release pMesh because we do not have a reference to it yet pMesh = pMeshContainer->MeshData.pMesh; // now generate the normals for the pmesh D3DXComputeNormals( pMesh, NULL ); } else // if no normals, just add a reference to the mesh for the mesh container { pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; pMesh->AddRef(); } // allocate memory to contain the material information. This sample uses // the D3D9 materials and texture names instead of the EffectInstance style materials pMeshContainer->NumMaterials = max( 1, NumMaterials ); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[NumFaces*3]; if( ( pMeshContainer->pAdjacency == NULL ) || ( pMeshContainer->pMaterials == NULL ) ) { hr = E_OUTOFMEMORY; goto e_Exit; } memcpy( pMeshContainer->pAdjacency, pAdjacency, sizeof( DWORD ) * NumFaces*3 ); memset( pMeshContainer->ppTextures, 0, sizeof( LPDIRECT3DTEXTURE9 ) * pMeshContainer->NumMaterials ); // if materials provided, copy them if( NumMaterials > 0 ) { memcpy( pMeshContainer->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials ); for( iMaterial = 0; iMaterial < NumMaterials; iMaterial++ ) { if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL ) { if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, pMeshContainer->pMaterials[iMaterial].pTextureFilename, &pMeshContainer->ppTextures[iMaterial] ) ) ) pMeshContainer->ppTextures[iMaterial] = NULL; // don't remember a pointer into the dynamic memory, just forget the name after loading pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else // if no materials provided, use a default one { pMeshContainer->pMaterials[0].pTextureFilename = NULL; memset( &pMeshContainer->pMaterials[0].MatD3D, 0, sizeof( D3DMATERIAL9 ) ); pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } // if there is skinning information, save off the required data and then setup for HW skinning if( pSkinInfo != NULL ) { // first save off the SkinInfo and original mesh data pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pMeshContainer->pOrigMesh = pMesh; pMesh->AddRef(); // Will need an array of offset matrices to move the vertices from the figure space to the bone's space cBones = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones]; if( pMeshContainer->pBoneOffsetMatrices == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } // get each of the bone offset matrices so that we don't need to get them later for( iBone = 0; iBone < cBones; iBone++ ) { pMeshContainer->pBoneOffsetMatrices[iBone] = *( pMeshContainer->pSkinInfo->GetBoneOffsetMatrix( iBone ) ); } // GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer ); if( FAILED( hr ) ) goto e_Exit; } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; e_Exit: SAFE_RELEASE( pd3dDevice ); // call Destroy function to properly clean up the memory allocated if( pMeshContainer != NULL ) { DestroyMeshContainer( pMeshContainer ); } return hr; } //-------------------------------------------------------------------------------------- // Name: CAllocateHierarchy::DestroyFrame() // Desc: 释放框架 //-------------------------------------------------------------------------------------- HRESULT CAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree ) { SAFE_DELETE_ARRAY( pFrameToFree->Name ); SAFE_DELETE( pFrameToFree ); return S_OK; } //-------------------------------------------------------------------------------------- // Name: CAllocateHierarchy::DestroyMeshContainer() // Desc: 释放网格容器 //-------------------------------------------------------------------------------------- HRESULT CAllocateHierarchy::DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase ) { UINT iMaterial; D3DXMESHCONTAINER_DERIVED* pMeshContainer = ( D3DXMESHCONTAINER_DERIVED* )pMeshContainerBase; SAFE_DELETE_ARRAY( pMeshContainer->Name ); SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency ); SAFE_DELETE_ARRAY( pMeshContainer->pMaterials ); SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices ); // release all the allocated textures if( pMeshContainer->ppTextures != NULL ) { for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++ ) { SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] ); } } SAFE_DELETE_ARRAY( pMeshContainer->ppTextures ); SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs ); SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf ); SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); SAFE_RELEASE( pMeshContainer->pSkinInfo ); SAFE_RELEASE( pMeshContainer->pOrigMesh ); SAFE_DELETE( pMeshContainer ); return S_OK; }
/*! * \file D3DXAnimation.h * * \author puppet_master * \date 九月 2015 * * \封装了微软自带的骨骼动画相关功能,内部包含读取骨骼动画,播放等功能。 * \不可以直接使用,需要克隆一个动画控制器,创建单独的实例才可以使用 */ #ifndef __D3DXANIMATION_H_ #define __D3DXANIMATION_H_ #include "AllocateHierarchy.h" class CD3DXAnimation { private: IDirect3DDevice9* m_pDevice; //D3D设备对象 CAllocateHierarchy* m_pAllocateHier; //骨骼动画网格模型指针 LPD3DXFRAME m_pFrameRoot; //帧 LPD3DXANIMATIONCONTROLLER m_pAnimController; //动画控制器 private: //一些微软自带函数,关于骨骼动画加载与绘制更新的函数,将其封装,不使用这些接口 void DrawMeshContainer( IDirect3DDevice9* pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase ); void DrawFrame( IDirect3DDevice9* pd3dDevice, LPD3DXFRAME pFrame ); HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrameBase, LPD3DXFRAME pFrameRoot ); void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix ); public: CD3DXAnimation(IDirect3DDevice9* device); ~CD3DXAnimation(void); //提供给外界的接口 //创建骨骼动画 bool Init(LPCTSTR filename); //复制骨骼动画控制器 LPD3DXANIMATIONCONTROLLER CloneAnimCtrl(void); //绘制骨骼动画 void Render(const LPD3DXMATRIX matrix); }; #endif
#include "stdafx.h" #include "D3DXAnimation.h" #include "TempDebug.h" CD3DXAnimation::CD3DXAnimation(IDirect3DDevice9* device) :m_pDevice(device), m_pAllocateHier(NULL), m_pAnimController(NULL), m_pFrameRoot(NULL) // m_BoneMatrix(NULL) { } CD3DXAnimation::~CD3DXAnimation(void) { D3DXFrameDestroy(m_pFrameRoot, m_pAllocateHier); SAFE_RELEASE(m_pAnimController); SAFE_DELETE(m_pAllocateHier); } //-------------------------------------------------------------------------------------- // Name: SetupBoneMatrixPointers() // Desc: 设置好各级框架的组合变换矩阵。 //-------------------------------------------------------------------------------------- HRESULT CD3DXAnimation::SetupBoneMatrixPointers( LPD3DXFRAME pFrameBase, LPD3DXFRAME pFrameRoot ) { if( pFrameBase->pMeshContainer != NULL ) { D3DXFRAME_DERIVED* pFrame = NULL; D3DXMESHCONTAINER_DERIVED* pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pFrameBase->pMeshContainer; // if there is a skinmesh, then setup the bone matrices if (pMeshContainer->pSkinInfo != NULL) { UINT cBones = pMeshContainer->pSkinInfo->GetNumBones(); pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones]; for (UINT iBone = 0; iBone < cBones; iBone++) { pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind(pFrameRoot, pMeshContainer->pSkinInfo->GetBoneName(iBone)); if (pFrame == NULL) return E_FAIL; pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix; } } } if (pFrameBase->pFrameSibling != NULL) { if (FAILED(SetupBoneMatrixPointers(pFrameBase->pFrameSibling, pFrameRoot))) return E_FAIL; } if (pFrameBase->pFrameFirstChild != NULL) { if (FAILED(SetupBoneMatrixPointers(pFrameBase->pFrameFirstChild, pFrameRoot))) return E_FAIL; } return S_OK; } //-------------------------------------------------------------------------------------- // Name: DrawFrame() // Desc: 绘制骨骼 //-------------------------------------------------------------------------------------- void CD3DXAnimation::DrawFrame( IDirect3DDevice9* pd3dDevice, LPD3DXFRAME pFrame ) { if (pFrame == NULL) return; LPD3DXMESHCONTAINER pMeshContainer; pMeshContainer = pFrame->pMeshContainer; // 取得网格容器 while( pMeshContainer != NULL ) { DrawMeshContainer(pd3dDevice, pMeshContainer, pFrame); // 绘制非空蒙皮网格 pMeshContainer = pMeshContainer->pNextMeshContainer; // 遍历所有网格容器 } DrawFrame(pd3dDevice, pFrame->pFrameSibling); // 绘制兄弟框架 DrawFrame(pd3dDevice, pFrame->pFrameFirstChild); // 绘制子框架 } //-------------------------------------------------------------------------------------- // Name: DrawMeshContainer() // Desc: 绘制蒙皮容器中的蒙皮网格 //-------------------------------------------------------------------------------------- void CD3DXAnimation::DrawMeshContainer( IDirect3DDevice9* pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase ) { D3DXMESHCONTAINER_DERIVED* pMeshContainer = ( D3DXMESHCONTAINER_DERIVED* )pMeshContainerBase; D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase; UINT iMaterial; UINT NumBlend; UINT iAttrib; DWORD AttribIdPrev; LPD3DXBONECOMBINATION pBoneComb; UINT iMatrixIndex; D3DXMATRIXA16 matTemp; D3DCAPS9 d3dCaps; pd3dDevice->GetDeviceCaps( &d3dCaps ); // first check for skinning if( pMeshContainer->pSkinInfo != NULL ) { AttribIdPrev = UNUSED32; pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>( pMeshContainer->pBoneCombinationBuf->GetBufferPointer() ); // Draw using default vtx processing of the device (typically HW) for( iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++ ) { NumBlend = 0; for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i ) { if( pBoneComb[iAttrib].BoneId[i] != UINT_MAX ) { NumBlend = i; } } if( d3dCaps.MaxVertexBlendMatrices >= NumBlend + 1 ) { // first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i ) { iMatrixIndex = pBoneComb[iAttrib].BoneId[i]; if( iMatrixIndex != UINT_MAX ) { D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] ); pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ); } } pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, NumBlend ); // lookup the material used for this subset of faces if( ( AttribIdPrev != pBoneComb[iAttrib].AttribId ) || ( AttribIdPrev == UNUSED32 ) ) { pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ); pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ); AttribIdPrev = pBoneComb[iAttrib].AttribId; } // draw the subset now that the correct material and matrices are loaded pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ); } } pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, 0 ); } else // standard mesh, just draw it after setting material properties { pd3dDevice->SetTransform( D3DTS_WORLD, &pFrame->CombinedTransformationMatrix ); for( iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++ ) { pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D ); pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] ); pMeshContainer->MeshData.pMesh->DrawSubset( iMaterial ); } } } //-------------------------------------------------------------------------------------- // Name: UpdateFrameMatrics() // Desc: 更新框架中的变换矩阵 //-------------------------------------------------------------------------------------- void CD3DXAnimation::UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix ) { if (pFrameBase == NULL || pParentMatrix == NULL) return; D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase; // 将当前骨骼的相对于父骨骼的偏移矩阵作累积运算 D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix); UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix); // 更新兄弟骨骼 UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix); // 更新子骨骼 } //--------------------------------------------------------- //Name:真正暴露给外部调用的函数 //Desc:关于动画的创建,更新,绘制 //--------------------------------------------------------- bool CD3DXAnimation::Init(LPCTSTR filename) { m_pAllocateHier = new CAllocateHierarchy(); D3DXLoadMeshHierarchyFromX(filename, D3DXMESH_MANAGED, m_pDevice, m_pAllocateHier, NULL, &m_pFrameRoot, &m_pAnimController); SetupBoneMatrixPointers(m_pFrameRoot, m_pFrameRoot); return true; } void CD3DXAnimation::Render(const LPD3DXMATRIX matrix) { //m_pDevice->SetTransform(D3DTS_WORLD, matrix); UpdateFrameMatrices(m_pFrameRoot, matrix); DrawFrame(m_pDevice, m_pFrameRoot); } LPD3DXANIMATIONCONTROLLER CD3DXAnimation::CloneAnimCtrl(void) { //克隆一个动画控制器,真正使用的是克隆的动画控制器,而并非原始的动画控制器,原始的动画控制器仅供克隆。 LPD3DXANIMATIONCONTROLLER pControl = NULL; if(FAILED(m_pAnimController->CloneAnimationController( m_pAnimController->GetMaxNumAnimationOutputs(), m_pAnimController->GetMaxNumAnimationSets(), m_pAnimController->GetMaxNumTracks(), m_pAnimController->GetMaxNumEvents(), &pControl ))) { return NULL; } return pControl; }
/*! * \file AnimInstance.h * * \author puppet_master * \date 九月 2015 * \骨骼动画实例类:可以直接使用的骨骼动画实例,内部包含骨骼动画绘制指针与单独的控制器。 */ #ifndef __ANIMINSTANCE_H_ #define __ANIMINSTANCE_H_ #include "D3DXAnimation.h" class CAnimInstance { private: CD3DXAnimation* m_pAnimMesh; LPD3DXANIMATIONCONTROLLER m_pAnimController; D3DXMATRIX m_Matrix; float m_fSpeed; bool m_bIsLoop; public: CAnimInstance(void); ~CAnimInstance(void); //初始化一个动画网格实例,获得动画网格资源指针,并拷贝出一个单独的动画控制器 bool Init(CD3DXAnimation* mesh); //绘制实例 void Render(); //根据名称播放动画 bool PlayAnimation(LPCTSTR name, bool isLoop = true); //更新动画 void Update(float delayTime); //设置动画速度 void SetSpeed(float speed); //获得动画速度 float GetSpeed()const{return m_fSpeed;} //更新矩阵 void SetMatrix(const LPD3DXMATRIX matrix); //获得矩阵 D3DMATRIX GetMatrix(){return m_Matrix;} //获得骨骼动画个数 int GetAnimationNum() const; //根据动画编号获得动画集 LPD3DXANIMATIONSET GetAnimationSet(int index) const; }; #endif
#include "stdafx.h" #include "AnimInstance.h" CAnimInstance::CAnimInstance(void) { } CAnimInstance::~CAnimInstance(void) { } bool CAnimInstance::Init(CD3DXAnimation* mesh) { m_pAnimMesh = mesh; return m_pAnimController = mesh->CloneAnimCtrl(); } void CAnimInstance::Render() { m_pAnimMesh->Render(&m_Matrix); } bool CAnimInstance::PlayAnimation(LPCTSTR name, bool isLoop) { LPD3DXANIMATIONSET pAnimationSet = NULL; m_pAnimController->GetAnimationSetByName(name, &pAnimationSet); m_pAnimController->SetTrackAnimationSet(0, pAnimationSet); return true; } void CAnimInstance::Update(float delayTime) { m_pAnimController->AdvanceTime(delayTime, NULL); } void CAnimInstance::SetSpeed(float speed) { m_fSpeed = speed; } void CAnimInstance::SetMatrix(const LPD3DXMATRIX matrix) { m_Matrix = *matrix; } int CAnimInstance::GetAnimationNum() const { return m_pAnimController->GetMaxNumAnimationSets(); } LPD3DXANIMATIONSET CAnimInstance::GetAnimationSet(int index) const { if (index >= 0 && index < GetAnimationNum()) { LPD3DXANIMATIONSET pAnimSet = NULL; m_pAnimController->GetAnimationSet(index, &pAnimSet); return pAnimSet; } return NULL; }