使用 Three.js 框架中的 AnimationClip

person 少陵野老    watch_later 2024-10-12 21:44:08
visibility 50    class AnimationClip    bookmark 专栏

在 Three.js 动画系统中,AnimationClip 是用于存储关键帧动画数据的核心组件。通过 AnimationClip,我们可以创建复杂的动画,并将其应用于场景中的对象。AnimationClip 可以与 AnimationMixerAnimationAction 结合使用,以提供强大的动画控制。

本文将详细介绍 AnimationClip 的用法,包括它的属性、方法及如何与其他 Three.js 组件配合使用。通过多个示例演示如何使用 AnimationClip 来创建和控制动画。

1. 什么是 AnimationClip

AnimationClip 是一种定义动画的类,它包含了一个或多个 KeyframeTrack(关键帧轨迹),每个 KeyframeTrack 定义了动画中某个属性的变化。通过设置多个关键帧,可以让属性在不同的时间点上发生变化,从而创建动画效果。

1.1 AnimationClip 的核心组件

  • KeyframeTrack:定义对象属性在不同时间的变化。常见的 KeyframeTrackVectorKeyframeTrack(用于位置变化)、QuaternionKeyframeTrack(用于旋转变化)、ColorKeyframeTrack(用于颜色变化)等。
  • AnimationMixer:动画混合器,管理所有 AnimationClip 的播放和控制。
  • AnimationAction:表示一个动画实例,负责控制动画的播放行为。

2. 创建 AnimationClip

AnimationClip 通常通过关键帧轨迹(KeyframeTrack)来定义。让我们通过一个简单的示例展示如何创建一个 AnimationClip

2.1 初始化场景

首先,我们需要创建一个基本的场景,包括一个立方体对象,并通过摄像机和渲染器进行渲染。

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

camera.position.z = 5;

2.2 创建 3D 对象

接下来,我们为动画创建一个立方体对象:

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

2.3 创建 KeyframeTrack

KeyframeTrack 是定义动画变化的轨迹。在这个示例中,我们将使用 VectorKeyframeTrack 来控制立方体沿 Y 轴的运动。

const times = [0, 1, 2];  // 定义动画的时间点
const values = [0, 0, 0, 0, 2, 0, 0, 0, 0];  // 定义在每个时间点的位置
const positionKF = new THREE.VectorKeyframeTrack('.position', times, values);

2.4 创建 AnimationClip

接下来,我们使用关键帧轨迹创建 AnimationClipAnimationClip 的第一个参数是名称,第二个参数是动画的持续时间,第三个参数是包含的关键帧轨迹数组。

const clip = new THREE.AnimationClip('moveUpAndDown', 2, [positionKF]);

3. 使用 AnimationMixer 播放 AnimationClip

AnimationMixer 是管理和播放动画的工具。为了让动画播放,我们需要创建一个 AnimationMixer,然后通过它来生成 AnimationAction 并播放 AnimationClip

3.1 创建 AnimationMixer

const mixer = new THREE.AnimationMixer(cube);

3.2 创建 AnimationAction 并播放

通过 AnimationMixerclipAction 方法,可以创建一个 AnimationAction 对象,接着调用 play() 方法来播放动画。

const action = mixer.clipAction(clip);
action.play();

3.3 更新 AnimationMixer

为了让动画正常播放,我们需要在渲染循环中不断更新 AnimationMixer

const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);

    const delta = clock.getDelta();
    mixer.update(delta); // 更新动画

    renderer.render(scene, camera);
}

animate();

到这里,我们已经成功创建了一个基本的动画,立方体会在 Y 轴上来回移动。

4. AnimationClip 的属性和方法

AnimationClip 提供了多种属性和方法,允许我们对动画进行更复杂的控制。接下来我们将详细介绍这些属性和方法,并展示如何使用它们。

4.1 duration

duration 表示动画的时长。可以通过设置此属性来更改动画的持续时间。

clip.duration = 3;  // 将动画时长设置为 3 秒

4.2 tracks

tracks 是一个包含所有 KeyframeTrack 的数组。可以通过它来查看和修改动画中包含的所有轨迹。

console.log(clip.tracks);  // 查看动画的关键帧轨迹

4.3 resetDuration()

resetDuration() 方法会根据关键帧轨迹的时间自动调整动画的持续时间。

clip.resetDuration();

4.4 trim()

trim() 方法会移除动画中多余的时间段,仅保留关键帧定义的有效部分。这在需要裁剪动画时非常有用。

clip.trim();

4.5 optimize()

optimize() 方法可以优化动画,移除冗余的关键帧,从而减少动画数据的大小。对于复杂动画来说,这可以提高性能。

clip.optimize();

5. 多个 AnimationClip 的使用

在许多情况下,一个对象可能会有多个动画。Three.js 允许我们为同一个对象创建多个 AnimationClip,并通过 AnimationAction 控制不同动画之间的过渡和混合。

5.1 创建第二个 AnimationClip

我们再创建一个动画,使立方体沿 X 轴移动:

const positionKF2 = new THREE.VectorKeyframeTrack(
    '.position', 
    [0, 1, 2], 
    [0, 0, 0, 2, 0, 0, 0, 0, 0]
);

const clip2 = new THREE.AnimationClip('moveSideToSide', 2, [positionKF2]);

5.2 播放多个 AnimationClip

我们可以通过 AnimationMixer 创建多个 AnimationAction 来播放不同的动画,并通过调整它们的播放时间和权重来实现动画的混合。

const action2 = mixer.clipAction(clip2);
action2.play();

5.3 混合动画

通过调整动画的权重,可以让两个动画平滑过渡或混合播放。如下代码展示了如何让两个动画同时播放,并通过权重控制它们的影响。

action.weight = 0.5;
action2.weight = 0.5;

在这个例子中,立方体将会同时沿 Y 轴和 X 轴移动,产生一个对角线的移动效果。

6. 动画循环和事件

在动画中,我们通常希望控制动画的循环方式。AnimationClip 提供了多种循环模式,允许我们灵活控制动画的播放行为。

6.1 设置循环模式

Three.js 提供了三种主要的循环模式:

  • THREE.LoopOnce:动画播放一次后停止。
  • THREE.LoopRepeat:动画无限循环。
  • THREE.LoopPingPong:动画往复播放。

我们可以通过 AnimationActionsetLoop 方法来设置动画的循环方式:

action.setLoop(THREE.LoopPingPong, Infinity); // 动画往复循环

6.2 监听动画事件

通过 AnimationMixer,我们可以监听动画的开始、结束、循环等事件。以下示例展示了如何监听动画播放的完成事件:

mixer.addEventListener('finished', (event) => {
    console.log('动画播放完成');
});

7. 完整示例

以下是一个完整的示例,展示了如何使用 AnimationClipAnimationMixer 创建和控制多个动画:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js AnimationClip 示例</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script

>
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        const geometry = new THREE.BoxGeometry(1, 1, 1);
        const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);

        const positionKF = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 0, 0, 0, 2, 0, 0, 0, 0]);
        const clip = new THREE.AnimationClip('moveUpAndDown', 2, [positionKF]);

        const positionKF2 = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 0, 0, 2, 0, 0, 0, 0, 0]);
        const clip2 = new THREE.AnimationClip('moveSideToSide', 2, [positionKF2]);

        const mixer = new THREE.AnimationMixer(cube);
        const action = mixer.clipAction(clip);
        const action2 = mixer.clipAction(clip2);

        action.play();
        action2.play();

        action.weight = 0.5;
        action2.weight = 0.5;

        const clock = new THREE.Clock();

        function animate() {
            requestAnimationFrame(animate);

            const delta = clock.getDelta();
            mixer.update(delta);

            renderer.render(scene, camera);
        }

        animate();

        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });
    </script>
</body>
</html>

8. 结论

AnimationClip 是 Three.js 动画系统的核心组件之一,允许开发者定义复杂的动画。本文详细介绍了如何创建和使用 AnimationClip,并结合 AnimationMixerAnimationAction 实现了多种动画控制方式。通过优化、裁剪和混合动画,可以实现更加灵活的动画效果。希望本文能够帮助你更好地理解和使用 Three.js 的动画系统。

如有任何问题或建议,欢迎留言讨论!

评论区
评论列表
menu