您的位置:首页 > 其它

【DirectX】D3D骨骼动画的实现(总结)

2011-11-16 10:34 387 查看
typedef struct _D3DXFRAME{ //骨骼(框架)结构体

LPSTR Name; //骨骼名

D3DXMATRIX TransformationMatrix; //相对于父骨骼坐标系的变换矩阵

LPD3DXMESHCONTAINER pMeshContainer; //网格容器

struct _D3DXFRAME* pFrameSibling; //兄弟骨骼

struct _D3DXFRAME* pFrameFirstChild;//子骨骼

}D3DXFRAME,LPD3DXFRAME;

typedef struct _D3DMESHCONTAINER{ //网格容器结构体

LPSTR Name; //网格容器名

D3DXMESHDATA MeshData; //网格数据

LPD3DMATERIAL pMaterials; //网格材质

LPD3DXEFFECTINSTANCE pEffects; //特效

DWORD NumMatrials; //材质数

DWORD* pAdjacency; //邻接三角形信息

LPD3DXSKININFO pSkininfo; //蒙皮信息

struct _D3DMESHCONTAINER* pNextMeshContainer; //下一个网格容器指针

}D3DMESHCONTAINER, *LPD3DMESHCONTAINER;

struct D3DXFRAME_DERIVED:public D3DXFRAME{ //骨骼(框架)扩展结构体

D3DXMATRIXA16 CombinedTransformationMatrix; //动作变换矩阵

};

struct D3DMESHCONTAINER_DERIVED:public D3DMESHCONTAINER{ //网格容器扩展结构体

LPDIRECT3DTEXTURE9* ppTextures; //纹理数组,如果没有纹理数组则为NULL

LPD3DXMESH pOrigMesh; //原网格

LPD3DXATTRIBUTERANGE pAttributeTable; //属性表

DWORD NumAttributeGroups; //属性组个数

DWORD NumInfl;

LPD3DXBUFFER pBoneCombinationBuf; //骨骼缓冲区

D3DXMATRIX** ppBoneMatrixPtrs; //骨骼矩阵

D3DXMATRIX* pBoneOffsetMatrices; //骨骼权重矩阵

DWORD NumPaletteEntries;

};

//在内存中创建一个Frame(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::CreateFrame(

LPCSTR Name, //框架名

LPD3DXFRAME* ppNewFrame //返回创建的Frame对象

)

//创建一个网格容器(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::CreateMeshContainer(

LPCSTR Name, //网格容器名

const D3DXMESHDATA* pMeshData, //网格数据

const D3DXMATERIAL* pMaterials, //网格材质

const D3DXEFFECTINSTANCE* pEffectInstances, //效果

DWORD NumMaterials, //材质数目

const DWORD* pAjacency, //邻接三角形信息

LPD3DXSKININFO pSkinInfo, //蒙皮信息

LPD3DXMESHCONTAINER* ppNewMeshContainer //返回创建的网格对象

);

//释放一个帧(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::DestroyFrame(

LPD3DXFRAME pFrameToFree

);

//释放网格容器(纯虚函数,需要给出具体的实现细节)

virtual HRESULT ID3DXAllocateHierarchy::DestroyMeshContainer(

LPD3DMESHCONTAINER pMeshContainerToFree

);

//ID3DXAllocateHierarchy接口的扩展类

class CAllocateHierarchy: public ID3DXAllocateHierarchy

{

public:

STDMETHOD(CreateFrame)(THIS_ LPCTSTR 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);

public:

CAllocateHierarchy(CSkinMesh *pSkinMesh) :m_pSkinMesh(pSkinMesh) {}

CSkinMesh* m_pSkinMesh;

};

/*----------------------该类的实现细节(内含4个纯虚函数的实现细节)-------------------------*/

//骨骼名称命名

HRESULT AllocateName( LPCTSTR Name, LPTSTR *pNewName )

{

UINT cbLength;

if (Name != NULL)

{

cbLength = lstrlen(Name) + 1;

*pNewName = new TCHAR[cbLength];

if (*pNewName == NULL)

return E_OUTOFMEMORY;

memcpy(*pNewName, Name, cbLength*sizeof(TCHAR));

}

else

{

*pNewName = NULL;

}

return S_OK;

}

//创建并初始化一个帧并命名

HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR 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;

//初始化帧的数据

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;

}

//创建网格容器

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;

if (pMeshData->Type != D3DXMESHTYPE_MESH) //如果不是网格数据类型

{

hr = E_FAIL;

goto e_Exit;

}

pMesh = pMeshData->pMesh;

if (pMesh->GetFVF() == 0) //取得定点的可变格式,返回0表示不能转换为可变格式

{

hr = E_FAIL;

goto e_Exit;

}

pMeshContainer = new D3DXMESHCONTAINER_DERIVED; //申请内存

if (pMeshContainer == NULL)

{

hr = E_OUTOFMEMORY;

goto e_Exit;

}

memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED)); //内存置0

hr = AllocateName(Name, &pMeshContainer->Name); //网格容器命名

if (FAILED(hr))

goto e_Exit;

pMesh->GetDevice(&pd3dDevice); //获得容器设备

NumFaces = pMesh->GetNumFaces(); //获得网格的三角形面数

//如果没有法向量,则添加它们

if (!(pMesh->GetFVF() & D3DFVF_NORMAL))

{

pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

//先复制

hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),

pMesh->GetFVF() | D3DFVF_NORMAL,

pd3dDevice, &pMeshContainer->MeshData.pMesh );

if (FAILED(hr))

goto e_Exit;

pMesh = pMeshContainer->MeshData.pMesh;

//生成法向量

D3DXComputeNormals( pMesh, NULL );

}

else

{

pMeshContainer->MeshData.pMesh = pMesh;

pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;

pMesh->AddRef();

}

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 (NumMaterials > 0)

{

memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials);

for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)

{

if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL)

{

TCHAR* strTexturePath=pMeshContainer->pMaterials[iMaterial].pTextureFilename;

if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,

&pMeshContainer->ppTextures[iMaterial] ) ) )

pMeshContainer->ppTextures[iMaterial] = NULL;

pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;

}

}

}

else //没有材质,则添加一个默认值

{

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 (pSkinInfo != NULL)

{

pMeshContainer->pSkinInfo = pSkinInfo;

pSkinInfo->AddRef();

pMeshContainer->pOrigMesh = pMesh; //备份指针

pMesh->AddRef();

cBones = pSkinInfo->GetNumBones();

pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];

if (pMeshContainer->pBoneOffsetMatrices == NULL)

{

hr = E_OUTOFMEMORY;

goto e_Exit;

}

//取得骨骼的权重矩阵

for (iBone = 0; iBone < cBones; iBone++)

{

pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));

}

//生成蒙皮网格

hr = m_pSkinMesh->GenerateSkinnedMesh(pMeshContainer);

if (FAILED(hr))

goto e_Exit;

}

*ppNewMeshContainer = pMeshContainer;

pMeshContainer = NULL;

e_Exit:

SafeRelease(pd3dDevice);

//释放网格容器

if (pMeshContainer != NULL)

{

DestroyMeshContainer(pMeshContainer);

}

return hr;

}

//释放帧

HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)

{

SafeDeleteArray( pFrameToFree->Name );

SafeDelete( pFrameToFree );

return S_OK;

}

//释放网格容器

HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)

{

UINT iMaterial;

D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;

SafeDeleteArray( pMeshContainer->Name );

SafeDeleteArray( pMeshContainer->pAdjacency );

SafeDeleteArray( pMeshContainer->pMaterials );

SafeDeleteArray( pMeshContainer->pBoneOffsetMatrices );

//释放所有纹理对象

if (pMeshContainer->ppTextures != NULL)

{

for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)

{

SafeRelease( pMeshContainer->ppTextures[iMaterial] );

}

}

SafeDeleteArray( pMeshContainer->ppTextures );

SafeDeleteArray( pMeshContainer->ppBoneMatrixPtrs );

SafeRelease( pMeshContainer->pBoneCombinationBuf );

SafeRelease( pMeshContainer->MeshData.pMesh );

SafeRelease( pMeshContainer->pSkinInfo );

SafeRelease( pMeshContainer->pOrigMesh );

SafeDelete( pMeshContainer );

return S_OK;

}

//装入骨骼动画

HRESULT WINAPI D3DXLoadMeshHierarchyFromX(

LPCTSTR Filename, //骨骼动画的.x文件名

DWORD MeshOptions, //D3DXMESH_MANAGED等选项

LPDIRECT3DDEVICE pDevice, //关联的3D设备

LPD3DXALLOCATEHIERARCHY pAlloc, //Frame层次对象生成接口

LPD3DXLOADUSERDATA pUserDataLoader, //一般为NULL

LPD3DXFRAME* ppFrameHierarchy, //返回已具有层次结构的根Frame指针

LPD3DXANIMATIONCONTROLLER* ppAnimController //返回相应的动画控制器

);

//生成蒙皮网格

HRESULT ID3DXSkinInfo::ConvertToIndexedBlendedMesh(

LPD3DXMESH pMesh, //传入的原网格

DWORD Options, //当前并未使用

DWORD paletteSize, //骨骼矩阵调用

const DWORD* pAdjacencyIn, //传入的临界三角形信息

LPDWORD pAdjacencyOut, //一般为NULL

DWORD* pFaceRemap, //一般为NULL

LPD3DXBUFFER* ppVertexRemap, //一般为NULL

DWORD* pMaxVertexInfl, //一个顶点可以受到骨骼影响的最大骨骼数

DWORD* pNumBoneCombinations, //骨骼组合属性表中的骨骼数

LPD3DXBUFFER* ppBoneCombinationTable, //骨骼组合属性表

LPD3DMESH* ppMesh

);

//ppBoneCombinationTable(骨骼组合属性表)的元素定义

typedef struct _D3DXBONECOMBINATION{

DWORD AttribId; //子集的属性id

DWORD FaceStart; //起始三角形面

DWORD FaceCount; //子集的三角形面个数

DWORD VertexStart; //起始顶点

DWORD VertexCount; //顶点计数

DWORD* BoneId; //该子集的各个骨骼

}D3DXBONECOMBINATION, *LPD3DXBONECOMBINATION;

//释放骨骼框架

HRESULT D3DXALLOCATEHIERARCHY::D3DXFrameDestroy(

LPD3DXFRAME pFrameRoot, //根帧指针

LPD3DXALLOCATEHIERARCHY pAlloc //创建帧层次结构的接口

);

//调整当前动画的时间点

HRESULT D3DXANIMATIONCONTROLLER::AdvanceTime(

DOUBLE TimeDelta, //动画进行的时间

LPD3DXANIMATIONCALLBACKHANDLER pCallbackHandler //回调处理,可设置为NULL

);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: