骨骼动画

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

骨骼动画(Skeletal Animation)

相信这里没有人没玩过采用骨骼动画技术的游戏,看看那些热门的动作游戏,例如《波斯王子》、《分裂细胞》和《战神》,你就知道骨骼动画的威力了(我承认是猜的)。骨骼动画技术用来使我们的3D模型在屏幕上动起来,通过和动作捕捉技术结合,可以让模型做出非常逼真的动作。而这样一个极具威力的技术,其原理却相当简单。

假设我们要让游戏主角做出一个动作,例如波斯王子拿弯刀往前一劈。最简单的方法,就是让模型师建一个动画序列,然后在程序中逐帧播放,就像放电影一样。不过这样一来工作量就太大了,玩家也需要N个G的硬盘来安装这个游戏。与此不同,骨骼动画技术采用了一种很聪明的方式。首先,建模师完成一个标准姿势的3D模型,通常是双手沿着肩的方向伸展平放,双脚打开。所有的后继动作将由这个基础动作演变得到。在完成这个基准模型之后,建模师再建一个骨骼结构,一系列相互关联的顶点,就像一个骨架一样,与人体模型各个关节匹配并且都会有一定数量的顶点与之关联。想象一下人和人身上的骨骼就很容易知道我在说什么。之后,在我们想要完成的动画序列中,挑选一些关键帧,对每个关键帧,将骨骼的位置与关键帧匹配。然后把这一系列的关键帧骨骼保存起来,除了骨骼的位置,同时保存的还有从基准位置变换到当前关键帧的旋转、平移、缩放或者一个混合的坐标变换矩阵。在我们引擎中,首先根据当前时间查找这时候角色是处于哪两个关键帧中间。找到之后以时间为参数在关键帧的坐标变换矩阵之间求插值,用插值结果来决定骨骼当前的位置。骨骼位置求出来后,所有和骨骼关联的顶点的坐标也可以相应求出来了。通过使用骨骼动画技术,我们用相对较少的数据就可以播放很平滑的动画!

了解了相关原理,来看看如何在directx中播放骨骼动画。我的参考书是《Advanced Animation with DirectX》。

现在我们知道为了播放骨骼动画,需要有骨骼(bone)的数据,模型(mesh)的数据,关联骨骼和模型上每个顶点的关联数据,以及关键帧的坐标变换数据。所有这些数据必须以某种形式存在于某个地方供我们获取才行。这里要介绍的MS的x文件格式以及从中获取数据的方法。强烈建议大家都来学习一下x文件格式!你会发现它即简单又强大,即使用来存放自定义数据也是相当的方便,一旦掌握之后我保证你会对它爱不释手。

典型的x文件以数据模板和实际数据两部分组成。数据模板类似c++中的结构定义,不过更为灵活和开放。实际数据就是遵守模板定义的数据段。看一个例子,

template Employee {

<3D82AB43-62DA-11cf-AB39-0020AF71E433> // 每个模板关联唯一的GUID

STRING Name; // 姓名

DWORD Sex; // 性别

[ContactEntry] // 联系方式, 另一个模板,模板可以嵌套

}

template ContactEntry {

<4C9D055B-C64D-4bfe-A7D9-981F507E45FF> // GUID

STRING PhoneNumber; // 电话号码

STRING Address; // 地址

}

Employee David{

"David";

1;

ContactEntry{

"100-100000000";

"far far away";

}

}

从上面这个简单的例子我们就可以看出x文件的大概模样了,详细的情况大家可以参考《Advanced Animation with DirectX》。下面我们看如何来读取这样一个x文件,借助下几个对象,

ID3DXFile -- x文件格式文档对象。例如Employee.x这样一个文件。

ID3DXFileEnumObject -- 用来枚举x文档的顶级模板数据。所谓顶级模板数据是指那些没有

父模板的数据,例如上面的David数据段。

ID3DXFILEDATA -- 模板数据。上面的David和他的联系方式都是ID3DXFILEDATA

对象,自包含。

下面看实际的分析函数, 下面的代码适用于DirectX 9.0 SDK Update (October 2004),原书的代码有点过时了。

//-----------------------------------------------------------------------------

// 名称 : Parse

// 描述 : 分析x文件格式文档

//-----------------------------------------------------------------------------

bool Parse( char *filename, void **pData )

{

LPD3DXFILE lpD3DXFile;

LPD3DXFILEENUMOBJECT lpD3DXFileEnumObj;

LPD3DXFILEDATA lpD3DXFileData;

// 参数检查

if( NULL == filename )

return false;

// 创建X文件对象

HRESULT hr = D3DXFileCreate( &lpD3DXFile );

if( FAILED( hr ) )

return false;

// 注册标准模板

hr = lpD3DXFile->RegisterTemplates(

( LPVOID )D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES );

if( FAILED( hr ) )

{

Release( lpD3DXFile );

return false;

}

// 创建X文件枚举对象

hr = lpD3DXFile->CreateEnumObject(

filename, D3DXF_FILELOAD_FROMFILE, &lpD3DXFileEnumObj ); if( FAILED( hr ) )

{

Release( lpD3DXFile );

return false;

}

// 解析开始

bool parseResult = BeginParse( pData );

if( true == parseResult )

{

// 查询顶级模板数

SIZE_T childCount = 0;

lpD3DXFileEnumObj->GetChildren( &childCount );

// 分析每个订级模板

for( DWORD i=0; i

{

// 获取当前模板

hr = lpD3DXFileEnumObj->GetChild( i, &lpD3DXFileData ); if( FAILED( hr ) )

break;

相关文档
最新文档