动画

Starter pack

动画是让您的3D 场景变得生动的关键。它们可以通过用户交互滚动时间触发,并应用于3D 对象灯光相机

掌握动画是一种创建沉浸式体验的关键技能。您掌握的技巧越多,就越能表达您的创造力

注意: 3D 模型动画的内容已在模型章节中介绍。

Lerp

Lerp 是一种数学函数,可以在两个值之间进行插值。它非常有用于在两个点之间动画化一个

const value = THREE.MathUtils.lerp(start, end, t);

第一个参数起始值第二个参数结束值第三个参数是介于 01 之间的插值因子

插值因子越接近0动画就越慢。插值因子越接近1,动画达到结束或目标值的速度就越快。

让我们在 starter packAnimatedBox 组件上试验一下。

该组件有一个 boxPositions 数组,包含盒子不同时间点位置。让我们添加一个 useFrame 钩子以基于时间更新盒子的位置:

import { RoundedBox } from "@react-three/drei";
import { useRef } from "react";

export const AnimatedBox = ({ boxPositions, ...props }) => {
  const box = useRef();

  useFrame(({ clock }) => {
    const seconds = parseInt(clock.getElapsedTime());
    const targetPosition = boxPositions[seconds % boxPositions.length];

    box.current.position.x = targetPosition.x;
    box.current.position.y = targetPosition.y;
    box.current.position.z = targetPosition.z;
  });
  // ...
};

此时我们的盒子并未动画化。它是从一个位置跳到另一个位置。让我们使用 lerp 函数为它添加动画:

import * as THREE from "three";
// ...

export const AnimatedBox = ({ boxPositions, ...props }) => {
  const box = useRef();

  useFrame(({ clock }) => {
    const seconds = parseInt(clock.getElapsedTime());
    const targetPosition = boxPositions[seconds % boxPositions.length];
    box.current.position.x = THREE.MathUtils.lerp(
      box.current.position.x,
      targetPosition.x,
      0.05
    );
    box.current.position.y = THREE.MathUtils.lerp(
      box.current.position.y,
      targetPosition.y,
      0.05
    );
    box.current.position.z = THREE.MathUtils.lerp(
      box.current.position.z,
      targetPosition.z,
      0.05
    );
  });
  // ...
};

现在盒子有了动画效果。它可以平滑地从一个位置移动到另一个位置。

Vector3 类有一个 lerp 方法,可以替代使用 THREE.MathUtils.lerp 函数:

// box.current.position.x = THREE.MathUtils.lerp(
//   box.current.position.x,
//   targetPosition.x,
//   0.05
// );
// box.current.position.y = THREE.MathUtils.lerp(
//   box.current.position.y,
//   targetPosition.y,
//   0.05
// );
// box.current.position.z = THREE.MathUtils.lerp(
//   box.current.position.z,
//   targetPosition.z,
//   0.05
// );
box.current.position.lerp(targetPosition, 0.05);

这样可以减少很多行代码,而且效果相同!

请不要犹豫,尽情玩弄这些时间,尝试对其他属性(如 rotationscale)进行 lerp 操作,以尝试不同的效果

Float

FloatDrei 库 中的一个包装组件,用于简单地给对象一种漂浮的印象。

它包含以下属性:

  • speed: 动画速度,默认为 1
  • rotationIntensity: XYZ 轴旋转强度,默认为 1
  • floatIntensity: 上/下漂浮强度,与 floatingRange 一起作为乘数使用,默认为 1
  • floatingRange: 对象在 y 轴方向漂浮的范围,默认为 [-0.1, 0.1]

让我们在 Experience.jsx 中让我们的 Duck 漂浮起来:

Three.js logoReact logo

React Three Fiber: The Ultimate Guide to 3D Web Development

✨ You have reached the end of the preview ✨

Go to the next level with Three.js and React Three Fiber!

Get full access to this lesson and the complete course when you enroll:

  • 🔓 Full lesson videos with no limits
  • 💻 Access to the final source code
  • 🎓 Course progress tracking & completion
  • 💬 Invite to our private Discord community
Unlock the Full Course – Just $85

One-time payment. Lifetime updates included.