Blend Tree
Blend Tree là node đặc biệt trong Animator Controller, pha trộn nhiều Animation Clip theo một hoặc hai tham số float — chuyển động mượt theo tốc độ và hướng.
Hãy tưởng tượng...
Blend Tree giống như bộ điều chỉnh âm thanh của bộ phối nhạc. Bạn có ba track nhạc: "bước chậm", "chạy bộ", "chạy nước rút". Thay vì chuyển cắt giữa ba bản nhạc, bộ phối tự động trộn chúng theo tốc độ — khi tốc độ = 2m/s, nghe 70% bước chậm + 30% chạy bộ. Khi tốc độ = 8m/s, nghe 100% chạy nước rút. Kết quả: animation di chuyển tự nhiên không có điểm gãy nào dù tốc độ thay đổi liên tục.
Khái niệm chi tiết
Blend Tree là node thay thế State trong Animator Controller — thay vì chạy một clip, nó blend nhiều clip dựa trên parameter. Có ba loại chính: 1D (blend theo một float, dùng cho speed), 2D Simple Directional (blend theo hai float như X/Z velocity, dùng cho di chuyển 8 hướng), và 2D Freeform Directional/Cartesian (linh hoạt hơn, tự tính toán vùng ảnh hưởng).
Trong 1D Blend Tree, mỗi clip có một Threshold value — khi parameter
ở giữa hai threshold, Unity tính trọng số (weight) bằng nội suy tuyến tính. Ví dụ: Idle ở
threshold 0, Walk ở 2, Run ở 6 — khi Speed=1, blend Idle 50%/Walk 50%. Bật
Automate Thresholds
để Unity phân bố đều các clip.
2D Blend Tree dùng cho locomotion phức tạp: bạn có các clip cho Walk Forward, Walk Backward, Walk Left, Walk Right, Idle, Run Forward… và blend theo cả horizontal + vertical velocity. Unity dùng thuật toán Gradient Band Interpolation (Simple) hoặc Triangulation (Freeform) để tính weight tối ưu. Mỗi clip trong 2D có tọa độ (X, Y) trong không gian tham số.
Normalized time là điểm quan trọng: khi blend nhiều clip có độ dài khác nhau,
Unity normalize thời gian để tất cả cùng pha — chân phải luôn bước cùng nhau dù clip
walk 1s và run 0.6s. Bật
Time Scale
trên mỗi motion để kiểm soát tốc độ phát.
Sơ đồ 1D và 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)
Hướng dẫn thực hành
Tạo Blend Tree trong State
Trong Animator window → chuột phải → Create State → From New Blend Tree. Hoặc double-click một State → Add Motion → New Blend Tree.
Chọn loại Blend Tree
Inspector → Blend Type: 1D cho tốc độ đơn giản; 2D Simple Directional cho 8-directional movement.
Gán Parameter và thêm Motions
1D: chọn Float parameter (Speed). (+) → Add Motion → kéo Animation Clip. Đặt Threshold cho từng clip.
Preview trong Animator window
Khi đang Play: di chuyển slider Parameter trong Animator window để xem blend realtime trên model.
Drive từ script
animator.SetFloat("Speed", velocity.magnitude) và animator.SetFloat("VelocityX", vel.x) cho 2D.
Trình mô phỏng tương tác
Điều chỉnh Speed và Direction để xem Blend Tree tính trọng số từng clip.
Blend weights loading...
Ví dụ Code
Cơ bảnDrive 2D Blend Tree bằng Rigidbody velocity — locomotion đa hướng.
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()
{
// Chuyển velocity từ world → local space của nhân vật
Vector3 localVel = transform.InverseTransformDirection(rb.velocity);
// Damping 0.1s để blend mượt, không nhảy cóc
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);
}
}Ví dụ Code
Nâng caoĐọc Blend Tree weights hiện tại để biết clip nào đang dominant — dùng cho footstep audio.
using UnityEngine;
public class BlendTreeReader : MonoBehaviour
{
Animator anim;
void Awake() => anim = GetComponent<Animator>();
// Đọc danh sách clip đang blend và weight của chúng
void Update()
{
AnimatorClipInfo[] clips = anim.GetCurrentAnimatorClipInfo(0);
foreach (var info in clips)
{
Debug.Log($"{info.clip.name}: {info.weight:F2}");
}
// Tìm clip dominant (weight > 0.5) để chọn âm thanh bước chân
string dominant = "Idle";
float maxW = 0f;
foreach (var info in clips)
{
if (info.weight > maxW)
{
maxW = info.weight;
dominant = info.clip.name;
}
}
// dominant = tên clip chiếm ưu thế — chọn footstep volume theo đó
float footVol = dominant.Contains("Run") ? 1f :
dominant.Contains("Walk") ? 0.6f : 0f;
}
}📌 Ghi nhớ nhanh
- ▸1D: blend theo 1 float (tốc độ); 2D: theo 2 float (X, Z)
- ▸Threshold: giá trị parameter tại đó clip đạt weight=1
- ▸SetFloat với damping để tránh jitter khi blend
- ▸InverseTransformDirection để chuyển sang local space
- ▸GetCurrentAnimatorClipInfo để đọc weights hiện tại
⚠️ Lỗi thường gặp
❌ Nhân vật trượt chân khi blend Walk/Run
Clip Walk và Run có root motion speed khác nhau
✅ Enable "Adjust Time Scale" trong Blend Tree để normalize tốc độ
❌ Blend Tree 2D trông không tự nhiên ở diagonal
Không có clip cho hướng chéo (45 độ)
✅ Thêm clip diagonal hoặc dùng "2D Freeform Cartesian" type