Airglass.js现已支持关键帧动画

Airglass.js最近的更新中支持了关键帧动画,这依赖于canvas离屏渲染技术。开发者可以从序列图创建关键帧,也可以拷贝其他可渲染组件的关键帧,这适用于希望呈现相同效果的组件,以节省不必要的内存开销。我还在探索关键帧渲染与直接渲染之间的平衡点。

直接渲染

在我开发Airglass.js的初期,我将所有的关于在画布上渲染的操作都封装在名为draw的方法中,所有可渲染组件有用有该方法名,只是每一个不同的组件各自的draw方法的内部计算于渲染逻辑不同。每当组件状态需要更新时,重新设定控制组件渲染状态的参数,然后由渲染器负责调用组件的darw方法。我当时为了尽快构建起Airglass.js的原型,暂且这样简单处理渲染逻辑。但我承认这并不是成熟的组件渲染解决方案。

所谓千里之堤溃于蚁穴。对于一次性渲染后不再频繁更新的组件还好说。对于每秒需要更新24、30或60帧画面的动效来说,频繁的做重复的计算显然是在浪费实践和资源,尤其是所需要渲染的效果组件从几十个上升到到成百上千个时,问题就变得越发严重。我把这种渲染方式称为直接渲染,一种原始的、笨拙的、不灵光但也是必须经历的且在某些场景中也会适用的渲染方式。

关键帧渲染

男孩跑动效果关键帧动画sprite图

Airglass现已支持从序列图中生成关键帧。我目前规定关键帧只存在于名为Effect的效果类中,顾名思义,关键帧动画非常适合需要特殊视觉效果的应用场景。该效果类的实例也可以加入到Airglass的渲染器中,渲染器按需调用效果组件的draw方法,就能不断循环播放所有关键帧。当然也可以指定动画从哪一帧开始播放,何时开始以及何时结束。即使应用了相同关键帧的效果组件,为组件设定不同的起始关键帧,也能制造出随机的视觉效果。

就拿奔跑的小男孩举例,每一个渲染小男孩奔跑的效果组件都来自于同一组关键帧,这样复用关键帧的好处是减少不必要的内存开销。但是只要控制每一个小男孩奔跑画面从哪一帧开始播放,便能呈现出所有奔跑的小男孩在同一时刻不同的跑步姿势。这就是关键帧渲染。

男孩跑动效果关键帧动画sprite图

关键帧渲染方式能极大的降低甚至不需要渲染时做更新状态的计算。只需要适用drawImage方法将当前播放头流经的关键帧画面渲染到画布上即可。小男孩奔跑例子是我直接用一张含有透明通道的PNG格式的图片作为序列图生成的能被Airglass解析的关键帧序列,只需要渲染设计师提前绘制画面即可。而对于需要实时生成的比如要求效果组件需要用有不同颜色的情况,开发者可以很方便的扩展Effect类的init和draw方法,即可动态生成需要的关键帧序列。

具体的解决方案五花八门,只要选择一种适用于目标应用场景的即可。就拿我刚才举的不同颜色的雷达波的例子来说。关键帧动画意味着每一帧的画面内容已经提前设定好了,设计好关键帧序列后的开发者只能更改当前渲染周期内播放哪一帧画面。虽然看起来Airglass像是要做成一款开发游戏的库,但并不总是这样,Airglass提供解决渲染的方案,至于开发者如何使用Airglass尽可能发挥它的极致可能。我会另外开发FUI组件库。

男孩跑动效果关键帧占用更少的CPU计算量

渲染定位

效果组件最终呈现在画布上的样子由一组关键帧序列决定。渲染到画布上就涉及到渲染到画布的那个位置。canvas画布是二维平面,指定效果组件在画布上的X与Y坐标就能描述它在canvas画布上的位置信息。我为效果类Effect的实例增加了一个名为locate的设置定位点的方法,该方法接收三个参数。第一个参数表示组件定位点的X坐标,第二个参数表示定位点的Y坐标,第三个参数可选,表示将定位点放置在矩形效果组件的哪一个位置:

locate(x, y, position = 0){
 // position: 0、1、2、3、4、5、6、7、8
}

1、3、5、7分别对应左上、右上、右下、左下的定位点,这个CSS中设置margin、padding或border-radius属性值的顺序相似。另外2、4、6、8分别对应到1和3、3和5、5和7、7和8定位点的中点位置。

图解airglass定位点

制作Sprite序列图

仍然拿奔跑的男孩举例,Airglass读取序列图并转换为可识别的关键帧。从目前Airglass对关键帧的支持程度来看,对序列图有一些要求。序列图应该保持横向铺开的排列方式。不过这种情况不会维持太久,我会想设置定位点那样,让Airglass支持各种排列方式的序列图。初步设想是使用到多维数组的矩阵,需要开发者通过多维数组的形式告诉Airglass序列图的排列方式。

sprite序列图

从实现细节来讲,我为Airglass创建了名为Keyframes的类,他专门用来维护关键帧动画的生成和渲染。转换序列图和关键帧动画的生成有关,所以也是由Keyframes来维护的。通过fromImage方法读取序列图并初始化关键帧。在关键帧动画这方面,应该在读取序列图的时候更加灵活,这是我接下来要继续改进Airglass的其中一个目标。

请使用Github账号登录留言