Angular中基于Three.js合并GLTF动画的实现方法
在Three.js中组合同一模型的面部与肢体GLTF动画
核心前提
首先必须确保两组GLTF文件基于完全相同的基础模型与骨骼结构——骨骼的层级、名称、绑定关系必须完全一致,否则动画无法正确映射到模型上。如果导出时没做到这一点,先回到建模软件(比如Blender)调整:导出一个带骨骼的基础模型,再分别导出面部表情、肢体动作的纯动画文件(不带模型网格)。
实现步骤
1. 加载模型与动画资源
在Angular项目中,用GLTFLoader分别加载基础模型、面部动画GLTF、肢体动作GLTF:
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { AnimationMixer, AnimationAction } from 'three'; let mixer: AnimationMixer; let model: THREE.Group; // 存储所有动画Action const animationActions: Record<string, AnimationAction> = {}; // 先加载带骨骼的基础模型 new GLTFLoader().load('path/to/base-model.gltf', (gltf) => { model = gltf.scene; scene.add(model); mixer = new AnimationMixer(model); // 加载面部动画GLTF,提取动画剪辑 new GLTFLoader().load('path/to/facial-animations.gltf', (facialGltf) => { facialGltf.animations.forEach((clip) => { const action = mixer.clipAction(clip); animationActions[clip.name] = action; }); }); // 加载肢体动作GLTF,提取动画剪辑 new GLTFLoader().load('path/to/body-animations.gltf', (bodyGltf) => { bodyGltf.animations.forEach((clip) => { const action = mixer.clipAction(clip); animationActions[clip.name] = action; }); }); });
2. 组合播放动画
当需要播放「奔跑+微笑」这类组合时,直接调用对应动画Action的play()方法即可——只要两类动画的骨骼影响范围不重叠(面部动画只动面部骨骼,肢体动画只动躯干四肢),它们会自然叠加:
// 播放奔跑+微笑 animationActions['run'].loop = THREE.LoopRepeat; animationActions['run'].play(); animationActions['smile'].loop = THREE.LoopRepeat; animationActions['smile'].play();
如果存在骨骼重叠(比如某段动画同时影响头部),可以通过调整weight属性控制动画混合程度:
// 让面部动画完全覆盖头部的肢体动画影响 animationActions['smile'].weight = 1; animationActions['smile'].play();
3. 帧更新动画
在Angular的动画循环中(比如用requestAnimationFrame),必须更新AnimationMixer的时间,否则动画不会播放:
let prevTime = performance.now(); function animate() { requestAnimationFrame(animate); const currentTime = performance.now(); const delta = (currentTime - prevTime) / 1000; if (mixer) { mixer.update(delta); } renderer.render(scene, camera); prevTime = currentTime; } animate();
关键注意点
- 不要为同一模型创建多个
AnimationMixer,所有动画都要绑定到同一个mixer实例上。 - 如果加载的GLTF包含重复模型,记得只保留基础模型,只提取另一组的动画剪辑,避免场景中出现重复模型。
- 建模导出时,确保动画的骨骼名称与基础模型完全匹配,哪怕是大小写差异都会导致动画失效。
内容的提问来源于stack exchange,提问作者james Makinde
相关产品推荐
相关产品推荐

