咱们知道,作动画有多种形式,能够用CSS的animation,也能够用Canvas,或者是用JS控制CSS的属性造成动画。咱们常用CSS作一些比较简单的动画,像过分、加载的动画,对于一些比较复杂的,可能会作成gif,或者是用Canvas,使用Canvas的控制粒度能够很细,同时工做量相对也比较大。作动画还有其它的方式,那就是使用After Effect(AE)/ Flash/Premiere(Pr)/会声会影等视频软件,这种可视化的制做方式相对于直接写代码来讲,会更容易简单天然。作动画自己应该使用工具进行制做,可是这种视频软件作出来的动画最后都是生成视频文件,而且一般体积还很大,没有办法直接移植到网页上去。
javascript
然而好消息是,如今咱们可使用AE作动画,而后使用bodymovin插件导出成html文件进行播放。AE是Adobe推出的一个很出名的视频后期处理软件,有些电影就是用AE作的,如变形金刚,还有人把AE当成增强版PS使用。也就是说假如咱们能够AE作出一些电影级别的效果,而后用html播放,那是一件多么酷炫的事情。css
bodymovin是一个AE的一个开源的第三方扩展,github地址。上面能够下载这个插件。而后再安装一个ZXPInstaller来安装这个文件,而后重启AE就能够了,固然前提是你要安装一个AE。它支持AE CC版本:html
After Effects | CC 2017, CC 2015.3, CC 2015, CC 2014 |
---|
安装完以后,点击AE的菜单Window -> Extensions -> Bodymovin就会弹出一个窗口:java
我相信不少人都没有玩过AE,因此这里我简单地介绍一下。首先新建一个工程(project),而后新建一个合成(composition),选择1080p/29fps,时长为10s,它就会建立一个10s的合成。以下时间轴面板的显示:node
这个时间轴将会是频繁操做的地方。点击文字工具,在上方的预览窗口选中一个位置点击建立文字,而后把它拖到窗口外面,由于咱们准备作一个文字从外面进来的动画,因此刚开始它是在外面的。把上图右边的蓝色竖线表示的时间线拖到0s的位置,而后在左边的文字图层的Position属性打一个关键帧,以下图所示:git
而后把时间线挪到3s的位置,改变文字的Position,把它挪到窗口的中间,这个时候AE会自动在时间线的位置打一个关键帧,以下图所示:github
而后按一下空格键进行预览,预览窗口就会播放起了咱们刚刚设定的动画:npm
你会发现,这个过程不是和CSS的keyframe动画同样的么?没错!动画的原理都是同样,经过设定关键帧制做动画。如今来比较一下用AE和用CSS/Canvas作这个动画的区别。json
如今用CSS作这个动画,以下代码所示:canvas
<style> .text{ animation: move 3s linear infinite; } @keyframes move{ from{ transform: translateX(-320px); } to{ transform: translateX(100px); } } </style> <div class="container"> <p class="text">Hello, frontend</p> </div>复制代码
咱们给animation添加一个动画,这个动画有两个关键帧,分别在0%和100%的位置,须要变化的是transform的属性。这段代码在浏览器运行,就会有刚刚用AE作的动画的效果了。若是用Canvas呢,应该怎么实现呢?
以下代码所示:
<canvas id="text-move" width="600" height="400"></canvas> <script> !function(){ window.requestAnimationFrame(draw); var canvas = document.querySelector("#text-move"), ctx = canvas.getContext("2d"); function draw(){ //计算文字position var textPosition = getPosition(); drawText(); window.requestAnimationFrame(draw); } }();复制代码
这个是canvas动画的基本框架,先注册requestAnimationFrame的draw函数,使得浏览器在从新绘制屏幕时会先调一下这个函数,理想状况下1s会绘制60幅图片,也就是说1s为60帧/60fps。
上面代码最关键的地方是在于计算文字位置position,一样地,也是要先设定初始位置和终点位置还有动画时间,从而知道移动的速度v,即每1s多少距离,记录一个动画开始时间,而后在每次draw的时候用Date.now()获取当前时间减掉开始时间,就获得时间t,而后用v * t就能够获得位移。这就是用Cavans作动画的基本原理,咱们看到,用Canvas须要本身实现一个关键帧系统。
从抽象级别来看的话,AE > CSS >> Canvas,使用AE我只须要拖一拖,而后打上几个关键帧,而使用CSS,我须要把个人操做写成代码,而使用Canvas我须要从0开始一点一点去控制,固然你可使用一些动画和游戏的引擎提升效率。因此若是有一个可视化界面让你去完成一些复杂的操做,和让你一行一行去写代码的方式选择的话,我想大部分人应该会选择前者。固然这二者的区别不只仅是操做上的简便性,使用AE借用插件还能够快速地制做出一些复杂的效果。
刚刚已经用AE作了一个最简单的动画,如今用bodywin把它导出来。打开bodymovin,选中合层,选择输出路径,以下图所示:
而后点击Render,完成它会输出一个json文件,打开这个导出的文件:
{"v":"4.10.1","fr":29.9700012207031,"ip":0,"op":95.0000038694293,"w":1920,"h":1080,"nm":"Comp 1","ddd":0,"assets":[],"fonts":{"list":[{"origin":0,"fPath":"","fClass":"","fFamily":"Myriad Pro","fWeight":"","fStyle":"Regular","fName":"MyriadPro-Regular","ascent":70.9991455078125}]},"layers":[{"ddd":0,"ind":1,"ty":5,"nm":"hello, frontend","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[-1017,692,0],"e":[458,692,0],"to":[245.83332824707,0,0],"ti":[-245.83332824707,0,0]},{"t":90.0000036657751}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"t":{"d":{"k":[{"s":{"s":164,"f":"MyriadPro-Regular","t":"hello, frontend","j":0,"tr":0,"lh":196.8,"ls":0,"fc":[0,0.64,1]},"t":0}]},"p":{},"m":{"g":1,"a":{"a":0,"k":[0,0],"ix":2}},"a":[]},"ip":0,"op":300.00001221925,"st":0,"bm":0}]}
这个文件记录了全部动画的过程,如上加粗字体是咱们刚刚打的两个关键帧的位置。而后安装一下bodymovin的引擎,可在github上面下载bodymovin.js或者是npm install一下:
npm install bodymovin复制代码
而后就可使用bodymovin了,以下html:
<!DOCType html> <html> <head> <meta charset="utf-8"> </head> <body> <div id="animation-container" style="width:100%"></div> <script src="node_modules/bodymovin/build/player/bodymovin.js"></script> <script src="index.js"></script> </body> </html>复制代码
index.js以下代码所示:
var animation = bodymovin.loadAnimation({
container: document.getElementById('animation-container'),
renderer: 'canvas', //svg、html
loop: true,
autoplay: true,
path: 'data.json'
})复制代码
调用它的loadAnimation的API,传几个参数,它支持canvas/svg/html三种形式,也就是说它能够用canvas作动画,也能够用svg和html,其中canvas的性能最高,可是canvas有不少效果不支持。data.json的位置经过path告诉它。全部的动画就经过改变path指向的data.json文件区分,而其它的参数不用变。也就是说全部的动画内容和效果都是经过data.json控制的。
如今在浏览器上面运行一下,你会发现报了一个错:
后来发现这个错误是由于文字的缘由,若是是用canvas的方式的时候要把文字导成svg的形式,而不是一个纯文本而后经过设置font-family,这个能够在bodymovin里面进行设置,以下图所示:
还能够直接导出一个完整的demo,直接打开html就能够运行,这个比较方便。效果以下:
而且咱们发现,它的大小和位移都是相对于容器的,当你把窗口拉小,它也会跟着变小。当使用svg的时候,它是用JS控制svg path标签的transform:
当使用html时,它是控制CSS的transform:
咱们一个hello, world的工程已经能够跑起来,bodymovin能支持多复杂的动画呢?
用AE作动画的时候常常会用到AE的摄像机图层,所谓摄像机就是一个视角,默认状况下这台摄像机是从正前方中间拍过去的,咱们能够改变这台摄像机的位置,如把摄像机往前推那么内容就会放大,把摄像机往左右移动,那么看到的内容就会发生倾斜,它有不少仿摄像机的参数能够控制:
摄像机属性均可以经过打关键帧作动画,如今咱们加上摄像机作3d的动画。作完后,若是还用canvas的话,它会提示你不能使用canvas,由于它目测不支持WebGL转换,以下图所示:
提示说使用了一个3d camera,尝试使用html renderer,这里要改为html。最后的效果以下:
经过检查,能够看到摄像机也是用transform的matrix控制的。完整的dmo可见这个连接。
而后咱们再继续作复杂的动画
在全部特效里面,笔者最喜欢的是粒子效果,这种效果也是电影里面常常用到的特效,如冰雪女王的冰雪魔法:
还有文字的粒子效果:
可是这种效果我试了一下没有办法导出来,这种效果自己就比较复杂,渲染起来比较耗时,在html实时播放也不太现实。
还有有时候会报一些奇怪的错误,最常报的一个错误是这个:
bodymovin.js:9249 Uncaught TypeError: this.addTo3dContainer is not a function
多是使用了一些特定效果,触发了它的bug。
可是不要沮丧,咱们仍是能够导出一些复杂的效果的,作动画这种关键仍是在于idea。
例如能够作一个装饰的小动画,以下所示:
一个完整的demo见这个网址。
还能够作一个相册视频,效果以下:
完整的demo见这个网址。
若是是作成一个1080p的视频,1.5分钟的mp4格式就算压得比较厉害也要100多MB,可是如今我只要加载一个90kb的json文件和一个240kB的库文件以及10Mb左右的图片就能够了。而且里面的文字和图形仍是矢量的。
如今来看一下CPU消耗,能够看到这个相册视频svg动画仍是很耗CPU的,可是你开一个视频播放器也一样挺消耗CPU资源的。
无论怎么样,bodymovin提供了另一种作网页动画的全新方式,摆脱那种纯代码控制的黑暗,甚至你都不用学Canvas和WebGL,也能够作出很酷炫的动画。可是无疑这种方式存在一种弊端,那就是没办法添加参数控制,例如我作一个愤怒的小鸟,我得经过拉弓的方向和力度以及小鸟的重量去计算它的轨迹。可是用AE作的只能是纯动画。因此平时能够二者结合。
bodymovin还支持转成IOS/Android代码,我感受这个东西发展还在初级阶段,网上也没有不少关于这个的介绍。可是随着这个的承认度提高,发展愈来愈好,说不定之后可以支持更多的特效,甚至能够提供参数支持。