就像CoreAnimation 中提到的, Nebula2动作系统急需一个全新的设计和编码. 在《龙歌》的开发和另一个针对表情动画的研究中, 我们不得不为这个天生不足的系统加入新的特性. 最后系统勉强可以正常工作了, 但从设计的角度来说, 它的可维性变得很差. 因为从事一个商业项目有很多约束(里程碑, 特性和质量), 这通常是惟一的选择, 最好是让一些事情在里程碑结束前可以工作(就算是内部的实现很杂乱), 以便顺利地完成目标. 至少最后可以确定, 哪些特性需要一个完全的新设计, 和避免错误的实现方法.
把Nebula3当成一个试验台, 《龙歌》完成之前我就开始着手一个新的动作系统. 老系统的主要问题有:
第一个设计选择是把动作代码分成2个子系统: CoreAnimation 和Animation. CoreAnimation 已经在这里说明过了.
CoreAnimation 主要关心资源的管理, 而高层的Animation系统提供了一些特性来实现复杂的动作混合方案.
刚开始Animation子系统时我考虑的是混合树. 混合树的一片叶子就是采样结点, 它在一个特定时间点采样了一个动作剪辑. 这棵树的结点从输入连接点接收采样数据, 混合(或处理)输入数据到一个单一的输出连接点, 直到根结点, 得到最后的结果. 几个星期的工作和一些接口的修订证明了, 这样的一个系统比老的Nebula2动作系统还要复杂. 我找不到一个简便的方式把”真实世界的情况)输入这棵混合树, 甚至相对简单的混合情况也变得异常复杂.
因此我放弃了混合树, 并开始一种更为直接的优先混合系统, 它基于动作轨道(大致跟Maya’s Trax Editor 差不多). 按照这条新的途径, 所有的事情突然变得条理, 几天后第一个实现就完工了.
新的Animation系统有2个重要的对象类型: AnimJob 和AnimSequencer.
一个AnimJob 代表一个具有下列属性的单一动作:
有了开始时间, 持续时间和混合优先级属性, AnimSequencer 对象安排AnimJobs 到一个2D坐标系统中, 它的水平轴是时间, 垂直轴是混合优先级. 当采样一个指定点时, AnimSequencer首先查找所有经过采样点的动作 job. 然后, 以最低优先级的动作job开始, 每个活动的job会被评估并且结采样果会与之前的混合结果按优先级进行混合.
AnimJob 仅仅是一个基类, 所以可以派生来为混合过程加入定制的功能 (像反向运行学或者一些朝向目标的功能). 现在只有一个特定的子类: PlayClipJob, 它只是简单地采样一个动作剪辑.
新的Animation子系统修正了绝大多数老Nebula2系统的问题:
总的来说, 新的Animation系统更加简单, 健壮, 易用, 并且易懂.
一些以前证明有用的东西还没有, 或许以后会加入的特性: