OGRE1.9 Facial Animation实例

Introduction

在Ogre1.9的Facial Animation中采用了顶点动画(确切点说是Pose Animation)让面部产生面部表情及发音动画。


一、顶点动画(Vertex Animation)

顶点动画是直接使用顶点让网格(mesh)产生动画的一种方式。每一组动作在顶点动画中对应一个顶点数据实体。顶点动画被存储在.mesh文件中,因为它与网格的顶点紧密相连。实际上,顶点动画分为两种子类型。(具体参考OGRE Manual相关内容


1、Morph Animation(变形动画)

变形动画依靠在每个关键帧中及其之间保存和插入顶点绝对位置的快照(snapshot)。当骨骼动画不能恰当处理动画对象时,变形动画会比较有用。在分物体必须从根本改变动画部分的结构和形状时,骨骼动画就不适合了。
由于绝对位置数据的使用,不可能在同样的顶点数据中混合多于一个的变形动画;如果你想使用动画混合,你应该使用骨骼动画,因为它更有效。如果你激活了在同一个顶点数据中包含的多个动画,只有最后一个有效。也就是说动画状态的"weight"选项不能被用于变形动画。
Morph animation can be combined with skeletal animation if required See section Combining Skeletal and Vertex Animation. Morph animation can also be implemented in hardware using vertex shaders, See Morph Animation in Vertex Programs

2、Pose Animation(姿态动画)

姿态动画允许将多个潜在的不同效果等级的顶点姿态(Vertex Poses)混合成最终的顶点状态。该动画通常用于面部动画,在这种动画中每一个面部表情被作为一个独立的动画,我们可以将一个表情混合在另外一个上,如果每个姿态只影响面部的一部分,也可以组合所有的表情。
为了产生姿态动画,需要引用预先包含在Mesh中的一套动作集,这些动作集采用与源顶点的偏移量来表示。但是并不要求每一个都有偏移量,当用软件处理这些数据时,没有偏移量的顶点会被忽略掉,如果用硬件处理的话,没有偏移量的顶点会自动被填充为0。
一旦定义好了姿态,你就可以在动画中引用它们。每一个姿态动画轨迹(Pose Animation Track)对应着一个单独的几何数据集合(或者与物体网格Mesh对应,或者是其中的某个子网格Submesh对应),在动画中的每个关键帧可以引用一个或多个姿态(Pose),且每一个有其相应的影响值(Influence)。你能定义许多关键帧,使用多种姿态的混合,从而产生多个部位协调运动的动画。
应该小心多个姿态同时应用的情况。当在硬件中处理姿态动画的时候(参考Ogre Manual Pose Animation in Vertex Programs),每个激活的动作都需要额外的顶点缓冲器加入到渲染器(shader)中,如果采用软件来处理动画,你处理的激活姿态越多消耗的时间也就越长。也就是说,在一个关键帧中如果有两个姿态,在下一帧中也有两个,那么在它们过渡之间实际上就有4个激活的关键帧。
You can combine pose animation with skeletal animation, See section Combining Skeletal and Vertex Animation, and you can also hardware accelerate the application of the blend with a vertex shader, See Pose Animation in Vertex Programs


二、Pose Animation xml结构

<mesh>

<submeshes>

<submesh material="子网格材质" ...>

<faces count="面数">

<face ... />

</faces>

<geometry vertexcount="顶点数">

<vertexbuffer ...> // 顶点缓冲器内容

<vertex>

<position 顶点位置>

<normal 顶点法向量>

<texcoord 纹理坐标>

</vertex>

</submesh>

</submeshes>

<submeshnames> // 主要是为pose和animation提供索引号

<submeshname name="子网格的名字" index="子网格的索引号(从0开始)">

</submeshnames>

<poses> // 这些参数主要是对手调动画有效

<pose target="submesh or mesh" index="对应哪个网格的姿态" name="姿态的名字">

<poseoffset index="顶点索引" x y z相对偏移量 />

</pose>

</poses>

<animations> // 下面这些动画对于自动播放动画有效

<animation name="动画名字" length="帧长度">

<tracks> // 动画迹

<track target="submesh or mesh" index="姿态索引号" type="动画类型,这里是pose">

<keyframes> // 关键帧

<keyframe time="时间">

<poseref poseindex="pose索引" influence="影响值[0-1]" />

</keyframe>

</keyframes>

</track>

</tracks>

</animation>

</animations>

</mesh>


三、姿态动画(Pose Animation)处理步骤(具体参考Ogre的FacialAnimation)

(1)加载mesh纹理

(2)创建动画createAnimation

(3)创建顶点轨迹跟踪createVertexTrack

(4)创建顶点姿势关键帧createVertexPoseKeyFrame(只用了一帧)

(5)增加所有的姿势关联addPoseReference

(6)关键帧的更新姿势关联updatePoseReference

(7)调用动画状态的父通知来更新动画getParent->_notifyDirty()

四、具体实现

1 建模工具对Pose Animation的支持

Facial Demo中所用的头部模型是由SoftImage授权使用的XSI面部动画模型,不是所有的导出工具都支持Pose Animation,目前有 SoftImage XSI 5.0 Exporter v1.2.3、oFusion Pro for 3ds max、Maya Ogre导出器支持。

2 关键顶点的寻找

通过分析xml中的poseoffset偏移量,可以看到许多非常小的数据,这些数据是由模型导出工具产生的,其实它们完全可以被忽略掉。通过实验,我将原来604个顶点的poseoffset数据减少为75个,而且效果和原来相差不大,说明这75个poseoffset对应的顶点是该动画的关键顶点。

3 在程序中如何读取Pose Animation

下面是包括在场景创建函数createScene中创建动画的代码:


(1)载入包含pose animation的mesh

// pre-load the mesh so that we can tweak it with a manual animation
mHeadMesh = MeshManager::getSingleton().load("facial.mesh", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

(2)创建动画createAnimation :创建动画将其命名为Manual,并将长度初始化为0

(3)创建顶点轨迹跟踪createVertexTrack:这些动画pose被定义在<pose>标签中

(4)创建顶点姿势关键帧createVertexPoseKeyFrame:创建手动动画,并将关键帧起始位置置为0
// create a manual animation, create a pose track for it, and create a keyframe in that track
mManualKeyFrame = mHeadMesh->createAnimation("Manual", 0)->createVertexTrack(4,
VAT_POSE)->createVertexPoseKeyFrame(0);

(5)增加所有的姿势关联addPoseReference
// create pose references for the first 15 poses
for (unsigned int i = 0; i < 15; i++) mManualKeyFrame->addPoseReference(i, 0);

(6)创建实体
// create a head entity from the mesh and attach it to a node with a vertical offset to center it
Entity* head = mSceneMgr->createEntity("Head", "facial.mesh");
mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, -30, 0))->attachObject(head);

(7)从mesh中得到名为action的动画参数(在<animations>标签中定义);
获取先前从mesh文件中得到的动画Manual

// get the animation states
mSpeakAnimState = head->getAnimationState("Speak");
mManualAnimState = head->getAnimationState("Manual");

下面是包括在sliderMoved函数中的代码:

(8)关键帧的更新姿势关联updatePoseReference

// update the pose reference controlled by this slider
mManualKeyFrame->updatePoseReference(StringConverter::parseInt(slider->getName().substr(4)), slider->getValue());

(9)调用动画状态的父通知来更新动画

// dirty animation state since we're fudging this manually
mManualAnimState->getParent()->_notifyDirty();


下面是包括在frameRenderingQueued函数中的代码:

下面在是每一帧渲染开始都会调用的frameStarted函数中自动播放动画代码:
// 根据自上一帧以来所消耗的秒数来修改调整关键帧位置
if(mPlayAnimation) mSpeakAnimState->addTime(evt.timeSinceLastFrame);


References

http://www.ogre3d.org/docs/manual/manual_78.html#Vertex-Animation

http://www.cnblogs.com/lancidie/archive/2010/09/24/1833964.html

http://blog.csdn.net/zhuxiaoyang2000/article/details/7266048

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值