Unity Term Book
动画与 UI

Blend Tree

Blend Tree 是 Unity Animator Controller 中的特殊节点,用一到两个 float 参数混合多段 Animation Clip,按速度与方向实现平滑运动过渡。适合角色八向移动、瞄准混合与坡度适应等场景,帮助动画师减少硬切抖动,让程序用参数驱动自然、可调的运动表现效果。

想象一下...

Blend Tree 是一台混音器。你有三条音轨:"慢走"、"慢跑"、"冲刺"。不是硬切,混音器按速度交叉淡化——2 m/s 时听到 70% 走 + 30% 慢跑;8 m/s 时 100% 冲刺。结果:速度连续变化时,移动动画也没有接缝。

概念详解

Blend Tree 在 Animator Controller 中替代普通 State—— 不是一段 clip,而是按参数混合多段。三种主要类型: 1D(一个 float,通常是速度)、2D Simple Directional(两个 float 如 X/Z 速度,八向移动),以及 2D Freeform Directional/Cartesian(影响区域更灵活)。

1D Blend Tree 中,每段 clip 有一个 Threshold——参数落在两个阈值之间时, Unity 插值权重。例如:Idle 在 0,Walk 在 2,Run 在 6——Speed=1 时得到 Idle 50%/Walk 50%。 开启 Automate Thresholds 可均匀分布 clip。

2D Blend Tree 用于更丰富的移动:前/后/左/右走、Idle、前跑… 由水平 + 垂直速度混合。 Unity 使用 Gradient Band Interpolation(Simple)或 Triangulation(Freeform)。 每段 clip 在参数空间有 (X, Y) 坐标。

Normalized time 很重要:clip 长度不同时,Unity 会 归一化 时间以保持同相—— 即使走 1s、跑 0.6s,右脚也始终一起落地。可对每段 motion 开启 Time Scale 控制播放速度。

1D 与 2D Blend Tree

1D Blend (Speed)

Idle

0

Walk

2

Walk

4

Run

6

Threshold: Idle=0 · Walk=2 · Run=6

2D Blend (Velocity X/Z)

↑ Fwd
↓ Bwd
I
F
B
L
R

动手步骤

1

在 State 中创建 Blend Tree

Animator 窗口 → 右键 → Create State → From New Blend Tree。或双击 State → Add Motion → New Blend Tree。

2

选择 Blend Tree 类型

Inspector → Blend Type:简单速度用 1D;八向移动用 2D Simple Directional。

3

指定 Parameter 并添加 Motions

1D:选 Float 参数(Speed)。(+)→ Add Motion → 拖入 Animation Clip。为每段设 Threshold。

4

在 Animator 窗口预览

播放时:在 Animator 窗口拖动 Parameter 滑条,实时看模型上的混合。

5

用脚本驱动

animator.SetFloat("Speed", velocity.magnitude);2D 再加 animator.SetFloat("VelocityX", vel.x)。

交互模拟器

调节 Speed 与 Direction,观察 Blend Tree 如何为每段 clip 分配权重。

Blend weights loading...

代码示例

基础

用 Rigidbody 速度驱动 2D Blend Tree——多方向移动。

using UnityEngine;

public class BlendTreeDriver : MonoBehaviour
{
  Animator anim;
  Rigidbody rb;

  static readonly int VelXHash = Animator.StringToHash("VelocityX");
  static readonly int VelZHash = Animator.StringToHash("VelocityZ");
  static readonly int SpeedHash = Animator.StringToHash("Speed");

  void Awake()
  {
      anim = GetComponent<Animator>();
      rb   = GetComponent<Rigidbody>();
  }

  void Update()
  {
      // World velocity → character local space
      Vector3 localVel = transform.InverseTransformDirection(rb.velocity);

      // 0.1s damping so the blend does not jump
      const float damp = 0.1f;
      anim.SetFloat(VelXHash,  localVel.x, damp, Time.deltaTime);
      anim.SetFloat(VelZHash,  localVel.z, damp, Time.deltaTime);
      anim.SetFloat(SpeedHash, localVel.magnitude, damp, Time.deltaTime);
  }
}

代码示例

进阶

读取当前 Blend Tree 权重,了解哪段 clip 占主导——适合脚步音效。

using UnityEngine;

public class BlendTreeReader : MonoBehaviour
{
  Animator anim;

  void Awake() => anim = GetComponent<Animator>();

  // List clips currently blending and their weights
  void Update()
  {
      AnimatorClipInfo[] clips = anim.GetCurrentAnimatorClipInfo(0);

      foreach (var info in clips)
      {
          Debug.Log($"{info.clip.name}: {info.weight:F2}");
      }

      // Dominant clip (weight > 0.5) → pick a footstep volume
      string dominant = "Idle";
      float maxW = 0f;
      foreach (var info in clips)
      {
          if (info.weight > maxW)
          {
              maxW = info.weight;
              dominant = info.clip.name;
          }
      }

      float footVol = dominant.Contains("Run") ? 1f :
                      dominant.Contains("Walk") ? 0.6f : 0f;
  }
}

📌 快速记忆

  • 1D:按 1 个 float(速度)混合;2D:按 2 个 float(X、Z)
  • Threshold:某 clip 权重=1 时的参数值
  • SetFloat 加 damping 避免混合抖动
  • InverseTransformDirection 转到本地空间
  • GetCurrentAnimatorClipInfo 读取实时权重

⚠️ 常见错误

  • ❌ 混合 Walk/Run 时角色脚滑

    Walk 与 Run clip 的根运动速度不同

    ✅ 在 Blend Tree 上开启 "Adjust Time Scale" 归一化速度

  • ❌ 2D Blend Tree 斜向看起来不对

    没有 45° 方向的 clip

    ✅ 加斜向 clip,或用 "2D Freeform Cartesian"