threejs中给物体做动画主要有3种方式,每种方式都有自己的优缺点,下面我们看看不同方式的使用方法。
1.使用SetInterval,间隔1/60秒执行一次
let i=0 setInterval(()=>{ cube.rotation.z+=0.01 //每隔一段时间z物体绕z轴旋转0.01 renderer.render(scene,camera) //渲染相机 },1000/60)
但是SetInterval有一个问题,就是它不是严格的1/60秒执行一次,因为它不包括其他代码运算的时间,如果其他代码运行时间比较长,这个时间间隔是要大于1/60秒。所以在threejs中做动画,我们一般不推荐这种方式。
2.使用requestAnimationFrame
function tick(){ cube.rotation.z+=0.01 //每隔一段时间z物体绕z轴旋转0.01 renderer.render(scene,camera) //渲染相机 requestAnimationFrame(tick) } tick()
使用requestAnimationFrame我们并没有传入一个时间间隔,好处就是它会尽可能的接近1/60秒的间隔,所以在threejs中做动画一般都是用requestAnimationFrame。但是它也有问题存在,如果有两台显示器,一台显示器是60hz,另一台是120hz,由于两台显示器的刷新率不一样就导致同样的动画在这两台显示器上的速度不一样。
3.解决不同刷新率的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()
但是这种方法相对也是比较麻烦,threejs帮我们提供了比较好用的对象:Clock。所以优化代码如下。
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()
代码的完整版在main.js文件下:
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()
实现效果如下:
const w =750 const h =750
//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.getElementById("myproject").append(renderer.domElement)
const clock=new THREE.Clock() function tick(){ const time=clock.getElapsedTime() 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()