There are three main ways to animate objects in threejs, each of which has its own advantages and disadvantages. Let's take a look at the use of different ways.
1. Use SetInterval to execute once every 1/60 seconds
let i=0 setInterval(()=>{ cube.rotation.z+=0.01 //每隔一段时间z物体绕z轴旋转0.01 renderer.render(scene,camera) //渲染相机 },1000/60)
One problem with SetInterval is that it is not strictly executed once every 1/60 second, because it does not include the operation time of other codes. If other codes run for a long time, the time interval is greater than 1/60 second. Therefore, we generally do not recommend animation in threejs.
2. Use requestAnimationFrame
function tick(){ cube.rotation.z+=0.01 //每隔一段时间z物体绕z轴旋转0.01 renderer.render(scene,camera) //渲染相机 requestAnimationFrame(tick) } tick()
We didn't pass in a time interval when using requestAnimationFrame. The advantage is that it will be as close as possible to the interval of 1/60 seconds. Therefore, we usually use requestAnimationFrame when animating in threejs. But it also has problems. If there are two monitors, one is 60hz and the other is 120hz, because the refresh rates of the two monitors are different, the speed of the same animation on the two monitors is different.
3. Resolve requestAnimationFrame with different refresh rates
We need to make the radian of each rotation independent of the update rate.
let time=Date.now() function tick(){ let currentTime=Date.now() let deltaTime=currentTime-time time=currentTime cube.rotation.z+=deltaTime*0.001 renderer.render(scene,camera) requestAnimationFrame(tick) } tick()
However, this method is relatively troublesome. Threejs helps us provide a more useful object: Clock. So the optimization code is as follows.
const clock=new THREE.Clock() function tick(){ const time=clock.getElapsedTime() console.log(time) cube.rotation.z=time cube.position.x=Math.sin(time*2)*2 cube.position.y=Math.cos(time*2)*2 renderer.render(scene,camera) requestAnimationFrame(tick) } tick()
The complete version of the code is in the main.js file:
import * as THREE from 'three' const w =window.innerWidth const h =window.innerHeight //Scene(场景) const scene=new THREE.Scene() //坐标轴 const axes = new THREE.AxesHelper(2,2,2) scene.add(axes) //创建一个立方体,物体:geometry(几何体,骨架) + material(材质,皮肤) const geometry = new THREE.BoxGeometry(1,1,1) const material = new THREE.MeshBasicMaterial() const cube=new THREE.Mesh(geometry,material) //把立方体放入场景 scene.add(cube) //创建光线 const light = new THREE.AmbientLight() //把光线放入场景 scene.add(light) //创建一个相机 const camera=new THREE.PerspectiveCamera(75,w/h,0.1,100) //75是能看到的角度范围 camera.position.set(0,0,5) camera.lookAt(0,0,0) //创建渲染器 const renderer=new THREE.WebGLRenderer() renderer.setSize(w,h) renderer.render(scene,camera) document.body.append(renderer.domElement) //解决不同刷新率的问题 //requestAnimationFrame let time=Date.now() function tick(){ let currentTime=Date.now() let deltaTime=currentTime-time time=currentTime cube.rotation.z+=deltaTime*0.001 renderer.render(scene,camera) requestAnimationFrame(tick) } tick() const clock=new THREE.Clock() function tick(){ const time=clock.getElapsedTime() console.log(time) cube.rotation.z=time cube.position.x=Math.sin(time*2)*2 cube.position.y=Math.cos(time*2)*2 renderer.render(scene,camera) requestAnimationFrame(tick) } tick()
The results are as follows: