javascript

【 Three.js&GSAP 】使用 Three.js 和 GSAP 控制模型中的动画

在中,我们通常会加载带有动画的模型,这些动画可能包含多个部件的运动(如车门的开闭、轮胎的旋转等)。为了使模型中的动画更加生动且易于控制,我们可以借助(GreenSock Animation Platform)库,直接控制模型的各个部分或整个动画序列。本文将介绍两种常见的应用场景:

2024-11-24·阅读约 14 分钟·计算中...

Three.js 中,我们通常会加载带有动画的模型,这些动画可能包含多个部件的运动(如车门的开闭、轮胎的旋转等)。为了使模型中的动画更加生动且易于控制,我们可以借助 GSAP(GreenSock Animation Platform)库,直接控制模型的各个部分或整个动画序列。本文将介绍两种常见的应用场景:一是通过 GSAP 控制模型中某个组件的动画,二是控制整个模型的动画播放。

模型设计师与程序员的协作

在 3D 项目开发中,模型设计师和程序员需要紧密合作。设计师有时会将动画直接嵌入到模型中,而有时他们仅提供动画的基本框架,让程序员来控制动画的细节。这种做法通常取决于项目需求和开发进度。

  1. 设计师嵌入动画:设计师可以在模型制作时就将动画直接加入(例如,车门开关、人物动作等)。这些动画会被打包进模型文件中,程序员只需通过 Three.jsAnimationMixer 来控制动画的播放。

  2. 程序员控制动画:如果设计师没有在模型中预设动画,或者需要程序员根据用户交互来控制动画,程序员可以通过 GSAPThree.js 的动画系统,直接控制模型的各个部件(如门、车轮等)的旋转、平移等动画效果。

无论哪种方式,程序员都可以利用 GSAP 来进一步优化和控制动画的播放,增强用户体验。


1. 使用 GSAP 控制模型中的元件动画

有时我们不需要播放整个模型的动画序列,而是希望单独控制模型中的某个部件(例如车门)的动画。在这种情况下,我们可以直接通过 GSAP 来控制目标元件的属性变化,通常是旋转、平移等。

示例:控制车门的开关

假设我们有一个包含多个车门动画的模型,但我们只希望控制其中一个车门的开关。通过 GSAP,我们可以控制车门的旋转或平移,以实现开门和关门的动画效果。

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import gsap from 'gsap';

// 初始化场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const controls = new OrbitControls(camera, renderer.domElement);

// 添加环境光
const light = new THREE.AmbientLight(0xffffff, 1);
scene.add(light);

// 加载 GLTF 模型
const loader = new GLTFLoader();
let car;  // 存储整个车模型
let doorLF; // 左前门模型
let isDoorLFOpen = false;  // 车门开关状态

loader.load(
  "path/to/your/car_model.glb", // 替换为你的模型路径
  (gltf) => {
    car = gltf.scene;
    scene.add(car);

    // 假设左前门的模型名字为 "Door_LF"(根据你的模型结构)
    doorLF = car.getObjectByName("Door_LF");

    // 确保门处于关闭状态
    doorLF.rotation.y = 0;

    // 设置默认动画状态
    doorLF.visible = true;
  },
  undefined,
  (error) => {
    console.error("加载模型失败", error);
  }
);

// 渲染循环
function animate() {
  requestAnimationFrame(animate);
  controls.update();  // 更新控制器
  renderer.render(scene, camera);
}
animate();

// 按钮事件控制
document.getElementById("toggleLF").addEventListener("click", () => {
  if (!doorLF) return;  // 如果门尚未加载,跳过

  if (isDoorLFOpen) {
    // 使用 GSAP 反向动画打开车门
    gsap.to(doorLF.rotation, {
      y: 0,  // 关门,y轴旋转回原始位置
      duration: 1,
      ease: "power2.out"
    });
  } else {
    // 使用 GSAP 动画打开车门
    gsap.to(doorLF.rotation, {
      y: Math.PI / 2,  // 打开门,y轴旋转 90 度
      duration: 1,
      ease: "power2.out"
    });
  }

  // 切换车门状态
  isDoorLFOpen = !isDoorLFOpen;
});
关键点解析
  1. 获取目标元件
    使用 car.getObjectByName("Door_LF") 获取车门的 3D 对象。你需要根据你的模型实际结构修改 Door_LF 为你想控制的部件名称。

  2. GSAP 动画控制

    • gsap.to(doorLF.rotation, { y: Math.PI / 2, duration: 1, ease: "power2.out" }):控制车门沿 Y 轴旋转 90 度,以模拟车门打开。
    • gsap.to(doorLF.rotation, { y: 0, duration: 1, ease: "power2.out" }):将车门旋转回原始位置,模拟车门关闭。
  3. 控制状态
    使用布尔变量 isDoorLFOpen 来跟踪车门的开关状态,每次点击按钮时反转该状态,并触发动画。


2. 控制整个模型中的动画

有时我们需要控制整个模型的动画序列,比如车门的开闭、车轮的转动等,通常这些动画已经预设在模型文件中。我们可以使用 AnimationMixer 来播放这些动画,但如果你想通过 GSAP 来控制这些动画的播放状态、速率或进度,也完全可以实现。

示例:控制整个车门开关的动画

假设模型中已经包含了车门开关的动画序列,我们希望通过 GSAP 来控制整个动画的播放、暂停或进度。

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

// 初始化场景和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 加载 GLTF 模型
const loader = new GLTFLoader();
let mixer; // 动画混合器

loader.load(
  "path/to/your/car_model.glb", // 替换为你的模型路径
  (gltf) => {
    const model = gltf.scene;
    scene.add(model);

    // 创建 AnimationMixer
    mixer = new THREE.AnimationMixer(model);

    // 获取完整动画片段
    const fullAnimationClip = gltf.animations[0]; // 假设第一个动画是车门开闭
    const action = mixer.clipAction(fullAnimationClip);

    // 控制动画的播放
    action.play(); // 播放动画

    // 控制动画的暂停
    action.paused = true; // 暂停动画

    // 修改动画的播放速度
    action.timeScale = 2; // 动画加速
  },
  undefined,
  (error) => {
    console.error("加载模型失败", error);
  }
);

// 渲染循环
function animate() {
  requestAnimationFrame(animate);
  if (mixer) mixer.update(0.01); // 更新动画混合器
  renderer.render(scene, camera);
}
animate();
关键点解析
  1. AnimationMixer 控制动画
    使用 AnimationMixer 来管理和控制模型的动画。通过 clipAction 获取动画,并使用 action.play() 开始播放,或者 action.paused = true 来暂停动画。

  2. GSAP 控制动画进度和速率

    • 通过 gsap.to() 可以控制整个动画的进度,比如改变动画播放速率 timeScale 或者设置动画的播放时间。
  3. 灵活控制动画
    使用 GSAP 可以更加精细地控制动画效果,包括速度、延迟、反向播放等,增强用户体验。


小结

无论是直接使用 Three.js 内置的动画系统,还是结合 GSAP 来实现更加精细的动画控制,模型动画的实现都需要依赖设计师和程序员的协作。通过合理的接口设计,程序员可以在不干扰设计师模型的基础上,实现更多的交互效果和控制方式。

希望本文的示例能帮助你更好地理解如何在 Three.js 中使用 GSAP 控制动画。如果你有其他问题,欢迎随时讨论!

订阅 FreeMac

每周精选:Mac 高效技巧、免费替代付费软件、开发者工具推荐。用对你的 MacBook,省钱 + 提效。