在学习了几何形状和材质之后,我们就能使用他们来创建物体了。最常用的一种物体就是网格(Mesh),网格是由顶点、边、面等组成的物体;其他物体包括线段(Line)、骨骼(Bone)、粒子系统(ParticleSystem)等。创建物体需要指定几何形状和材质,其中,几何形状决定了物体的顶点位置等信息,材质决定了物体的颜色、纹理等信息。
网格的创建非常简单,只要把几何形状与材质传入其构造函数。最常用的物体是网格(Mesh),它代表包含点、线、面的几何体,其构造函数是:
Mesh(geometry, material)
创建一个材质为黄色的Lambert材质,形状为长宽高分别为1,2,3的长方体网格物体。
var material = new THREE.MeshLambertMaterial({
color: 0xffff00
});
var geometry = new THREE.CubeGeometry(1, 2, 3);
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
//也可以合并写
var mesh = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3),
new THREE.MeshLambertMaterial({
color: 0xffff00
})
);
如将上面的例子中的材质的颜色改为红色:
mesh.material = new THREE.MeshLambertMaterial({
color: 0xff0000
});
位置、缩放、旋转
位置、缩放、旋转是物体三个常用属性。由于THREE.Mesh基础自THREE.Object3D,因此包含scale、rotation、position三个属性,它们都是THREE.Vector3实例。
修改位置position:
//修改z坐标为1
mesh.position.z = 1;
//整体移动到(1.5, -0.5, 0)
mesh.position.set(1.5, -0.5, 0);
//或
mesh.position = new THREE.Vector3(1.5, -0.5, 0)
缩放scale
//x轴方向放大2倍
mesh.scale.x = 2.0;
//整体缩小为原来0.5倍
mesh.scale.set(0.5,0.5,0.5);
旋转rotation,这是一个欧拉类型的值,但是旋转实际是通过有三个轴旋转的角度,单位是弧度。
//按Y轴正方向旋转45°
mesh.rotation.x += 0.25*Math.PI;
//顺序默认为x y z
mesh.rotation.set(100,0,0);
动画的本质是利用了人眼的视觉暂留特性,快速地变换画面,从而产生物体在运动的假象。而对于Three.js程序而言,动画的实现也是通过在每秒中多次重绘画面实现的。
为了衡量画面切换速度,引入了每秒帧数FPS
(Frames Per Second)的概念,是指每秒画面重绘的次数。FPS越大,则动画效果越平滑,当FPS小于20时,一般就能明显感受到画面的卡滞现象。而当FPS足够大(比如达到60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源,因此只需选择一个合适的FPS即可。
对于Three.js动画而言,一般FPS在30到60之间都是可取的。
setInterval方法
如果要设置特定的FPS(虽然严格来说,即使使用这种方法,JavaScript也不能保证帧数精确性),可以使用JavaScript DOM定义的方法:
setInterval(func, msec)
其中,func
是每过msec毫秒执行的函数,如果将func
定义为重绘画面的函数,就能实现动画效果。setInterval
函数返回一个id
。
如果需要停止重绘,需要使用clearInterval
方法,并传入该id
。
clearInterval(id_of_setinterval)
下面的例子通过setInterval
函数设置FPS为60,渲染了一个物体绕y轴不断旋转的动画
id = setInterval(draw, 60);
//绘制一个绕y轴旋转的网格物体
function draw() {
mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
renderer.render(scene, camera);
}
//停止动画
//html
<button id="stopBtn" onclick="stop()">Stop</button>
//script
function stop() {
if (id !== null) {
clearInterval(id);
id = null;
}
}
requestAnimationFrame方法
大多数时候,我们并不在意多久重绘一次,这时候就适合用requestAnimationFrame方法了。它告诉浏览器在合适的时候调用指定函数,通常可能达到60FPS。
function draw() {
mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
renderer.render(scene, camera);
//requestAnimationFrame只请求一帧画面,因此需要无终止递归调用
id = requestAnimationFrame(draw);
}
//同样也有办法停止动画
function stop() {
if (id !== null) {
cancelAnimationFrame(id);
id = null;
}
}
stat.js是Three.js的作者Mr. Doob的另一个有用的JavaScript库。很多情况下,我们希望知道实时的FPS信息,从而更好地监测动画效果。这时候,stat.js就能提供一个很好的帮助,它占据屏幕中的一小块位置,单击后显示每帧渲染时间。
function initStat() {
stat = new Stats();
stat.domElement.style.position = 'absolute';
stat.domElement.style.right = '0px';
stat.domElement.style.top = '0px';
document.body.appendChild(stat.domElement);
}
//表示一帧的开始与结束
stat.begin();
mesh.rotation.y = (mesh.rotation.y + 0.01) % (Math.PI * 2);
renderer.render(scene, camera);
stat.end();