到目前为止,我们已经看到过一些简单的动画,他们都不太复杂。我们在刚开始的几篇博文中就引入一个基础的渲染循环,在随后的一些博文中我们使用这个循环简单地旋转对象,并展示了其他几个基础的动画概念。
从本篇开始,我们将进一步来介绍 three.js 是如何支持动画操作的。我们将会一起来讨论以下四个主题:
- 基础动画:three.js 里所有动画的基础,修改对象的三个属性,即位置、旋转和缩放;
- 移动相机:动画中一个很重要的部分是在场景中移动相机的能力;
- 变形和蒙皮:制作复杂模型的动画,主要有两种方式。一是使用变形技术,定义几何体之间的过渡;二是使用骨骼和蒙皮技术处理几何体之间的过渡;
- 加载外部动画:前面我们介绍过 three.js 可以支持多种外部的文件格式。后面我们将会进一步探讨,看看 three.js 如何从外部文件中加载动画;
本篇我们将首先介绍基础动画。在这之前我们先来回顾一下最初给出过的 render(渲染)循环。为了支持动画,我们需要告诉 three.js 多久渲染一次场景。为此,我们使用了 HTML5 提供的标准的 requestAnimationFrame() 函数,如下代码所示:
......
render();
function render() {
// 渲染场景
renerer.render(scene, camera);
// 使用 requestAnimationFrame 函数安排下一次渲染
requestAnimationFrame(render);
}
在这段代码里,我们只需要在初始化场景时调用一次 render() 函数。然后在 render() 函数中,我们使用 requestAnimationFrame 函数来规安排一次渲染。这样,浏览器就可以保证以正确的时间间隔(通常是每秒 60次)调用 render() 函数。
在 requestAnimationFrame 函数出现之前,一般都会使用 setInterval(function, interval) 或者 setTimeout(function, interval) 函数来达到类似的目的。但是问题是,它们只会按照设置的时间间隔调用指定的函数,而不考虑其他正在发生的事情。即使动画没有显示或者隐藏在某个标签页下,这两个函数依然会被调用且会耗费某些资源。这就意味着会导致较高的 CPU 使用率。因此,这不是一种很好的实现方式。而通过 requestAnimationFrame 函数,我们不必告诉浏览器什么时候需要刷新屏幕,而是请求浏览器在最适合的时候执行我们提供的函数。通常情况下其结果是 60FPS(帧率)。并且使用 requestAnimationFrame 函数会让你的动画运行得更平滑,对 CPU 和 GPU 也更友好,你也不必再担心渲染时机方面的问题。
好了,我们先来介绍一下简单动画,我们通过改变对象的旋转、缩放、位置、材质、顶点以及面片等,就可以很容易地制作出动画。接下来,让我们回想一下最初在“three.js 01-04 之简单动画”这篇博文中那个非常简单的例子,这个例子中的 render 循环非常简单,你只要修改网格的属性即可,threejs 会处理剩下的事情,核心代码大致如下:
/** 渲染场景 */
function render() {
rotateCube(); // 旋转立方体
bounceSphere() // 弹跳球体
render.render(scene, camera);
requestAnimationFrame(render);
}
/** 转动立方体 */
function rotateCube() {
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
cube.rotation.z += 0.02;
}
/** 弹跳球体 */
var step = 0;
function bounceSphere() {
step += 0.04;
sphere.position.x = 20 + (10 * Math.cos(step));
sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));
console.log('step=' + step + ', x=' + 10 * Math.cos(step) + ', y=' + 10 * Math.abs(Math.sin(step)));
}
这段代码并没有什么特别的,只是很好地展示了 three.js 中各种动画背后的基础概念。接下来我们将会快速地浏览一下跟动画有关的内容。另外,当你使用 three.js 处理复杂场景时,除了动画,一个很重要的方面是使用鼠标在屏幕上选择对象的能力。
未完待续···