Direct-X学习笔记--骨骼动画进阶
上一次,封装了一个简单的骨骼动画类,但是,这个类有很多问题。第一,只能播放一个默认的动画,第二,一个动画的实例里面包含了所有的资源,而我们只是绘制的时候需要资源,实例本身并不需要都包含资源,所以只需要一个指针指向资源,绘制的时候通过这个指针渲染一下就好了,所以,这次在进行一次封装,实现一个支持多实例,多动画的骨骼动画类。
一.AnimationSet
一个.X文件中可能包含多个动画,比如idle,walk等等,这些动画都存储在.x文件中。一个动画称为一个AnimationSet,一个AnimationSet包含一个或者多个Animation,而一个Animation包含一个或者几个AnimationKey,即关键帧。我们暂时不去了解过于细节的问题,只需要去控制我们的模型,播放哪个动画就好了。所以,我们关注的地方就是AnimationSet。
打开一个骨骼动画,微软自带的那个tiny.X,就是那个很丑的小人,Ctrl+F找到AnimationSet:
好像确实是上面的那种分类方式,没有什么特殊的。不过,这个是只有一个默认的动作的骨骼动画模型,所以AnimationSet并没有命名,我们也没有办法控制它播放哪一个动画。下面,我们打开DX为我们准备的另一个Sample,多动画的那个例子,这里面有个tiny_4anim.x文件,这里面包含了四个骨骼动画,我们再看一下:
看到AnimationSet后面跟了个名字,叫Walk。我们依次查看一下,这四个动画分别为Walk,Loiter,Jog,Wave。即AnimationSet都是有名字的。好了,既然知道了名字,我们就想到了,通过名字,来命令DX播放不同的骨骼动画,DX确实为我们提供了这样一个接口。不过,还得再等等,因为还有一个东西木有学会,就是AnimationController--动画控制器。
二.AnimationController、
AnimationController,即动画控制器。我们使用骨骼动画的时候,要通过这个动画控制器来控制动画的播放,切换等等。在上次的那个类中,其实已经写过一个动画控制器的。而且,这个动画控制器是会在模型载入时,通过DX给的API初始化完成的。但是,我们并不能用这个动画控制器!为什么呢?答案很简单,因为,一个动画控制器对应着一个动画的实例的当前状态,假如我们所有的实例内部都包含了骨骼动画资源的话,那么倒是无需考虑这个了。但是,游戏中有那么多实例,资源仅仅需要一份就够了,我们只是需要在绘制的时候,用一下这个骨骼动画模型的指针,把这个模型渲染一下就行了。但是,为什么动画控制器也需要多个呢?比如10个实例的话,这10个实例可能在做不同的动作,速度可能也不一样,如果我们都采用相同的动画控制器的话,那么,这10个实例的动作会高度统一...简直比阅兵都齐。
那么,我们要怎么样为每个动画实例创建一个动画控制器呢?其实这个东东DX也为我们准备好了,我们也是调用一下API就可以拷贝出一个独立的动画控制器,放在我们的实例中,这样,每个实例都有自己的动画控制器,就可以分别以不同的速度或者频道做不同的动作啦!
注意吼!这个AnimationControl貌似是浅复制的,所以,我们在销毁动画实例的时候是不需要delete掉这个AnimationController的。如果delete掉一个,程序会崩掉哦!
三.进一步封装的多实例多动画骨骼动画类
这里还是简单的贴上之前的代码:
-
/*!
-
* \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;
-
}
D3DXAnimation.h修改版本:
-
/*!
-
* \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
-
.cpp文件:
-
#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;
-
}
这次最主要的类--骨骼动画实例类,
AnimInstance.h:
-
/*!
-
* \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
.cpp:
-
#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;
-
}
这次,我们读取一下tiny_4anim.x这个.X文件,然后创建10个实例,让他们随机的播放动画:
不过瘾,来50个看看:

浙公网安备 33010602011771号