Unity Term Book
애니메이션 & UI

Blend Tree

Blend Tree는 Animator Controller의 특수 노드로, 하나 또는 두 개의 float 파라미터로 여러 Animation Clip을 섞습니다. 속도·방향에 따른 부드러운 로코모션과 1D·2D 블렌드 가중치·Threshold를 다루는 실전 학습 가이드입니다.

상상해 보세요...

Blend Tree는 믹서입니다. "느린 걷기", "조깅", "스프린트" 세 트랙이 있을 때, 하드컷 대신 속도에 따라 크로스페이드합니다——2 m/s면 걷기 70% + 조깅 30%. 8 m/s면 스프린트 100%. 결과: 속도가 연속으로 바뀌어도 이음새 없는 로코모션입니다.

개념 자세히

Blend Tree는 Animator Controller의 State를 대체합니다——클립 하나 대신 파라미터로 여러 클립을 블렌드합니다. 주요 유형 셋: 1D(float 하나, 보통 속도), 2D Simple Directional(X/Z 속도처럼 float 둘, 8방향 이동), 2D Freeform Directional/Cartesian(더 유연한 영향 영역).

1D Blend Tree에서 각 클립에는 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)

↑ 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; 8방향 이동은 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가 각 클립에 주는 가중치를 확인하세요.

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: 클립 가중치=1이 되는 파라미터 값
  • ▸SetFloat에 damping을 써 블렌드 지터 방지
  • ▸InverseTransformDirection으로 로컬 공간 변환
  • ▸GetCurrentAnimatorClipInfo로 실시간 가중치 읽기

⚠️ 흔한 실수

  • ❌ Walk/Run 블렌드 시 발이 미끄러짐

    Walk와 Run 클립의 루트 모션 속도가 다름

    ✅ Blend Tree에서 "Adjust Time Scale"을 켜 속도를 정규화

  • ❌ 2D Blend Tree가 대각선에서 이상함

    45° 방향용 클립이 없음

    ✅ 대각선 클립을 추가하거나 "2D Freeform Cartesian" 사용