使用 Three.js 框架中的 AnimationAction

person 少陵野老    watch_later 2024-10-12 21:41:55
visibility 34    class AnimationAction    bookmark 专栏

在 Three.js 动画系统中,AnimationAction 是用来控制动画的关键部分。它允许我们播放、暂停、停止动画,并对动画的速度、权重、循环行为进行控制。AnimationActionAnimationMixerAnimationClip 一起使用,能够轻松创建和管理复杂的动画效果。

本文将详细讲解 AnimationAction 的各种用法,包括它的属性、方法及其与其他 Three.js 组件的配合使用。并通过多个示例演示如何使用 AnimationAction 来实现不同的动画控制效果。

1. 什么是 AnimationAction

AnimationAction 是 Three.js 动画系统中的核心组件之一,表示的是动画混合器中的一个动画动作。通过 AnimationAction 对象,可以对 AnimationClip(动画片段)进行播放、暂停、恢复、停止等操作,同时也可以控制动画的循环方式、速度、权重等。

1.1 关键组件

  • AnimationMixer:用于控制多个 AnimationAction 的混合。
  • AnimationClip:定义动画片段,它包含了动画的所有信息。
  • AnimationAction:表示 AnimationClip 的一个实例,负责控制动画的播放行为。

2. 基本用法

为了演示 AnimationAction 的使用,首先我们需要创建一个场景,并添加一个可以应用动画的对象。

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);

3. 创建 AnimationMixer 和 AnimationClip

在控制动画之前,我们需要创建一个 AnimationMixer,它是用来管理所有动画的对象。每个 AnimationClip 都表示一个动画,而 AnimationAction 则用于控制该动画的行为。

3.1 创建 AnimationMixer

const mixer = new THREE.AnimationMixer(cube);

3.2 创建 AnimationClip

我们将创建一个简单的动画片段,使立方体沿 Y 轴来回移动:

const positionKF = new THREE.VectorKeyframeTrack(
    '.position', // 目标属性
    [0, 1, 2],   // 关键帧时间点
    [0, 0, 0,    // 起点位置
     0, 2, 0,    // 中间位置
     0, 0, 0]    // 终点位置
);

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

4. 使用 AnimationAction 控制动画

通过 AnimationMixerAnimationClip 创建一个 AnimationAction,然后可以对动画进行控制。

4.1 创建 AnimationAction 并播放

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

4.2 在渲染循环中更新动画

为了使动画正常播放,需要在渲染循环中更新 AnimationMixer

const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);

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

    renderer.render(scene, camera);
}

animate();

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

5. AnimationAction 的属性和方法

AnimationAction 提供了丰富的属性和方法,用于更精细地控制动画行为。以下将详细介绍常用的属性和方法,并通过示例展示如何使用。

5.1 play()

play() 方法用于开始或恢复动画的播放。

action.play();

5.2 paused

paused 属性控制动画是否暂停。如果将 paused 设置为 true,动画会停止播放,设置为 false 则恢复播放。

action.paused = true;  // 暂停动画
action.paused = false; // 恢复播放

5.3 stop()

stop() 方法停止动画播放,并将播放进度重置为初始状态。

action.stop();

5.4 reset()

reset() 方法将动画进度重置为初始状态,但不会停止动画。

action.reset();

5.5 playbackRate

playbackRate 属性控制动画的播放速度。默认值为 1,可以通过设置不同的值来加快或减慢动画速度。

action.playbackRate = 2; // 两倍速度播放
action.playbackRate = 0.5; // 半速播放

5.6 time

time 属性表示动画的当前时间。通过设置 time,可以跳到动画的指定时间点。

action.time = 1.5; // 跳到动画的 1.5 秒处

5.7 weight

weight 属性控制动画的权重,用于在多个动画混合时调整其影响程度。权重范围为 0(无影响)到 1(完全影响)。

action.weight = 0.5; // 混合权重为 50%

5.8 loop

loop 属性定义动画的循环方式,Three.js 提供了三种循环模式:

  • THREE.LoopOnce:动画播放一次后停止。
  • THREE.LoopRepeat:动画无限循环。
  • THREE.LoopPingPong:动画往复循环。
action.loop = THREE.LoopPingPong; // 动画来回播放

6. 混合多个 AnimationAction

Three.js 支持同时播放多个动画,并通过调整权重实现动画的平滑过渡。下面的示例展示了如何混合两个动画。

6.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('moveX', 2, [positionKF2]);
const action2 = mixer.clipAction(clip2);

6.2 混合动画

我们可以同时播放两个动画,并通过权重控制它们的影响:

action.play();
action2.play();
action.weight = 0.5;  // 第一动画的权重
action2.weight = 0.5; // 第二动画的权重

这样,立方体会同时沿 X 轴和 Y 轴移动,产生一个斜向的动画效果。

7. 完整示例

下面是一个完整的示例,展示了如何在 Three.js 中使用 AnimationAction 控制动画:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js AnimationAction 示例</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);

        camera.position.z = 5;

        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 mixer = new THREE.AnimationMixer(cube);

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

        const clip = new THREE.AnimationClip('move', 2, [positionKF]);
        const action = mixer.clipAction(clip);
        action.play();

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

        const clip2 = new THREE.AnimationClip('moveX', 2, [positionKF2]);
        const action2 = mixer.clipAction(clip2);
        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();
    </script>
</body>
</html>

8. 处理窗口调整

同样,不要忘记在窗口调整大小时更新渲染器和摄像机:

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

9. 结论

通过 AnimationAction,你可以灵活地控制 Three.js 中的动画效果,实现丰富的动画场景。本文详细介绍了 AnimationAction 的基本用法、常用属性和方法,并结合示例演示了如何实现不同的动画效果。希望对你在 Three.js 动画开发中有所帮助!如有问题或建议,欢迎留言讨论。

评论区
评论列表
menu