6.2Three.js 动画系统 6.2 Three.js 动画系统详解 Three.js 动画系统提供了一套强大的工具,用于创建复杂的动画效果。它允许你控制场景中对象的属性,如位置、旋转、缩放、材质属性等,并随着时间推移改变这些属性,从而实现各种动画效果。 6.2.1 动画系统的核心概念 Three.js 动画系统的核心概念包括: AnimationClip: 动画剪辑,定义了动画的关键帧数据,描述了在特定时间内属性的变化。 KeyframeTrack: 关键帧轨道,存储了特定属性(例如位置或旋转)随时间变化的关键帧数据。 AnimationMixer: 动画混合器,用于管理和播放AnimationClip,并将其应用到场景中的对象。
Three.js 动画系统提供了一套强大的工具,用于创建复杂的动画效果。它允许你控制场景中对象的属性,如位置、旋转、缩放、材质属性等,并随着时间推移改变这些属性,从而实现各种动画效果。
Three.js 动画系统的核心概念包括:
AnimationClip: 动画剪辑,定义了动画的关键帧数据,描述了在特定时间内属性的变化。
KeyframeTrack: 关键帧轨道,存储了特定属性(例如位置或旋转)随时间变化的关键帧数据。
AnimationMixer: 动画混合器,用于管理和播放AnimationClip,并将其应用到场景中的对象。
AnimationAction: 动画动作,AnimationMixer创建的实例,代表一个正在播放的AnimationClip。
可以用 mermaid 图来表示它们之间的关系:
动画的核心在于定义属性如何随时间变化。这通过 AnimationClip 和 KeyframeTrack 实现。
1. KeyframeTrack:
KeyframeTrack 定义了特定属性在不同时间点的值。Three.js 提供了多种类型的 KeyframeTrack,例如:
NumberKeyframeTrack: 用于数字属性,如位置、缩放等。
VectorKeyframeTrack: 用于 THREE.Vector3 属性,如位置、缩放等。
QuaternionKeyframeTrack: 用于 THREE.Quaternion 属性,如旋转。
ColorKeyframeTrack: 用于 THREE.Color 属性,如材质颜色。
代码示例:创建一个 NumberKeyframeTrack 控制物体 X 轴位置
import * as THREE from 'three'; // 时间轴,单位秒 const times = [0, 1, 2]; // 对应时间点的值 const values = [0, 5, 0]; const track = new THREE.NumberKeyframeTrack('.position[x]', times, values);
在上面的代码中:
.position[x] 指定了要控制的属性,这里是物体的 X 轴位置。
times 数组定义了关键帧的时间点(秒)。
values 数组定义了对应时间点属性的值。
2. AnimationClip:
AnimationClip 将多个 KeyframeTrack 组合在一起,形成一个完整的动画剪辑。
代码示例:创建一个 AnimationClip
const clip = new THREE.AnimationClip('moveX', 3, [track]); // 名称,时长,轨道数组
在上面的代码中:
'moveX' 是动画剪辑的名称。
3 是动画剪辑的总时长(秒)。
[track] 是一个包含 KeyframeTrack 的数组。
AnimationMixer 负责管理和播放 AnimationClip。AnimationAction 是 AnimationMixer 创建的实例,代表一个正在播放的 AnimationClip。
代码示例:使用 AnimationMixer 播放动画
// 创建一个立方体 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); // 创建 AnimationMixer const mixer = new THREE.AnimationMixer(cube); // 创建 AnimationAction const action = mixer.clipAction(clip); // 播放动画 action.play(); // 在渲染循环中更新 AnimationMixer function animate() { requestAnimationFrame(animate); mixer.update(delta); // delta 是时间间隔 renderer.render(scene, camera); } animate();
在上面的代码中:
new THREE.AnimationMixer(cube) 创建了一个与立方体关联的 AnimationMixer。
mixer.clipAction(clip) 创建了一个 AnimationAction,用于播放之前创建的 AnimationClip。
action.play() 开始播放动画。
mixer.update(delta) 更新 AnimationMixer,根据时间间隔 delta 计算动画的当前状态。 delta通常是 clock.getDelta() 的返回值.
AnimationAction 提供了多种方法来控制动画的播放:
action.play(): 开始播放动画。
action.stop(): 停止播放动画。
action.pause(): 暂停动画。
action.resume(): 恢复播放动画。
action.reset(): 重置动画到初始状态。
action.crossFadeTo(otherAction, duration, warp): 平滑过渡到另一个动画。
action.setLoop(loopMode, repeatCount): 设置循环模式和重复次数。
action.timeScale: 动画播放速度,1 为正常速度,大于 1 加速,小于 1 减速。
action.weight: 动画权重,0 为完全不显示,1 为完全显示。
代码示例:动画循环播放
action.setLoop(THREE.LoopRepeat, Infinity); // 无限循环
代码示例:动画速度控制
action.timeScale = 2; // 两倍速度播放
代码示例:动画权重控制
action.weight = 0.5; // 动画权重为 0.5
Three.js 支持从外部文件加载动画,例如 GLTF/GLB 文件。
代码示例:加载 GLTF 模型和动画
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; const loader = new GLTFLoader(); loader.load('path/to/model.gltf', function (gltf) { const model = gltf.scene; scene.add(model); const mixer = new THREE.AnimationMixer(model); const clips = gltf.animations; clips.forEach(function (clip) { const action = mixer.clipAction(clip); action.play(); }); // 在渲染循环中更新 AnimationMixer function animate() { requestAnimationFrame(animate); mixer.update(delta); renderer.render(scene, camera); } animate(); });
在上面的代码中:
GLTFLoader 用于加载 GLTF 模型。
gltf.scene 包含加载的模型。
gltf.animations 包含加载的动画剪辑。
遍历 gltf.animations,为每个 AnimationClip 创建一个 AnimationAction 并播放。
Three.js 动画系统允许你在动画的特定时间点触发事件。这可以通过 AnimationAction 的 time 和 weight 属性来实现。你需要手动检测这些属性的值,并在达到特定值时执行相应的操作。
代码示例:在动画播放到一半时触发事件
action.play(); function animate() { requestAnimationFrame(animate); mixer.update(delta); if (action.time > clip.duration / 2 && !eventTriggered) { console.log('动画播放到一半了!'); eventTriggered = true; } renderer.render(scene, camera); } let eventTriggered = false; animate();
动画混合(Animation Blending): 通过 crossFadeTo 方法,可以平滑地在不同的动画之间过渡,创建更自然的动画效果。
动画权重(Animation Weighting): 通过调整 AnimationAction 的 weight 属性,可以控制不同动画的影响程度,实现更复杂的动画混合效果。
骨骼动画(Skeletal Animation): 对于具有骨骼结构的模型,可以使用 THREE.Skeleton 和 THREE.SkinnedMesh 来实现骨骼动画。
形态动画(Morph Animation): 通过 THREE.MorphTarget 和 THREE.MorphTargetInfluences,可以实现模型形状的平滑变形。
动画可能会消耗大量的计算资源,因此性能优化至关重要。以下是一些优化建议:
减少动画对象的数量: 尽量减少场景中需要进行动画的对象数量。
简化动画: 避免使用过于复杂的动画,尽量使用简单的动画效果。
使用 LOD(Level of Detail): 对于距离较远的对象,可以使用低精度的模型和动画。
优化关键帧数据: 减少关键帧的数量,并使用压缩算法来减小关键帧数据的大小。
避免在动画循环中进行复杂的计算: 尽量将复杂的计算移到动画循环之外。
Three.js 动画系统是一个功能强大的工具,可以用于创建各种复杂的动画效果。通过理解动画系统的核心概念,并掌握相关的 API,你可以轻松地为你的 Three.js 场景添加生动的动画效果。记住,性能优化是动画开发中不可忽视的重要环节。
希望这篇文章能够帮助你更好地理解和使用 Three.js 动画系统。通过实践和探索,你将能够创造出令人惊叹的 3D 动画体验。