这两天在做 3D蒙皮动画时遇到些问题,折腾了一天半,嗨!很郁闷啊!我要大叫来发泄一下。
本来打算用D3D设备直接设置世界坐标矩阵来实现动画的,但发现有一个问题,当我不使用D3DXEFFECT来设置渲染效果的时候就可以正常显示动画;当我使用它来设置渲染效果的时候,动画就没了。我想可能是用D3DXEFFECT来设置渲染效果的时候把D3D设备的 SetTransform功能屏蔽掉了(其实我不理解这个渲染过程^_^)。
下面说一下加载和渲染蒙皮动画的大概流程吧。
首先继承2个结构:D3DXFRAME、D3DMESHCONTAINER 和一个接口:ID3DXAllocateHierarchy。
//------------------------------------------------------------
//说明:框架
//------------------------------------------------------------
struct GFrame : public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix; //最终变换矩阵
};
//------------------------------------------------------------
//说明:网格容器
//------------------------------------------------------------
struct GMeshContainer : public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9 * _ppTexs; //纹理列表
LPD3DXMESH _pOrigMesh; //原mesh
DWORD _dwNumAttrGroups; //属性组个数
DWORD _dwMaxNumInfl; //一个面最多受多少骨骼影响
DWORD _dwNumPaletteEntries; //样色个数
LPD3DXBUFFER _pBoneCombBuf; //邻接矩阵列表
D3DXMATRIX** _ppBoneMatrixPtr; //骨骼矩阵列表
D3DXMATRIX* _pBoneOffsetMatrices; //骨骼矩阵引用
DWORD _iAttrSW; //用户 GenerateSkinnedMesh
};
//------------------------------------------------------------
//说明:封装网格的创建类
//------------------------------------------------------------
class GAllocateHierarchy : public ID3DXAllocateHierarchy
{
public:
// 下面4个方法是对父类的实现
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);
};
创建两个全局指针:
LPD3DXFRAME g_pFrameRoot = NULL; //根Frame
ID3DXAnimationController* g_pAnimCtl = NULL; //动画控制类
接着在初始化的地方(如果使用DXUT,则可以在OnCreateDevice中)调用 D3DXLoadMeshHierarchyFromX 来加载x文件。
GAllocateHierarchy ah;
D3DXLoadMeshHierarchyFromX( strXFileName, D3DXMESH_MANAGED, pDev,
& ah, NULL, & g_pFrameRoot, &g_pAnimCtl );
SetupBoneMatrixPointers( g_pFrameRoot, g_pFrameRoot); //建立矩阵指针
D3DXFrameCalculateBoundingSphere( g_pFrameRoot, & g_vObjCenter, g_fObjRadius ); //获取模型边界球
SetupBoneMatrixPointers 实现如下:
接着在更新信息的地方(如果使用DXUT,则可以在OnFrameMove中添加)添加以下代码:
UpdateFrameMatrices( g_pFrameRoot, &matWorld); //更新骨骼矩阵(其中 matWorld 可以包含模型的平移、缩放、旋转信息)
if( g_pAnimCtl != NULL)
g_pAnimCtl->AdvanceTime( fElapsedTime, NULL); //更新动画信息就靠它了
UpdateFrameMatrices 的实现如下:
最后在渲染的地方(如果使用DXUT,则在 OnFrameRender中)调用:
DrawFrame( pDev, g_pFrameRoot);
DrawFrame 的实现如下:
到此为止就可以实现加载和渲染动画了,这个实现的过程也有点复杂,一不小心搞错了某个地方,可能折腾半天都找不出原因。