AnimationMixer 实例必须在渲染循环中持续调用 update(delta),否则动画完全不播放;delta 必须为秒级浮点数,推荐用 THREE.Clock.getDelta() 获取,且 mixer 必须绑定正确 root(如 gltf.scene)。

AnimationMixer 实例必须在渲染循环中持续 update
不调用 mixer.update(delta),动画就完全不会播放——这是最常被忽略的硬性前提。glTF 加载后得到的 AnimationClip 只是数据模板,真正驱动骨骼变换的是 AnimationMixer 持续对当前时间做插值计算。
常见错误现象:model.scene 显示正常,但角色僵直不动;控制台无报错,mixer.clipAction(...).play() 也调用了,就是没反应。
- 确保
delta是以秒为单位的浮点数(例如从requestAnimationFrame的时间戳差值除以 1000 得到) - 必须在每一帧都调用
mixer.update(delta),不能只在加载完成时调用一次 - 如果使用
THREE.Clock,直接用clock.getDelta()最稳妥
clipAction 需显式绑定到模型的 skeleton root(通常是 model.scene)
glTF 导入后,骨骼动画作用的目标不是 model 对象本身,而是其内部的 scene(含 skeleton 和 skinnedMesh)。若传错对象,clipAction 会静默失败,不报错也不生效。
使用场景:加载多个 glTF 模型、或模型含嵌套组(如 Group 包裹 Scene)时尤其容易出错。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 正确写法:
mixer.clipAction(clip, model.scene)(model是GLTFLoader.load()回调里的gltf对象) - 错误写法:
mixer.clipAction(clip, model)或mixer.clipAction(clip, model.scene.children[0]) - 可加一行验证:
console.log('has skeleton?', model.scene.skeleton !== undefined)
glTF 动画轨道名和 clip 名通常不匹配,别依赖命名找 clip
很多用户试图用 gltf.animations.find(a => a.name === 'Walk'),但 glTF 导出器(如 Blender)生成的 name 字段常为空、重复或与 DCC 软件里显示的名字不一致。实际应优先靠索引或遍历检查 clip.tracks.length 和骨骼路径。
参数差异:AnimationClip 的 tracks 数组里每个 track 的 name 形如 "Armature.001.bone_002.rotation",这才是真实作用目标。
- 安全做法:用
gltf.animations[0]直接取第一个动画(多数单动画模型够用) - 调试技巧:打印所有 clips:
gltf.animations.forEach((c, i) => console.log(i, c.name, c.tracks.length)) - 性能影响:多动画时,提前用
mixer.clipAction(clip).setEffectiveWeight(0)关闭不用的 action,避免无谓计算
SkinnedMesh 必须启用 skinning,且材质需支持蒙皮
即使 mixer 正常 update、action 正确 play,如果模型的 SkinnedMesh 没启用 skinning 或材质不支持,骨骼变换仍不会影响顶点——表现为模型整体位移/旋转了,但肢体不变形。
容易踩的坑:手动创建材质、或使用自定义 shader 时忘记设 skinning: true;或者 glTF 加载后修改了材质但没同步更新 skinning 状态。
- 检查方式:
model.scene.traverse(o => { if (o.isSkinnedMesh) console.log('skin:', o.skeleton, 'mat.skin:', o.material.skinning) }) - 修复方法:对每个
SkinnedMesh,确保o.material.skinning = true,并重新赋值材质(触发内部更新) - 兼容性注意:WebGL1 设备上部分旧驱动对
skinning支持不稳定,建议用WebGLRenderer({ antialias: true })并禁用powerPreference: 'low-power'
mixer.update 在跑 → 再看 clipAction.play() 后 action.time 是否递增 → 最后查 SkinnedMesh.material.skinning 是否为 true。


















