上一篇中,我们了解了 Three.js 构建的场景的坐标系。见:Three.js(2)--坐标系
本篇,我们要让物体动起来。
如果要在场景中加入动画,那么首先要找到一种方法,使得场景可以以一定的时间间隔进行渲染。在 HTML5 和相应的 JavaScript API 出来之前,我们只能使用 setInterval 方法实现。比如,我们可以用 setInterval(render, 100) 设定每 100 毫秒调用一次 render 方法。而现在,我们更多会使用 requestAnimationFrame,requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个 API。调用 requestAnimationFrame 后,它会要求浏览器根据自己的频率进行一次重绘,它接收一个回调函数作为参数,在即将开始的浏览器重绘时,会调用这个函数,并会给这个函数传入调用回调函数时的时间作为参数。简单的说,比如我们执行了 requestAnimationFrame(render),浏览器将会在它下一次重绘时执行 render,浏览器自己会选择合适的时间使绘画过程平滑、高效。
setInterval VS. requestAnimationFrame
使用 setInterval 是由 CPU 去计算更新的,会造成 CPU 压力,CPU 计算更新的任务完成后,并不代表这些更新就能立刻显示在浏览器上,因为还必须等待浏览器的下一次重绘,才能显示更新后的动画;使用 requestAnimationFrame,我们动画的更新就能和浏览器的重绘频率保持一致,从而大大提高动画的流畅度,使用 GPU 去控制什么时候更新,也可以减小 CPU 的压力;
使用 requestAnimationFrame,在当前页闲置时,任务会被挂起;而 setInterval 各浏览器实现不一,但大部分不会被完全挂起。这个各有利弊吧,但小妖觉得页面不显示时,没必要继续动画,requestAnimationFrame 可以减少页面闲置时的计算。
张鑫旭大大有一篇对 requestAnimationFrame 的很妖娆的说明,见 http://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%E5%8A%A8%E7%94%BB%E7%AE%97%E6%B3%95/ (张鑫旭大大的所有文章都很妖娆)
结论,在小妖的 Demo 中都会使用 requestAnimationFrame,如果用到生产环境,请各位做好兼容处理。
前面我们说到哪了?噢,我们只是想让物体动起来。上代码:
每次执行 animate,会给浏览器一个任务,让它在下一次重绘时再次执行 animate,这里的 requestAnimationFrame 很像 setTimeout,只是不需要自己定义延时时间,由浏览器自己决定。每次 render 前,都会改变 cube.roation 和 sphere.position,这样两个物体就会动起来。效果如下:
看到这里,是不是已经了解动画的原理?就是帧动画,就是动画片!我们要做的就是在每次浏览器重绘之前改变物体的位置,只要能保证每次在 16.7ms 内完成修改(保证帧率为 60FPS),就能展示流畅的动画。
Demo 在这里:http://xngeer.frostbelt.cn/itemthreedemo/3.move.html
本篇介绍了如何展示一个简单的动画,我们约定在 Demo 中都使用 requestAnimationFrame。有同学会问了:小妖,每一帧都是对物体的位置做一点微调,你的这些参数值是怎么来的?cube.rotation.x += 0.01; 为什么是 0.01?为了确定这个值需要不断的改代码刷页面吗?下一篇我们将介绍如何调试~
本文暂时没有评论,来添加一个吧(●'◡'●)