Three.js 框架中 `Clock` 的使用详解

person 少陵野老    watch_later 2024-10-18 19:19:30
visibility 78    class Clock    bookmark 专栏

Clock 是 Three.js 中用于跟踪时间的类,通常用于动画、游戏循环或需要基于时间进行更新的场景。Clock 提供了简单而高效的 API,帮助开发者计算时间间隔(delta time)和总运行时间。这对于实现基于帧率的平滑动画、更新物体位置和处理时间相关的逻辑至关重要。

在这篇博客中,我们将详细介绍 Clock 的用法,探讨其所有的属性和方法,并通过丰富的示例来展示如何在实际项目中使用 Clock 来控制动画和时间逻辑。

1. 什么是 Clock

Three.js 中的 Clock 类是一个轻量级的工具,用于测量应用程序运行时的时间。它主要有两个用途:

  • 计算时间差:获取每帧之间的时间差(delta time),使得动画可以与帧率无关。
  • 测量总时间:记录自应用程序开始运行以来的总时间,用于时间相关的逻辑。

Clock 在动画或游戏开发中非常常用,因为它能够提供一种简单的方式来同步动画或移动,使其不依赖于帧率。

构造函数

const clock = new THREE.Clock(autoStart);
  • autoStart: 可选参数,默认为 true,表示是否在创建 Clock 的同时启动它。

2. Clock 的核心属性和方法

2.1 start

启动时钟。如果时钟已经启动,则这个方法不会产生效果。

clock.start();

2.2 stop

停止时钟。如果时钟已经停止,则此方法不会产生效果。

clock.stop();

2.3 getElapsedTime

获取自时钟启动以来的总运行时间,以秒为单位返回一个浮点数。这个时间包括暂停和恢复期间的累积时间。

const elapsedTime = clock.getElapsedTime();

2.4 getDelta

获取自上次调用 getDelta 或启动时钟以来的时间差(delta time)。它通常用于每帧的动画更新,以确保动画与帧率无关。

const delta = clock.getDelta();

2.5 running

running 是一个只读属性,返回当前时钟是否在运行。如果时钟启动了但没有停止,则返回 true,否则返回 false

console.log(clock.running); // true 或 false

3. Clock 的基础使用

我们来看一个使用 Clock 创建简单动画的例子。在这个例子中,我们通过 Clock 来控制一个立方体的旋转,并确保旋转速度与帧率无关。

示例:通过 Clock 控制物体的旋转

// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 设置相机位置
camera.position.z = 5;

// 创建一个 Clock 对象
const clock = new THREE.Clock();

// 渲染循环
function animate() {
    requestAnimationFrame(animate);

    // 获取时间差
    const delta = clock.getDelta();

    // 使用时间差控制立方体旋转
    cube.rotation.x += delta;
    cube.rotation.y += delta;

    renderer.render(scene, camera);
}
animate();

在这个例子中,我们使用 clock.getDelta() 获取每帧之间的时间差,并将其应用于立方体的旋转速度,使得动画可以平滑地运行,并且不依赖于帧率。

4. Clock 的进阶使用

4.1 控制动画速度

通过调整 delta time,我们可以轻松控制动画的快慢。例如,如果想让物体的旋转速度变为原来的两倍,可以在 delta 上乘以一个系数。

const speed = 2.0; // 设置速度为原来的两倍
cube.rotation.x += delta * speed;
cube.rotation.y += delta * speed;

4.2 暂停和恢复时钟

我们可以在特定情况下暂停时钟,例如在游戏暂停时,或者当用户切换到其他窗口时暂停动画。通过 clock.stop() 暂停时钟,并通过 clock.start() 恢复时钟。

document.addEventListener('visibilitychange', function() {
    if (document.hidden) {
        clock.stop();
    } else {
        clock.start();
    }
});

在这个例子中,当用户切换到其他窗口时,时钟会自动停止;当用户重新回到该窗口时,时钟会恢复。

4.3 获取总运行时间

getElapsedTime 方法返回自时钟启动以来的总时间,这对于跟踪总动画时间或在场景中控制特定事件的发生很有用。

const elapsedTime = clock.getElapsedTime();
if (elapsedTime > 5) {
    console.log('5秒已过去');
}

示例:使用 Clock 控制多个物体动画

在这个示例中,我们将创建多个物体,并使用 Clock 控制每个物体的不同动画。

// 创建场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建多个立方体
const cubes = [];
for (let i = 0; i < 5; i++) {
    const geometry = new THREE.BoxGeometry();
    const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
    const cube = new THREE.Mesh(geometry, material);
    cube.position.x = (i - 2) * 2; // 调整立方体位置
    cubes.push(cube);
    scene.add(cube);
}

// 设置相机位置
camera.position.z = 10;

// 创建一个 Clock 对象
const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);

    // 获取时间差
    const delta = clock.getDelta();
  
    // 为每个立方体设置不同的旋转速度
    cubes.forEach((cube, index) => {
        cube.rotation.x += delta * (index + 1); // 不同立方体不同的旋转速度
        cube.rotation.y += delta * (index + 1);
    });

    renderer.render(scene, camera);
}
animate();

在这个例子中,每个立方体的旋转速度都不同,通过 Clock 控制它们的动画,实现了流畅的帧率无关动画。

4.4 在复杂场景中使用 Clock

在复杂场景或游戏开发中,Clock 通常被用来同步多个动画、物理引擎或其他时间相关的逻辑。我们可以通过一个统一的时钟来控制整个场景的时间进度。

// 假设有一个物理引擎需要更新
function updatePhysics(delta) {
    physicsEngine.step(delta);
}

// 渲染循环
function animate() {
    requestAnimationFrame(animate);
  
    // 获取时间差
    const delta = clock.getDelta();
  
    // 更新物理引擎
    updatePhysics(delta);
  
    // 渲染场景
    renderer.render(scene, camera);
}
animate();

通过这种方式,我们可以确保物理引擎的更新频率与帧率同步,而不会因为帧率波动而影响物理模拟的准确性。

5. Clock 的最佳实践

  1. 确保每帧都调用 getDelta:在动画循环中,确保每帧都调用 clock.getDelta(),以确保获取的时间差准确无误。
  2. 根据需求选择 getElapsedTimegetDelta:如果你需要跟踪总时间,使用 getElapsedTime;如果你需要逐帧更新动画,使用 getDelta
  3. 使用 Clock 控制帧率无关的动画:通过 Clock 计算时间差,可以让动画和逻辑更新与帧率解耦,使得在不同设备上表现一致。
  4. 在暂停和恢复时正确处理时钟:在游戏或复杂场景中,当用户切换窗口或暂停时,需要停止时钟,并在恢复时重新启动。

6. 总结

Clock 是 Three.js 中非常实用的工具类,特别适合

在需要基于时间进行更新的场景中使用,如动画、游戏循环或物理模拟。通过 Clock,我们可以方便地获取时间差、跟踪总运行时间,并通过帧率无关的方式更新场景和动画。

在本文中,我们详细介绍了 Clock 的各种属性和方法,并通过多个示例展示了它在实际项目中的应用。希望这些内容能帮助你更好地理解和掌握 Clock 的使用,为你的 Three.js 项目增添更多的控制力和表现力。

评论区
评论列表
menu