《Pro Ogre 3D Programming》 读书笔记 之 第九章 动画 (转)
概述
动画,总的来讲,在计算机发展的各个阶段,与艺术家们快速浏览一系列彼此稍微不同的图片从而产生运动的幻觉的行为没有什么不同。1872年,Eadweard Muybridge给奔跑的马拍了一组连续的照片,从而证明了马在奔跑时会四脚同时离地。这是一系列的图片流可以产生运动幻觉的最早的文档化的记录。
现在在Ogre中,不必小题大作地装配一些设备来创造这种运动幻觉了。只需要每帧少量地移动或变形场景中的数据,幻觉就产生了。它确实只是幻觉。ogre不跟踪对象的速度,加速度,或是角色的胳膊是在抬起
或是叉着腰。ogre逐帧来处理位置与朝向。ogre能为你做的是帮你重新播放这些动画。这些动画可以是用离线工具制作的,或是运行时产生的,或仅是为了实现相机漫游而填充了一系列位置的曲线。
场景的每帧都会被重画,两帧之间没有什么会被保存下来。ogre中的动画仅仅是根据关于任意变量(通常
是时间)的函数,来定位与定向角色。每一帧,在ogre动画系统的控制之下,场景中的实体与动画被稍稍
移动或产生变形,然后场景被重画。这种产生动画的方式,与华纳兄弟的动画团队做卡通动画没什么同。
一行画24个卡通兔,彼此稍微不同,然后在1秒钟的时间连续播放。
Ogre中的动画类型
根据控制物体的不同方式分为两种:基于关键帧的动画,控制器。
抽象地来看,ogre中的动画是相关tracks的集合。track是作为时间函数存储的一组数据值。一对“track值”与"时间点“,构成了关键帧(keyframe),更好的一种说法是,在时间轴线上对对象全部或部分的位置,朝向,缩放,进行采样。根据动画的类型,ogre支持好几种关键帧。"关键帧”这个名称来源于手工制作动画的时代(像上面提到的制作卡通兔动画),首席艺术家会给他的下级提供一组关键的帧。这些帧给出了场景中角色的位置,然后下级艺术家们根据这些画出帧之间角色的位置。在ogre中,你就是首席艺术家,需要提供这些关键帧,ogre是你的下级,它帮你完成帧之间的过渡。
ogre中支持的track有下面这几种类型(一个track中的所有关键帧必须有一致的类型):
NumericAnimaitonTrack(NumericKeyFrame):
关键帧包含一个AnyNumeric类型的标量值。Any是ogre中定义的结构,和COM中的variant 类型一样,允许数据类型的多态化。AnyNumeric限定了可能的数据类型只能是数字的(实数,整数)。
NodeAnimationTrack(TransformKeyFrame):
关键帧包含两个3维向量,一个四元数,分别表示结点的位置,缩放与朝向。
VertexAnimationTrack(VertexMorphKeyFrame,VertexPoseKeyFrame):
关键帧包含或是引用在一个特定时间点上(在pose 动画中)顶点位置和混合权重(VertexPoseKeyFrame)。
动画状态
程序与ogre中的动画主要的交互是通过动画状态来完成的(animation state)。在建模工具中,可以为骨骼或顶点网格沿时间轴线定义多个动画,导出时每个动画都可以定义一个名字,通过这个名字来定位Entity中同的动画。通过动画状态可以访问动画的许多属性:长度,当前位置,动画名,是否循环,有否有效,权重(用于混合动画)。权重根据混合动画的类型进行不同的处理。
混合权平均:
告诉ogre做这种混合时,所有权重之和为1。如果不是1,ogre会进行正规化处理,使得它们的总和为1。这种方式只对骨骼动画有效,它也是默认的混合方式。
混合权累积:
ogre只是简单地把所有引用权重的效果进行累加,不会再平衡。这种方式只对顶点动画有效(pose, morph),用到骨骼动画时也可以。
动画状态也是也给动画“加时间”推动它向前变化的地方。基本上总是给一个时间增量,意味着从上次调用到现在增长了的时间。本质上,加一个时间增量与直接设定时间位置没有什么不同。
骨骼动画
骨骼动画是最常用的动画类型。网格(mesh)中的顶点被绑定到骨骼上,如同我们身体的肌肉绑定到骨上。
不同的是,计算机动画中的“骨头”不是真实存在的。它们用一些(无对应实体)变换来表示骨头的位置,朝向与缩放,经常是用矩阵来表示。骨骼动画的关键帧,仅是相对于骨骼恢复位置的偏移。它们被组合起来形成了沿着时间轴线上某一给定点的骨骼。
Ogre中的骨骼是有层次关系的,如脚骨与胫骨相连,胫骨又与膝盖骨相连。在这种层次关系下,除了root外,每个骨头都有父亲。但并不限于只有一个root,这种层次关系仅仅是用来传递转换(自上而下)。改变一根骨头会影响它所有孩子的位置。反向的运动ogre不支持:当一个骨头运动时,它不会影响父辈。
顶点绑定
顶点被绑定到骨骼时会指定一个权重,权重说明了骨头运动对顶点的影响效果。典型的是把一个顶点绑
定到多个骨头,赋于不同的权重。ogre仅支持每顶点四个骨头,但每个骨头可以与任意多个顶点关联。
顶点动画
与通过计算动画骨骼,再根据骨骼位置计算顶点位置的动画方式不同。顶点动画直接对顶点进行动画操作。它是资源密集型的解决方案,对于每个动画位置都要转送完整的顶点数据的拷贝。有时这种方式是维一的办法,例如实现逼真的面部表情动画。
顶点动画在动画track这个层次上被管理、操纵。这意味着我们可以对角色的头,脸部分使用复杂的pose动画,而角色的剩余部分使用相对简单的morph动画。但是不能对相同的顶点使用不同的动画类型。顶点动画在引用一组顶点集时,要么全部引用,要么一个也不引用。这意味着,在网格级别上来看,所有的共享几何(shared geometry)构成了顶点动画的顶点数据。在子网格级别上来看,所有子网格的顶点构成了顶点动画的顶点数据。举例来讲,一个子网格的某些顶点参与morph动画,而剩余顶点参与pose动画,这种情况是不允许的。
变形动画(Morph Animation)
变形动画是两种顶点动画技术中最简单最直观的一种。实际的顶点位置做为"快照"被保存。这与前面说到
的卡通兔动画的过程是一样的。这种方法比较消耗资源,但是计算效率最高。关键之间数据通过插值得。
主要的缺点是不能混合多个变形动画,因为他们保存的是顶点的绝对位置。当然,如果有两个动画,它们
影响的顶点没有交集,那么确实可以对这两个动画进行混合。
姿势动画(Pose Animation)
模型的各种姿势被保存在动画tracks中。这些姿势可以被混合来创建更复杂的动画。顶点的位置是相对于
复原位置的偏移量,而不是顶点的绝对位置。而且只有变化的数据才被保存。因此,它不仅更灵活,而且
对资源使用也更高效。
pose动画的关键帧引用一个或多个pose tracks,每个引用对姿势有一个影响权重。权重决定了当pose被混合时每个顶点偏移对最终的顶点位置产生多大的影响。不必在每一帧都引用一个pose。在实践中,pose混合会碰到一些限制:每个附加的pose需要更多的处理时间。
混合动画
不能混合pose与morph动画到一起,也不能混合多个morph动画。
当混合骨骼动画与顶点动画时,ogre将首先计算/混合顶点动画,然后应用骨骼变形到混合顶点上。
规范的pose与骨骼动画混合的程序,会混合全身体的骨骼动画与复杂的面部表情。例如,可以对角色的面部顶点使用pose动画,而角色的剩余部分(包括头)使用相对简单的骨骼动画。
混合两个骨骼动画对于动画之间的切换是最有用的。例如角色可能在循环地执行"跑步"这个动画,一会儿
他可能要停下来(执行"idle"动画),那么这时需要对两个动画进行混合。
Morph与骨骼动画的混合,对于给骨骼动画的角色增加"外皮"网格变形是很合适的。例如,将一个衣服动画与角色实际的骨骼运动动画混合,这样就避免了对衣服进行实时模拟的高额代价。
硬件vs软件
应用硬件加速时最应该记住的是:硬件动画网格数据不能被CPU使用。这相当重要!假如你依赖网格数据
进行别的计算(体积阴影计算,物理模拟),一旦顶点变形计算被移到GPU中,顶点就永远消失了,不在代码中使用了,假如需要变形之后的顶点数据,那么你还得用CPU进行与GPU同样的计算!这确实也可以做到,告诉ogre做吧: Entity::addSoftwareAnimationRequest()。
硬件加速的骨骼动画与顶点动画混合,会在顶点程序中执行混合。假如你刚才还没有注意到上面曾经提到
过的执行顺序的话,现在又有机会让你意识到这点:先顶点,然后骨骼。这同样也意味着,所有的动画技术都应该是基于硬件加速的,不能让硬件加速的骨骼动画与基于软件的顶点动画混合。
使用GPU加速骨骼动画时,应该考虑到:骨骼动画算法的本质上要求,在计算每个顶点时,骨架中所有骨头的数据必须都被提供。老旧的硬件仅仅支持24 bones或更少的skinning通道。这时应把mesh分为几段,在多个通道中skin它们。ogre只会把submesh引用到的bones发送到skinning shader,而不是骨骼中所有的bones,这使得多个skinnig pass成为可能。
在CPU中对morph动画顶点进行插值的主要优点是利用了GPU并行计算的本质。morph计算起来也不复杂,
主要的输入是两个顶点位置与一个插值因子,顶点程序产生插值后的顶点位置做为输出。
pose动画与morph类似,而且有与骨骼动画类似的限制:它提供给程序的pose数目如何进行传递。
标签点
标签本身不是动画的一部分,但它们常被用于联结任意对象(例如武器)到存在的动画模型上。标签点
的概念比较简单:它是骨架中一块特殊的骨头,它能在运行时,控制绑定对象的位置与朝向。不必事先
创建标签点,可以在运动期attched一个可移动对象到骨架中一个命名的骨头上。Entity有这样一个方法:
attachObjectToBone();一旦物体被绑到骨头上,它就会随着标签点移动。需要知道的是,对象并不是真正
地被attched到标签点上。它被attched到用那个骨骼的Entity上。
动画与控制器
两者都是基于一个一维的变量来控制对象的状态,把变量输入一个函数产生输出。对于动画来说,输入变量是时间,而对于控制器来说,输入变量是任何你想要的东西。
动画的特点:
通过插值函数计算给定时间点上track值来产生输出,从而改变顶点位置。
动画被认为是个封闭的系统:你设置输入值,ogre 使用它来更新相关对象的属性。
插值函数较为固定:要么线值,要么三次样条插值。
动画有ogre提供的许多工具的支持。
控制器的特点:
对于输出的计算更为灵活,工作函数需要提供,因此有更多选择。
控制器可以形成一个链,一个输出可作为另一个输入。
控制器自己不移动任何东西,对于输出可以不做任何事情。ogre用控制器来驱动纹理动画。
控制器自动逐帧更新,然而必须手工添加代码使每帧的动画向前变化。