03 Threejs物体匀速运动
1. requestAnimationFrame请求动画帧
为了最好的利用性能和渲染效果,需要在绘制每一帧画面的时候,计算需要渲染的画面。也就是使用window.requestAnimationFrame
方法。
1.1 requestAnimationFrame使用方式
window.requestAnimationFrame()
告诉浏览器——希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
-
该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
-
回调函数执行次数通常是每秒 60 次, 与浏览器屏幕刷新次数相匹配
function callback(){
//下一帧渲染画面前,需要执行处理的函数
}
window.requestAnimationFrame(callback);
1.2 确保不同帧率的画面运行速度一致
回调函数第一个参数会被传入DOMHighResTimeStamp参数,DOMHighResTimeStamp是当前被 requestAnimationFrame() 排序的回调函数被触发的时间。
let preTime
function render(time) {
//第一次调用render函数,没有上一帧的时间
if (preTime === undefined) {
preTime = time
}
//计算每帧画面的间隔时间,单位毫秒
const deltaTime = time - preTime
console.log('动画帧的间隔时间', deltaTime)
//保留当前时间作为上一帧时间,用于下一帧计算2帧间隔
preTime = time
renderer.render(scene, camera)
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render)
}
为了确保不同时间间隔,运动的速度一致,那么应该按照
移动距离 = 速度 * 时间
那么如果想要1m/s的速度远离原点的匀速运动
let preTime
function render(time) {
//requestAnimationFrame的回调函数默认传入一个时间参数
console.log("当前总时间/毫秒", time)
//第一次调用render函数,没有上一帧的时间
if (preTime === undefined) {
preTime = time
}
//计算每帧画面的间隔时间,单位毫秒,当前时间减去上一帧的时间,即为2帧直接的间隔时间
const deltaTime = time - preTime || 0
console.log('多少毫秒浏览器渲染一次', deltaTime)
if (deltaTime) {
console.log('浏览器1秒渲染的次数', 1000 / deltaTime)
}
preTime = time
//cube物体允许运动
//elapsedTime/1000是将毫秒改为秒
//1m/s的速度* 时间(秒)= 移动的距离
//将当前位置+=移动的距离,即为最后的距离
cube.position.x += 1 * (deltaTime / 1000)
if (cube.position.x > 3) {
cube.position.x = 0
}
renderer.render(scene, camera)
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render)
}
render()
1.3 匀速运动实例——使用requestAnimationFrame参数来获取时间,并处理动画
实现每3秒,即从原点出发匀速在x轴进行1m/s的匀速运动
import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 目标:requestAnimationFrame 时间参数 控制物体动画
// 1、创建场景
const scene = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
// 设置相机位置
camera.position.set(0, 0, 10)
scene.add(camera)
// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
// 将几何体添加到场景中
scene.add(cube)
console.log(cube)
// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(3)
scene.add(axesHelper)
function render(time) {
let t = (time / 1000) % 3
cube.position.x = t * 1
renderer.render(scene, camera)
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render)
}
render()
2. Clock对象——跟踪时间,处理动画
使用three.js自带的Clock
类实例的对象来完成时间的处理
2.1 Clock
该对象用于跟踪时间。
// 实例化clock对象,
// new Clock( autoStart : Boolean ),
// autoStart — (可选) 是否要在第一次调用 .getDelta() 时自动开启时钟。默认值是 true。
// 初始化时钟
const clock = new THREE.Clock();
2.2 获取运行当前帧的时间
2.2.1 getElapsedTime ()
获取自时钟启动后的秒数。
// 设置时钟
const clock = new THREE.Clock();
function render() {
// 获取时钟运行的总时长
let time = clock.getElapsedTime();
console.log("时钟运行总时长:", time);
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
2.2.2 getDelta ()
获取2帧之间的时间间隔。
// 设置时钟
const clock = new THREE.Clock();
function render() {
// 获取2帧之间的时间间隔
let deltaTime = clock.getDelta();
console.log("两帧之间的时间间隔:", deltaTime);
renderer.render(scene, camera);
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render);
}
render();
注意:getDelta、getElapsedTime如果同时用于同一动画帧,先调用getElapsedTime()会导致getDelta计时不准。因为每次调用这2个函数,都会对oldTime属性进行重置,所以getDelta计算出来的就不是上一帧的时间。
2.3 Clock匀速运动实例——使用getElapsedTime()
来获取时间,并处理动画
实现每3秒,即从原点出发匀速在x轴进行1m/s的匀速运动
import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 目标:控制3d物体旋转
// 1、创建场景
const scene = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
// 设置相机位置
camera.position.set(0, 0, 10)
scene.add(camera)
// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
// 将几何体添加到场景中
scene.add(cube)
console.log(cube)
// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(3)
scene.add(axesHelper)
const clock = new THREE.Clock()
function render(time) {
let deltaTime = clock.getDelta()
console.log('两次获取时间的间隔时间:', deltaTime)
let totalTime = clock.getElapsedTime()
console.log('时钟运行总时长:', totalTime)
let t = totalTime % 3
cube.position.x = t * 1
renderer.render(scene, camera)
// 渲染下一帧的时候就会调用render函数
requestAnimationFrame(render)
}
render()
转载自:https://juejin.cn/post/7201264999380254775