HT for Web 动画手册

索引


概述

HT动画系统由三部分内容组成:

其中TimerTimeline可以点击链接进入专门的文档查看,本文档专门描述TargetedAnimation

TargetedAnimation 概述

TargetedAnimationHT动画系统中最常用的一个动画,大部分动画都可以通过它来实现的。它本身由Clip剪辑和Target目标组成。Clip剪辑包含多组Track轨道,每个Track轨道描述了一组属性的关键帧。

Track

Track轨道是对一个属性根据关键帧进行动画的元件,其中关键帧包含了时间序列 Times跟对应的值序列 Values

在动画播放的时候,要计算某个精确时间点状态时候,它会对时间序列进行二分查找,找到前后的两个关键帧时间点,然后根据时间点的值,调用对应插值函数进行插值。

它的构造函数为: Track(name, times, values, easings, extraInfo)

举例:

new Track('width', [ 0, 1 ], [ 100, 200 ], 'linear')
new Track('style@shape.gradient.pack', [ 0, 2, 3.5, 5 ],
    [
        ['radial', 0.5, 0.5, 0.5, 0, '#4CAF50', 1, 'white'],   // 不同关键帧的 gradient pack 数据
        ['radial', 0.5, 0.5, 0.5, 0, '#2980B9', 1, '#D6EAF8'],
        ['radial', 0.5, 0.5, 0.5, 0, '#A9A9A9', 1, '#F5F5F5'],
        ['radial', 0.5, 0.5, 0.5, 0, '#F57C00', 1, 'white']
], undefined, { type : 'gradient' });

Track 包含的方法有:

这个例子中,用track.trim方法截取了Track,外围的Track中的scalegradient两个属性的动画都只有完整动画的局部。一般如果要截取动画的局部的话,有两种方式可以达成:

Track Type

默认的Tracktype包含有(下面以Times为 [0 - 1],Value为[a, b]举例):

默认情况下,会自动根据值的情况猜测该Track的类型,如果无法猜测,则默认为linear,此时如果要强制指定可以在 new Track 的时候传入extraInfo中指定type

如果上述类型均无法满足,用户需要完全自定义插值,可以使用ht.Default.setTrackType(type)方式注册:

ht.Default.setTrackType(type, { interpolation, valuesChangeHandler, stride })

这里需要注意的是,对于高频计算的Track来说,我们为了让它GC(Garbage Collection)的开销降到最低,内部都是通过array数组来存放过程跟结果,并且对于同一个Track来说数组是复用的,所以自定义Track的时候,虽然也可以玩完全接管走interpolation的插值函数并自行计算,但最终的output如果是对象的话推荐使用array并提供对应的stride指定单个output的数据步长

Additive

Trackadditive模式,表示是否动画是增量的。默认情况下,动画是非增量的,覆盖设置的,即Track设置的值会覆盖目标的值。 但是对于增量动画,Track设置的值会累加到目标的值上。

(注意,AdditiveClip来驱动来结算,Trackadditive属性只起一个标记作用,需要使用clip.setAdditive(true)来设置)

它意味着,对动画设置 additive 为 true 后,HT内部会计算跟Track起始帧的值的差值,差值的逻辑为:

增量动画应用到目标上的时候,如果目标有非增量类型的其他动画在播放,则增量直接累积到目标上。 如果此时目标上只有纯增量的动画,则会通过动画的trackbingdingname字段)的getter先获取当前目标的值作为初始值,再累加

这个例子里面用其中一个node创建它的移动跟旋转动画,然后设置为增量动画后复用给其他所有node。另外,按照每个node同中心的距离来作为动画的delay,并增加了根据高度来表现颜色的材质,以增加动画的表现效果

Clip

Clip剪辑是Track的集合,一组剪辑用于描述一套动作。例如人物的行走动画,即一个Clip剪辑,它一般包含多组不同骨骼部件的Track,每个Track描述不同的位移旋转等。

它的构造函数为:Clip(name, tracks, duration, isAdditive)

它包含的接口:

关于相位匹配 PhaseMatching

PhaseMatching 只有在动画切换并且target.playAnimation(animationName, speed, start, loop, fadeTime)设置了fadeTime的时候才会生效

我们举个例子:当前正在播放的动画叫做 A1,新播放的动画叫做 A2,fadeTime 0.8 秒

为什么会有相位匹配?

原因在于,譬如人物这种精细的模型,如果处在任意动画阶段就无条件混合的话,二者会有抽搐混合。所以一般会设定一定的相位,譬如人脚掌着地,认为脚掌着地是人行走的固定相位,那么在切换行走动画的时候,会先播放到脚掌着地的相位,再做混合相对就会融合的更好

(我们现在简单的认定融合的相位点是动画结尾位)

TargetedAnimation

将一组Clip剪辑应用到具体的目标或者目标群上的时候,并设定了播放速度、起始时间、循环模式等预期, 就构成了TargetedAnimation

它首先继承自Timer,所以具备Timer的全部功能。构造函数为: new ht.Animation.TargetedAnimation(clip, target, defaults)

它额外包含的接口:

这个例子中有一些信息特别说明一下:

AnimationUtil

为了方便创建动画,我们提供一些必要的工具函数便于快速手写动画

AnimationConfig

AnimationConfig 包含动画的配置信息,它主要是用于:

其数据定义如下:

{
    type : 'entity', // 可选,动画类型,model3d 表示驱动目标上的模型动画,image 表示驱动目标上的image动画,entity表示驱动目标自身动画
    default : false, // 可选,是否是默认动画,target.playAnimation(undefined) 没有带动画名的时候会查找所有动画中标记了 default : true 的进行播放
    duration : 1,    // 可选,动画时长,如果未设置,则按照 1 秒计算

    name : 'walk', // 动画名,后续 playAnimation 的动画名
    tracks : [
        { name : 'robotHips.position', times : [ 0, 9 ], values : [  0, 0, 0, 500, 500, 500 ], easings : [ 'Bezier' ], type : 'linear' },  // track 定义
        { name : 'robotHips.quaternion', times : [ 0, 9 ], values : [  0, 0, 0, 1, -0.3829, 0, 0, 0.92388 ], type : 'quaternion' },
    ],

    additive : false, // 可选,是否为增量的相对动画,具体参见[Additive](#ref_additive)
    exclusive : undefined, // 可选,是否为独占动画,如果一个动画是独占模式,则播放时会停下所有同 target 的其他独占动画
    phaseMatching : false, // 可选,是否为相位匹配模式
}

AnimationConfig 的播放接口可以是下面两种:

Entity 类型(包括 node / graphView / graph3dView)的 AnimationConfig 语法糖

为了更方便快速的创建常用 Entity 动画(目前的 Entity 动画包含node / graphView / graph3dView),我们提供了一些语法糖,进一步简化AnimationConfig的书写,具体的定义为:

{
    duration : 1, // 可选,动画时长,如果未设置则认为 1
    // type, name, default, additive, exclusive, phaseMatching 等属性见 AnimationConfig

    // 非上述关键字的,均被当作 track 的 name 处理
    'state@position' : { values : [ 1, 1, 1, 5, 5, 5 ], easings : [ 'Bezier' ], },
    'state@position' : { to : [ 5, 5, 5], easing : 'Bezier' },   // to 模式的话,用当前的 position 跟 to 的值,构成 values
    'state@position' : [ 5, 5, 5 ],  //   等同于 { to : [ 5, 5, 5 ] }
}

举个详细的例子,可以简单的进行快速创建动画:

node.playAnimation({
    // duration : 3,
    'p3' : [ 5, 5, 5 ],
    'scale3d' : { to : [ 2, 2, 2 ], easing : 'Spring' },
    'rotationY' : node.getRotationY() + Math.PI * 2
})

// or

node.registerAnimation({
    name : 'myCustomAnimation',
    // duration : 3,
    'p3' : [ 5, 5, 5 ],
    'scale3d' : { to : [ 2, 2, 2 ], easing : 'Spring' },
    'rotationY' : node.getRotationY() + Math.PI * 2
});
node.playAnimation('myCustomAnimation');

欢迎交流 service@hightopo.com