如果要在场景中加入动画,那么首先要找到一种方法,使得场景可以以一定的时间间隔进行渲染;
在HTML5和JavaScript API(应用开发接口)出来之前,这个方法是使用setInterval(function,interval)方法;
虽然,我们可以通过setInterval() 方法指定函数每100毫秒调用一次,但是,这个函数的问题是它并不考虑
浏览器中发生的事情;如果你正在浏览其他页面 ,这个函数仍然会每隔几毫秒就会被调一次;
除此之外,setInterval()方法并没有跟显示器的重画同步,这可能会导致较高的CPU使用率,降低系统效率。
引入requestAnimationFrame()方法
幸运的是 ,现在的浏览器已经有了解决setInterval()函数问题的方法,即requestAnimationFrame()函数;
通过requestAnimationFrame() 你可以指定一个函数,按照浏览器定义的时间间隔调用。
你可以在这个指定的函数里执行所有必要的绘画操作,而浏览器则会尽可能保证绘画过程平滑,高效;
写一个负责渲染的函数
function animate(){
requestAnimationFrame(animate);
renderer.render(scene,camera);
}
animate();
在animate() 函数里,我们又调用了一次 requestAnimationFrame(),目的是让这个动画持续进行;
整个场景创建完毕之后,调用一次animate() 函数来启动动画;
添加动画之前,需要引入一个小的辅助库
这个辅助库可以检测出动画运行的帧频;
显示动画时,该库可以在一个小图片里显示每秒显示的帧数(FPS)
//引入库
<script type="text/javascript" src="./libs/stats.js"></script>
//添加一个div元素,用来显示统计图形
<div id = "Stats-output"></div>
//初始化统计对象,并添加到div元素里
function initStats(){
var stats = new Stats();
//设置为0,监测的是FPS,如果设置为1,那么监测的是渲染时间
stats.setMode(0);
stats.domElement.style.position='absolute';
stats.domElement.style.left='opx';
stats.domElement.style.top='opx';
document.getElementById('Stats-output').appendChild(stats.domElement);
return stats;
}
//一开始调用此函数,使场景拥有了统计的功能
function init(){
var stats = initStats();
...
}
//告诉stats对象每次渲染开始的时间,可以在animate()函数里调用stats.update()方法
function animate(){
stats.update();
...
requestAnimationFrame(animate);
renderer.render(scene,camera);
}
添加动画,完整的代码参考
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>这世界唯一的妳</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<script src="./libs/three.js"></script>
<script src="./libs/stats.js"></script>
<body onload='init()'>
<div id="dv"></div>
<script>
function init() {
var stats = initStats();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
var planeGeometry = new THREE.PlaneBufferGeometry(60, 20);
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0xcccccc
});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 10;
plane.position.y = 0;
plane.position.z = 0;
plane.receiveShadow = true;
scene.add(plane);
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({
color: 0xff0000
});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = -10;
cube.position.y = 3;
cube.position.z = 0;
cube.castShadow = true;
scene.add(cube);
var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshLambertMaterial({
color: 0x0D4012
});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = 13;
sphere.position.y = 3;
sphere.position.z = 0;
sphere.castShadow = true;
scene.add(sphere);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight);
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight);
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
function initStats() {
var stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById('dv').appendChild(stats.domElement);
return stats;
}
document.getElementById('dv').appendChild(renderer.domElement);
var step = 0
var animate = function() {
stats.update();
//球的弹跳速度
step += 0.04;
requestAnimationFrame(animate);
sphere.position.x = 20 + (10 * (Math.cos(step)));
sphere.position.y = 2 + (5 * Math.abs(Math.sin(step)));
cube.rotation.x += 0.05;
cube.rotation.y += 0.05;
renderer.render(scene, camera);
}
animate();
}
</script>
</body>
</html>