Ogre参考手册(十二) 8 动画

8 动画

Ogre提供灵活的动画系统支持以下几种动画:

8.1 骨骼动画

骨骼动画通过移动网格中的树结构骨头实现,顶点通过绑定的骨头进行相应的移动。骨骼动画也叫皮肤动画。通常通过建模工具如SoftimageXSI,milkshape3D,Blender,3d Studio,Maya等创建。Ogre提供导出工具可以将这些模型转换为Ogre引擎自己的格式

可以为骨骼动画提供不同级别的支持,并不是所有引擎(包括建模工具)都支持全部的功能。Ogre支持以下内容:

l  每个网格可以关联到一个骨骼

l  一个骨骼可以支持无限的骨头

l  树结构的正向运动学

l  一个骨骼支持多个命名动画

l  每个动画支持无限的关键帧

l  线性或spline关键帧差值

l  顶点可以绑定多个骨头并设置权重以实现平滑皮肤

l  网格可同时使用权重应用多个动画,

骨骼和伴随的动画都保存在Ogre导出工具生成的.skeleton文件中。当你基于Mesh创建Entity时,关联的骨骼会自动加载。之后你可以使用AmimationState应用动画

骨骼动画既可以通过软件也可通过着色器(硬件皮肤/蒙皮)实现。无疑,硬件方式更好,因为可将一些工作从CPU移到GPU,同时也意味着不需要在每帧重新上传顶点数据。这对于巨大的、高细节模型特别重要。你应该尽可能使用硬件皮肤;这需要为材质设置顶点程序。参考顶点程序中的骨骼动画。骨骼动画可同时与顶点动画混合,参考混合骨骼和顶点动画

8.2 动画状态(animation State)

当包含任何类型动画的实体(Entity)被创建时,会为每个动画生成AnimationState对象

可通过Entity::getAnimationState获取AnimationState指针,之后使用该指针更新动画状态(一般在frameStated事件中)。AnimationState需要先通过setEnabled设置为有效,可以通过相应方法设置权重和时间位置。也可以用addTime以增量的方式改变动画位置,该方法自动处理循环,addTime可以使用负值用于反向动画。

8.3 顶点动画

顶点动画直接移动网格的顶点。每个顶点动画轨迹需要一个VertexData实例。顶点动画保存在.mesh文件中,因为其与网格的顶点结构关系很密切。

顶点动画分为两种:

l  变形动画(morph) 变形动画通过关键帧直接插值的简单技术实现,变形动画与骨骼动画广泛使用之前的古老的院校式动画有直接联系

l  姿态动画(pose) 姿态动画通过混合多个不相关的姿态实现,姿态表现为相对于基础顶点数据的偏移,并通过不同权重生成最终的效果。姿态动画最明显的用途时面部动画

为什么分为两种子类型

事实上,两种顶点动画都可以使用姿态动画实现。提供独立的变形动画是因为,变形动画的分组方式容易定义,同时对硬件着色器的需求更低。

变形动画提供了一系列用于差值的顶点数据快照,实现动画很简单。因为只是在关键帧之间线性差值,因此可以很快的对整个网格应用动画。不过这种简单方式不支持多个变形动画混合。如果你需要混合动画,建议在为整个网格应用动画时使用骨骼动画,在部分网格或者不适合骨骼动画时(如面部动画)使用姿态动画。在着色器中处理动画时,变形动画仅需要两个顶点缓冲区存放绝对的位置数据,以及一个差值系数。变形动画的每个轨迹对应唯一的顶点数据。

姿态动画更复杂一些,像变形动画一样,每个轨迹需要一组唯一的顶点数据。但不同的是,每个关键帧可以引用1到多个姿态,采用各自的影响系数。姿态是相对于基础顶点数据的偏移,而且可以是稀疏的(不需要引用所有顶点)。因为是偏移,因此可在同一轨迹或者多个动画间混合。这些特性特别适合脸部动画。

比如说,你制作一个脸部模型,定义了一组表示各种语音的姿态。之后你就可以定义一个动画叫”sayhello”,包含参照脸部基础数据的一个轨迹,轨迹包含一系列的关键帧,每个关键帧引用1到多个面部位置并采用不同的影响系数,这些在时间上的组合形成了说”hello的表情。因为姿态仅存储一次,而可以在多个动画中采用,是构建语音系统的有力方式。

姿态动画的不利之处是难以建立,需要分别定义关键帧引用的各种姿态。同时因为使用了更多的缓冲区(分别用于基础数据以及每个激活的姿态),你需要在使用硬件顶点着色器处理动画时,考虑同时混合的姿态个数。通过使用材质脚本includes_pose_animation,顶点程序定义可以指定最大的支持个数,参考在顶点程序中使用姿态动画。

这样通过将顶点动画分为两种实现方式,可以保持简单的变形技术易于使用,同时允许强大的姿态动画技术。注:变形动画不能与其它类型的顶点动画混合,姿态动画可以和姿态动画混合。同时所有的变形动画都可以用姿态动画实现(更复杂的方式),反过来不行。

子类型应用基于轨迹

主要注意子类型位于轨迹层级,不是动画或网格层级。因为轨迹映射到VertexData示例,这意味着如果网格划分为多个子网格(submesh),没有用于各自的几何体,你可以在一个子网格应用姿态动画,一个使用变形动画(或者非顶点动画)。

比如对一个复杂角色的常用设置,将头划分为独立的子网格,对头使用姿态动画,其它则采用骨骼动画

顶点缓冲区安排

使用软件处理顶点动画时,应将顶点的位置放在单独的硬件缓冲区中。这样可以避免在更新时上传其它的顶点数据,避免GPU带宽饱和。当使用Ogre导出工具创建的.mesh格式,Ogre自动做了这样的处理。如果你自己创建缓冲,就需要处理布局

Ogre::Mesh提供了一组函数辅助处理这些。Ogre::VertexDeclaration::getAutoOrganisedDeclaration()可以将顶点声明转换为推荐的方式,Ogre::VertexData::reorganiseBuffers()可以重新组织缓冲区的内容。

8.3.1 变形动画(morph)

变形动画在每个关键帧存储绝对的顶点位置,通过插值实现。用于不适合使用骨骼动画的时候;通常是对象的结构和形状在动画中有了彻底的改变,不大适合骨骼动画。

因为使用了绝对的位置,不大可能对使用相同顶点数据的变形动画进行混合。如果需要混合你应该使用更有效的骨骼动画。如果你激活了同一顶点数据的多个变形动画,则仅最后一个有效。这意味着animationstate的weight选项对变形动画没用

需要的话变形动画可以与骨骼动画混合,参考混合骨骼和顶点动画。变形动画还可以通过顶点着色器实现,参考:顶点程序中的变形动画

8.3.2 姿态动画(pose)

姿态动画允许多个不同影响系数的姿态混合为最终的顶点状态。通常用于面部动画,此时每种表情作为独立的动画,通过权重彼此混合或者在各自影响不同部分的时候组合。

为了实现这些,姿态动画通过引用相对于原始数据偏移量的姿态定义。姿态动画不需要为所以顶点指定偏移。使用软件混合的时候,这些顶点会完全跳过。在使用硬件时(需要为每个顶点对应顶点项),自动创建的顶点项不包括0偏移的顶点。

定义好的姿态可以在动画中引用。每个动画轨迹引用单个几何体(共享的几何体或者子网格专有的几何体),轨迹中的关键帧尅引用一到多个姿态,每个姿态对应不同的影响系数。整个动画的权重也会缩放这些影响系数。相邻关键帧存在引用而当前关键帧无引用的姿态影响系数做0处理。

你应该注意同时启用的姿态个数。当使用硬件处理姿态动画时,每个激活的姿态都需要一个顶点缓冲区。当你在一个帧使用两个姿态,而在下一帧使用不同的两个时,事实上需要四个活动的姿态以用于差值。

你可以混合姿态动画和骨骼动画,参考混合骨骼和顶点动画,你还可以使用硬件加速,参考顶点程序中的姿态动画

8.3.3 混合骨骼和顶点动画

可以对一个实体同时使用骨骼和顶点动画。此时先应用顶点动画,然后再进行骨骼动画。这允许对角色的面部采用姿态顶点动画的同时利用骨骼动画实现主要的运动动画。

从用户角度看,混合两者像同时启用两个动画一样简单。不过伴随这一很有用的功能,有一些问题需要注意:

混合硬件皮肤

对于复杂的角色,通过顶点程序实现硬件皮肤是个好主意。参考:顶点程序中的动画

你需要以Ogre同样的方式实现动画,即先实现顶点动画,然后再应用骨骼动画。记住,变形动画需要两个对应开始/结束关键帧的绝对位置快照缓冲区和一个差值参数,姿态动画需要一个基础顶点数据、n个姿态偏移缓冲区和n个权重参数(n为激活的姿态个数)。

子网格划分

如果你仅对网格的一小部分进行顶点和骨骼混合,比如面部,你应该将网格划分为两部分,一部分需要混合(头部),一部分不需要混合。这可以减少计算负荷,同时可减少顶点缓冲区使用,因为顶点关键帧和姿态缓冲区同样变小了。这样你需要实现两个独立的顶点程序,一个仅处理骨骼动画,另一个同时实现骨骼和顶点动画

8.4 场景节点动画

场景节点动画通过SceneManager创建,在移动节点的同时移动关联的对象。你可以通过例子CameraTrack中的相机和Fresnel中的鱼对此进行了解。

场景节点动画基本上与骨骼动画的代码相同。通过SceneManager::createAnimation创建主动画后,可以为每个节点创建NodeAnimationTrack ,同时创建控制位置、朝向和缩放的关键帧以用于线性或spline差值。你可以用骨骼动画同样的方式使用AnimationState,区别在于其通过SceneMananger获取,而不是Entity。动画在各帧会自动应用,你可以手工通过SceneManager::_applySceneAnimations()控制。

8.5 数值动画

除了前面所说的几种常用的动画类型之外,你还可以利用动画改变任何通过AnimableObject接口暴露的数值。(此类动画不是改变几何网格,只是改变数值,一般是对象的属性值)

AnimableObject

AnimableObject是一个抽象接口,用于维护和访问AnimableValue。AnimableObject维护了一个所有可用动画属性的字典,可以通过getAnimableValueNames获取。可以使用createAnimableValue创建AnimableValue对象,AnimableValue用于关联动画接口和具体的对象属性值(由NumericAnimationTrack启动并最终调用AnimableValue::applyDeltaValue)。

一个例子是Ogre::Light类,Light类扩展了AnimableObject接口(通过继承MovableObject,MovableObject直接继承了AnimableObject)并提供一组AnimableValue对象用于修改diffuseColour\attenuation等属性。可以创建NumericAnimationTrack并通过这些值对象修改Light的属性。其它自定义对象都可以通过同样的方式支持动画属性。

AnimableValue

实现自定义动画属性时,需要实现Animable接口。它们并不是纯虚方法,因为你只需要实现动画属性对应类型的方法。可参考Ogre::Light类实现

原文地址:https://www.cnblogs.com/wiki3d/p/4658293.html