DXUTD3D骨骼动画.docx
- 文档编号:6400783
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:35
- 大小:638.39KB
DXUTD3D骨骼动画.docx
《DXUTD3D骨骼动画.docx》由会员分享,可在线阅读,更多相关《DXUTD3D骨骼动画.docx(35页珍藏版)》请在冰豆网上搜索。
DXUTD3D骨骼动画
网格模型动画一般有两种:
一种是渐变动画;另一种是骨骼动画,这种动画包含在网格模型之中,通过网格模型不同部分之间的相对运动来实现动画。
骨骼动画基本原理
骨骼动画是目前最流行也最复杂的角色动画,它包含以下几个重要元素:
骨骼、动画。
骨骼动画思想的起源很简单,自然界中的大多数动物都拥有一套骨骼,身体的皮毛血肉都依附于骨骼,当骨骼开始运动的时候,依附于对应骨骼的皮毛血肉都随骨骼一起运动。
在三维图形编程领域,角色的躯体是由网格模型来表示的,网格模型通常由大量三角形图元组成,而三角形又是由顶点组成的。
为了模仿现实世界中角色自身的动作,就需要为角色网格模型添加一套骨骼,同时需要确定哪些顶点依附于哪块骨骼,这样当骨骼运动时就能牵引依附骨骼的顶点一起运动,这就是骨骼动画的基本原理。
骨骼动画模型的骨骼是以树状层次结构组织起来的,整个骨骼结构中有一块根骨骼,其他的骨骼都直接或间接连接到根骨骼上,形成角色模型的整个骨骼框架。
一般每块骨骼都带有两个矩阵,一个是初始变换矩阵(LocalTransformMatrix),表示骨骼的初始位置;另一个是组合变换矩阵(CombinedTransformMaitrx),用于对骨骼进行各种变换,从而实现角色动画。
在每次渲染角色模型前,需要更新整个骨骼层次结构,组合每个连续的变换,将上层骨骼的运动传递到下层骨骼,这个原理可表示为:
(子骨骼的)CombinedTransformMaitrx=(子骨骼的)LocalTransformMaitrxx(父骨骼的)CombinedTransformMaitrx
骨骼的组合变换矩阵是随动画的播放不断变化的,而它的初始变换矩阵一般是不改变的,正是所有骨骼的这些矩阵相互作用才牵引着顶点的变化,从而实现了骨骼动画。
因为一次变换只能将骨骼变换到一个特定位置,要形成连续的动画就需要一帧一帧地连续改变骨骼的位置,每次改变骨骼的位置都需要一个骨骼变换矩阵,在网格模型中不可能保存任意时刻骨骼的变换矩阵,通常是保存关键时间点骨骼的变换矩阵(即关键桢),然后在播放角色动画时,根据播放时间进行插值得到任意时刻骨骼的变换矩阵,从而形成连续的角色动画。
骨骼动画是通过骨骼变换矩阵实现的,在网格模型中保存的也是关键时间点骨骼的变换矩阵,因此插值就是针对这些关键时间点上的骨骼变换矩阵进行的。
假设在s1时刻骨骼变换矩阵是mat1,在s2时刻骨骼变换矩阵是mat2,在s1和s2之间的任意时刻s,其骨骼变换矩阵mat为:
mat=(1-w)*mat1+w*mat2
其中w是权值,通过这个权值来调节在s时刻骨骼变换矩阵中mat1和mat2所占的比重,对骨骼变换矩阵进行插值最简单的方法是线性插值,这时w=(s-s1)/(s2-s1)
骨骼动画类的设计与实现
我们需要将骨骼动画网格模型的相关操作封装到一组类和结构中,这一组类和结构可以看成一套完整的骨骼动画网格模型接口,它们之间的关系如下图所示:
其中,D3DXFRAME和D3DXMESHCONTAINER是Direct3D提供的两个结构,D3DXMESHCONTAINER结构用于保存模型的网格数据,D3DXFRAME用于保存模型的骨骼框架。
结构D3DXMESHCONTAINER_DERIVED继承自Direct3D提供的结构D3DXMESHCONTAINER,结构D3DXFRAME_DERIVED继承自Direct3D提供的结构D3DXFRAME,分别进行了相应的扩充,使其能够保存所需要的其他数据。
cAllocateHierarchy类负责从动画网格模型文件加载各种数据,该类继承自Direct3D中的ID3DXAllocateHierarchy接口。
cAnimMesh类是唯一对外开放的类,它通过cAllocateHierarchy类的对象从模型文件中加载所需的数据,并负责处理骨骼动画信息以及网格模型的渲染。
继承并扩展结构体D3DXFRAME
为了在渲染网格模型的同时播放包含在网格模型的动画,需要处理两个单独的实体:
骨骼结构(即框架结构)和网格模型。
框架结构和网格模型的相关数据分别使用D3DXFRAME_DERIVED和D3DXMESHCONTAINER_DERIVED结构保存。
需要指出的是.x文件中的一个网格模型可以由多个框架和多个网格组成,但具体到某一个框架时,它一般只有一个网格,当然它也可以有多个网格。
为了方便加载骨骼动画网格模型,Direct3D提供了两个重要的结构体:
D3DXFRAME和D3DXMESHCONTAINER,其中D3DXFRAME用来加载框架,其定义如下:
typedefstructD3DXFRAME{
LPSTRName;
D3DXMATRIXTransformationMatrix;
LPD3DXMESHCONTAINERpMeshContainer;
D3DXFRAME*pFrameSibling;
D3DXFRAME*pFrameFirstChild;
}D3DXFRAME,*LPD3DXFRAME;
显然在实现动画网格模型的绘制前,不仅要得到每个框架的初始变换矩阵,同时还要得到从该框架的所有父节点到本级框架的组合变换矩阵,这是因为任何一个父框架的位置改变都会影响该框架自身位置的变化,所以在此将结构D3DXFRAME扩展为D3DXFRAME_DERIVED,在D3DXFRAME_DERIVED中添加一个成员变量CombinedTransformMaitrx,用TransformationMatrix记录在任何动画数据未加载前框架的初始变换矩阵,也就是该框架的初始位置,用CombinedTransformMaitrx来记录从所有的父框架到该框架自身所积累起来的组合变换矩阵,这样就将整个网格模型很方便地组织起来了。
结构D3DXFRAME_DERIVED的定义如下:
structD3DXFRAME_DERIVED:
publicD3DXFRAME
{
D3DXMATRIXCombinedTransformMatrix;
};
继承并扩展结构体D3DXMESHCONTAINER
结构体D3DXMESHCONTAINER用来加载每个具体网格模型的数据,其定义如下:
typedefstructD3DXMESHCONTAINER{
LPSTRName;
D3DXMESHDATAMeshData;
LPD3DXMATERIALpMaterials;
LPD3DXEFFECTINSTANCEpEffects;
DWORDNumMaterials;
DWORD*pAdjacency;
LPD3DXSKININFOpSkinInfo;
D3DXMESHCONTAINER*pNextMeshContainer;
}D3DXMESHCONTAINER,*LPD3DXMESHCONTAINER;
结构体中没有记录网格模型的纹理信息,所以将该结构体扩展为D3DXMESHCONTAINER_DERIVED,定义如下:
structD3DXMESHCONTAINER_DERIVED:
publicD3DXMESHCONTAINER
{
IDirect3DTexture9**ppTextures;
};
其中ppTextures用来存储网格模型的纹理对象。
为了方便加载.x文件中的框架和网格模型数据,Direct3D提供了一个ID3DXAllocateHierarchy接口,该接口中有4个纯虚函数:
用来创建框架的CreateFrame(),创建网格容器的CreateMeshContainer(),销毁框架的DestroyFrame(),销毁网格容器的DestroyMeshContainer()。
应用程序会在相应的时机自动调用这些对应的函数,以构建或者销毁对应的框架或网格模型。
Method
Description
ID3DXAllocateHierarchy:
:
CreateFrame
Requestsallocationofaframeobject.
ID3DXAllocateHierarchy:
:
CreateMeshContainer
Requestsallocationofameshcontainerobject.
ID3DXAllocateHierarchy:
:
DestroyFrame
Requestsdeallocationofaframeobject.
ID3DXAllocateHierarchy:
:
DestroyMeshContainer
Requestsdeallocationofameshcontainerobject.
ID3DXAllocateHierarchy:
:
CreateFrame
HRESULTCreateFrame(
LPCSTRName,
LPD3DXFRAME*ppNewFrame
);
ID3DXAllocateHierarchy:
:
CreateMeshContainer
HRESULTCreateMeshContainer(
LPCSTRName,
CONSTD3DXMESHDATA*pMeshData,
CONSTD3DXMATERIAL*pMaterials,
CONSTD3DXEFFECTINSTANCE*pEffectInstances,
DWORDNumMaterials,
CONSTDWORD*pAdjacency,
LPD3DXSKININFOpSkinInfo,
LPD3DXMESHCONTAINER*ppNewMeshContainer
);
ID3DXAllocateHierarchy:
:
DestroyFrame
Requestsdeallocationofaframeobject.
HRESULTDestroyFrame(
LPD3DXFRAMEpFrameToFree
);
ID3DXAllocateHierarchy:
:
DestroyMeshContainer
Requestsdeallocationofameshcontainerobject.
HRESULTDestroyMeshContainer(
LPD3DXMESHCONTAINERpMeshContainerToFree
);
cAllocateHierarchy类继承自ID3DXAllocateHierarchy接口,在cAllocateHierarchy类需要重载这4个纯虚函数以实现动画网格模型数据的加载和释放。
该类的定义如下:
classcAllocateHierarchy:
publicID3DXAllocateHierarchy//?
{
private:
HRESULTAllocateName(LPCSTRname,LPSTR*ret_name);
public:
STDMETHOD(CreateFrame)(LPCSTRname,LPD3DXFRAME*ret_frame);
STDMETHOD(CreateMeshContainer)(LPCSTRname,
CONSTD3DXMESHDATA*mesh_data,
CONSTD3DXMATERIAL*xmaterials,
CONSTD3DXEFFECTINSTANCE*effect_instances,
DWORDnum_materials,
CONSTDWORD*adjacency,
LPD3DXSKININFOskin_info,
LPD3DXMESHCONTAINER*ret_mesh_container);
STDMETHOD(DestroyFrame)(THIS_LPD3DXFRAMEframe_to_free);
STDMETHOD(DestroyMeshContainer)(THIS_LPD3DXMESHCONTAINERbase_mesh_container);
};
函数AllocateFrame()用来为框架生成一个名称:
HRESULTcAllocateHierarchy:
:
AllocateName(LPCSTRname,LPSTR*ret_name)
{
if(name!
=NULL)
{
UINTlength=(UINT)strlen(name)+1;
*ret_name=newCHAR[length];
if(*ret_name==NULL)
returnE_OUTOFMEMORY;
memcpy(*ret_name,name,length*sizeof(CHAR));
}
else
{
*ret_name=NULL;
}
returnS_OK;
}
函数CreateFrame()的作用在于生成一个新的扩展框架,并按照指定的参数为该框架命名:
HRESULTcAllocateHierarchy:
:
CreateFrame(LPCSTRname,LPD3DXFRAME*ret_frame)
{
*ret_frame=NULL;
D3DXFRAME_DERIVED*new_frame=newD3DXFRAME_DERIVED;
if(new_frame==NULL)
returnE_OUTOFMEMORY;
HRESULThr=AllocateName(name,&new_frame->Name);
if(FAILED(hr))
{
deletenew_frame;
returnhr;
}
D3DXMatrixIdentity(&new_frame->TransformationMatrix);
D3DXMatrixIdentity(&new_frame->CombinedTransformMatrix);
new_frame->pMeshContainer=NULL;
new_frame->pFrameSibling=NULL;
new_frame->pFrameFirstChild=NULL;
*ret_frame=new_frame;
returnS_OK;
}
在一个框架创建好后,需要创建该框架的网格容器,这通过函数CreateMeshContainer()来实现:
HRESULTcAllocateHierarchy:
:
CreateMeshContainer(LPCSTRname,
CONSTD3DXMESHDATA*mesh_data,
CONSTD3DXMATERIAL*xmaterials,
CONSTD3DXEFFECTINSTANCE*effect_instances,
DWORDnum_materials,
CONSTDWORD*adjacency,
LPD3DXSKININFOskin_info,
LPD3DXMESHCONTAINER*ret_mesh_container)
{
*ret_mesh_container=NULL;
if(mesh_data->Type!
=D3DXMESHTYPE_MESH)
returnE_FAIL;
ID3DXMesh*mesh_ptr=mesh_data->pMesh;
DWORDfvf=mesh_ptr->GetFVF();
if(fvf==0)
returnE_FAIL;
//createameshcontainerandzeroit
D3DXMESHCONTAINER_DERIVED*new_mesh_container=newD3DXMESHCONTAINER_DERIVED;
if(new_mesh_container==NULL)
returnE_OUTOFMEMORY;
memset(new_mesh_container,0,sizeof(D3DXMESHCONTAINER_DERIVED));
//copymeshname
HRESULThr=AllocateName(name,&new_mesh_container->Name);
if(FAILED(hr))
{
DestroyMeshContainer(new_mesh_container);
returnhr;
}
IDirect3DDevice9*device;
mesh_ptr->GetDevice(&device);
new_mesh_container->MeshData.Type=D3DXMESHTYPE_MESH;
//besuremeshcontainnormal
if(!
(fvf&D3DFVF_NORMAL))
{
hr=mesh_ptr->CloneMeshFVF(mesh_ptr->GetOptions(),fvf|D3DFVF_NORMAL,device,
&new_mesh_container->MeshData.pMesh);
if(FAILED(hr))
{
release_com(device);
DestroyMeshContainer(new_mesh_container);
returnhr;
}
mesh_ptr=new_mesh_container->MeshData.pMesh;
D3DXComputeNormals(mesh_ptr,NULL);
}
else
{
new_mesh_container->MeshData.pMesh=mesh_ptr;
mesh_ptr->AddRef();//!
!
important,soDestroyMeshContainer()willnotcrash.
}
//loadmaterialsandtextures
UINTnum_faces=mesh_ptr->GetNumFaces();
new_mesh_container->NumMaterials=max(1,num_materials);
new_mesh_container->pMaterials=newD3DXMATERIAL[new_mesh_container->NumMaterials];
new_mesh_container->ppTextures=newLPDIRECT3DTEXTURE9[new_mesh_container->NumMaterials];
new_mesh_container->pAdjacency=newDWORD[num_faces*3];
if((new_mesh_container->pAdjacency==NULL)||(new_mesh_container->pMaterials==NULL)||
(new_mesh_container->ppTextures==NULL))
{
release_com(device);
DestroyMeshContainer(new_mesh_container);
returnE_OUTOFMEMORY;
}
memcpy(new_mesh_container->pAdjacency,adjacency,sizeof(DWORD)*num_faces*3);
memset(new_mesh_container->ppTextures,0,sizeof(LPDIRECT3DTEXTURE9)*new_mesh_container->NumMaterials);
D3DXMATERIAL*xmaterials_ptr=new_mesh_container->pMaterials;
if(num_materials>0)
{
memcpy(xmaterials_ptr,xmaterials,sizeof(D3DXMATERIAL)*num_materials);
xmaterials_ptr->MatD3D.Ambient=xmaterials_ptr->MatD3D.Diffuse;
for(UINTi=0;i { if(xmaterials_ptr[i].pTextureFilename! =NULL) { WCHARw_texture_path[MAX_PATH]; WCHARw_filename[MAX_PATH]; RemovePathFromFileName(xmaterials_ptr[i].pTextureFilename,w_filename); DXUTFindDXSDKMediaFileCch(w_texture_path,MAX_PATH,w_filename); if(FAILED(D3DXCreateTextureFromFileW(device,w_texture_path,&new_mesh_container->ppTextures[i]))) new_mesh_container->ppTextures[i]=NULL; } } } else { xmaterials_ptr[0].pTextureFilename=NULL; memset(&xmaterials_ptr[0].MatD3D,0,sizeof(D3DMATERIAL9)); xmaterials_ptr[0].MatD3D.Diffuse.r=0.5f; xmaterials_ptr[0].MatD3D.Diffuse.r=0.5f; xmaterials_ptr[0].MatD3D.Diffuse.b=0.5f; xmaterials_ptr[0].MatD3D.Specular=xmaterials_ptr[0].MatD3D.Diffuse; xmaterials_ptr[0].MatD3D.Ambient=xmaterials_ptr[0].MatD3D.Diffuse; } release_com(device); *ret_mesh_container=new_mesh_container; returnS_OK; } 在此实现的骨骼动画网格模型中没有涉及到蒙皮信息,所以在CreateMeshContainer()函数中没有处理参数skin_info指向的蒙皮信息。 函数DestroyFrame
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DXUTD3D 骨骼 动画
![提示](https://static.bdocx.com/images/bang_tan.gif)