经纬志
首页 / three.js / 使用示例

动画混合

两条片段分别驱动上臂与小臂,两个权重滑杆决定各自的影响比例。

three.js 0.160.0 · 更新 2026-10-28
源码与运行效果
运行效果

说明

机械臂由立柱、上臂与小臂组成,上臂的原点被安排在转动轴心上: 几何体先沿 X 平移半个长度,再把网格放到轴心位置, 这样改旋转就是绕轴转,不会整体甩出去。

两条片段都以四元数轨道驱动一个关节,时间轴同为 2.4 秒。 AnimationMixer 每帧把两条片段的结果按 setEffectiveWeight 混合,权重为 0 的那条不再影响姿态。

设置数值说明
片段时长2.4 秒两条片段共用同一组时间点
关键帧5 个0、0.6、1.2、1.8、2.4 秒
上臂摆幅±0.62 弧度约 ±35 度,绕 Z 轴
小臂摆幅−0.85 – 0.75 弧度相位与上臂错开
默认权重0.60 / 0.35两者之和不必等于 1
时间步长上限0.05 秒切到后台再回来时不会瞬移

轨道怎么命名

关键帧轨道用「节点名.属性」定位目标。节点名取自 Object3D.name,在本例中分别是 upper 与 lower。 Mixer 的根节点是机械臂所在的组,它只在这一棵子树里查找, 不会误伤场景里的其他同名对象。

const trackUpper = new THREE.QuaternionKeyframeTrack(
  'upper.quaternion',
  [0, 0.6, 1.2, 1.8, 2.4],
  quatValues([0, 0.62, 0, -0.62, 0])
);

const clipUpper = new THREE.AnimationClip('upper-swing', 2.4, [trackUpper]);

const mixer = new THREE.AnimationMixer(rig);
const actionA = mixer.clipAction(clipUpper);

actionA.play();
actionA.setEffectiveWeight(0.6);

旋转必须用四元数轨道。若写成欧拉角的三个数, 中间帧可能出现万向节死锁,姿态会以奇怪的角度穿过。 位置变化则用 VectorKeyframeTrack,缩放同理。

权重混合与交叉淡入

手动拖滑杆相当于直接设定权重,适合调试。 代码里更常见的写法是 crossFadeTo: 在指定时长内把当前动作淡出、目标动作淡入,两者的权重自动互补。

// 从走路切到跑步,1.2 秒内完成过渡
actionWalk.crossFadeTo(actionRun, 1.2, true);

第三个参数为 warp,开启后两条片段的时间轴会按比例缩放, 让脚步节奏平滑衔接。关闭时只混合姿态,可能出现瞬间的步频跳变。

每帧必须更新

mixer.update(dt) 是所有姿态变化的唯一来源, 渲染循环里漏掉它,画面会停在第一帧。 dt 建议设上限,页面被切到后台再切回来时 Clock 会返回一个很大的间隔,动画会直接跳过一整轮。

动画是姿态,不是数据。关键帧只描述节点的旋转与位移, 与要素属性、时间序列数据没有关系。 用动画表达时序变化时,需要自己把时间映射到关键帧位置。