Blend Tree
Blend Tree は Animator Controller の特殊ノードで、1〜2 個の Float Parameter から複数の Animation Clip を混ぜます。速度や方向に応じて滑らかなロコモーションを作れ、継ぎ目のない移動表現ができます。図解とシミュレーターで重みの変化を体感できます。
想像してみてください...
Blend Tree はミキサーです。「ゆっくり歩き」「ジョギング」「スプリント」の 3 トラックがあるとき、硬直切替ではなく速度に応じてクロスフェードします——2 m/s なら歩き 70% + ジョグ 30%。8 m/s ならスプリント 100%。結果、速度が連続的に変わっても継ぎ目のないロコモーションになります。
概念の詳細
Blend Tree は Animator Controller 内の State を置き換えます——1 クリップではなく、パラメータから複数をブレンドします。主な 3 タイプ: 1D(float 1 つ、通常は速度)、2D Simple Directional(X/Z 速度など float 2 つ、8 方向移動)、 2D Freeform Directional/Cartesian(より柔軟な影響領域)。
1D Blend Tree では各クリップに Threshold があります——パラメータが 2 つの Threshold の間にあるとき、Unity が重みを補間します。例: Idle=0、Walk=2、Run=6——Speed=1 なら Idle 50%/Walk 50%。
Automate Thresholds
を有効にするとクリップを均等間隔にできます。
2D Blend Tree はより豊かなロコモーション向け: Walk Forward/Back/Left/Right、Idle、Run Forward… を水平+垂直速度からブレンドします。Unity は Gradient Band Interpolation(Simple)または Triangulation(Freeform)を使います。各クリップはパラメータ空間の (X, Y) 座標を持ちます。
Normalized time が重要です: クリップ長が違うとき、Unity は時間を 正規化 して位相を揃えます——歩きが 1 秒、走りが 0.6 秒でも右足のステップが揃います。モーションごとに
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)
ハンズオン手順
State に Blend Tree を作成
Animator ウィンドウ → 右クリック → Create State → From New Blend Tree。または State をダブルクリック → Add Motion → New Blend Tree。
Blend Tree のタイプを選ぶ
Inspector → Blend Type: 単純な速度なら 1D、8 方向移動なら 2D Simple Directional。
Parameter を割り当てて Motion を追加
1D: Float Parameter(Speed)を選ぶ。(+) → Add Motion → Animation Clip をドロップ。クリップごとに Threshold を設定。
Animator ウィンドウでプレビュー
再生中: Animator ウィンドウの Parameter スライダーをドラッグし、モデル上でライブブレンドを確認。
スクリプトから駆動
animator.SetFloat("Speed", velocity.magnitude)、2D なら animator.SetFloat("VelocityX", vel.x) もセット。
インタラクティブシミュレーター
Speed と Direction を調整し、Blend Tree が各クリップにどう重みを付けるか確認しましょう。
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 重みを読み取り、どのクリップが優位かを知る——足音オーディオに便利。
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: float 1 つ(速度)でブレンド、2D: float 2 つ(X, Z)
- ▸Threshold: クリップの weight=1 になるパラメータ値
- ▸SetFloat に damping を付けてブレンドのジッタを防ぐ
- ▸InverseTransformDirection でローカル空間へ変換
- ▸GetCurrentAnimatorClipInfo でライブ重みを読む
⚠️ よくあるミス
❌ Walk/Run ブレンド中に足が滑る
Walk と Run クリップのルートモーション速度が違う
✅ Blend Tree で "Adjust Time Scale" を有効にして速度を正規化
❌ 2D Blend Tree が斜め方向でおかしい
45° 方向用のクリップがない
✅ 斜めクリップを追加するか、"2D Freeform Cartesian" を使う