이 동작 하나하나를 State Machine으로 연결하면, 노드 수십 개에 화살표 수백 개가 엉키는 스파게티가 만들어진다.
상태가 추가될 때마다 Transition(전이 조건)을 손으로 이어야 하고...
모션 매칭은 이 순서를 아예 버린다.
“지금 캐릭터가 이 속도, 이 방향, 이 포즈로 움직이고 있는데 가장 자연스럽게 이어질 동작이 뭐야?”
매 프레임 이 질문을 던지고, 수백 개의 애니메이션 데이터 중 가장 점수가 높은 포즈를 실시간으로 골라 재생한다.
이 글에서는 모션 매칭 시스템을 구성하는 여섯 개의 핵심 에셋이 어떤 역할을 하고 어떻게 연결되는지를 정리한다.
1. 원인 분석: 모션 매칭은 어떤 구조로 동작하는가
모션 매칭 시스템은 여섯 개의 에셋이 체인처럼 연결된다. 각각의 역할을 하나씩 분해한다.
1-1. Pose Search Schema (PSS) — 질문지 설계도
시스템이 캐릭터를 관찰할 때 “뭘 볼 건지” 적어둔 체크리스트다.
이 체크리스트의 각 항목을 채널(Channel)이라 부른다.
대표적인 채널은 두 가지다.
궤적 채널(Trajectory Channel)은 캐릭터가 앞으로 어디로 이동할지, 과거에 어디서 왔는지를 샘플링한다.
포즈 채널(Pose Channel)은 지금 양발이 어디에 있는지, 특정 뼈의 위치와 속도를 추적한다.
이 외에도 Velocity Channel, Heading Channel, Position Channel 등 다양한 채널을 추가할 수 있다.
각 채널에는 가중치(Weight)가 있다. “발 위치에 70점 배점, 이동 방향에 30점 배점” 같은 식으로 설계자가 의도적으로 중요도를 조절한다. 이 Weight 설정이 모션 매칭 결과의 품질을 좌우한다.
포즈 서치 스키마(Pose Search Schema)에서 가중치(Weight)를 1.0(기본값)에서 4.0(정지 상태)으로 높여 설정한 데에는 애니메이션의 '반응성'과 '정확도'를 조절하려는 명확한 의도가 있다.
1) 가중치 설정의 핵심 의도 (1.0 vs 4.0) - 1.0 (Default - 균형 유지): 일반적인 이동 상태에서는 캐릭터의 '포즈(Pose)'와 '궤적(Trajectory)'를 적절히 섞어서 판단한다. 포즈가 자연스러우면서도 경로를 잘 따라가는 애니메이션을 고르게 된다. - 4.0 (Stop - 강한 구속력): 정지(Stop) 상태는 캐릭터가 즉각적으로 멈춰야 하는 상황이다. 이때 가중치를 4.0으로 높이는 것은 "포즈가 조금 덜 어울리더라도, 일단 멈추라는 명령(궤적)을 최우선으로 따르라"는 뜻!
2. 왜 정지(Stop)에서 4.0? - 미끄러짐 방지: 가중치가 낮으면 캐릭터가 멈춰야 함에도 불구하고, 걷기 애니메이션이 선택되어 발이 땅에서 미끄러지는 현상이 발생할 수 있다. 가중치를 4.0으로 높이면 시스템이 정지 궤적에 훨씬 더 민감하게 반응하여 즉시 정지용 애니메이션을 선택하게 만든다. 결론적으로, `PSS_Ares_Stop`에서 가중치를 4.0으로 설정한 것은 정지 명령에 대한 정확도를 극대화하여 캐릭터가 미끄러지지 않고 정확한 지점에 멈추게 하려는 의도다.
💡 Schema는 "어떤 정보를 비교할지"를 정의하는 에셋이다. Schema가 없으면 PSD에 아무리 많은 애니메이션을 넣어도 비교 기준이 없는 답안지가 된다.
1-2. Pose Search Database (PSD) — 애니메이션 창고
실제 애니메이션 데이터가 저장되는 곳이다.
걷기, 달리기, 정지, 방향 전환 등 구체적인 모션 데이터가 여기에 들어간다.
PSD에는 Animation Sequence뿐 아니라 Animation Composite(여러 시퀀스를 이어붙인 것)나 Blendspace(파라미터에 따라 블렌딩하는 에셋)도 넣을 수 있다.
⚠️ 여기 넣는 애니메이션은 반드시 루트 모션(Root Motion)이 활성화되어 있어야 한다.
루트 모션이란, 애니메이션 에셋 자체에 "캐릭터가 앞으로 X만큼 전진한다"는 이동 정보가 뼈에 구워져(bake) 있는 것이다.
이게 없으면 캐릭터의 몸은 게임 로직에 의해 앞으로 밀려가는데, 발 애니메이션은 그 이동을 모르기 때문에 제자리에서 미끄러진다. 풋 슬라이딩의 가장 흔한 원인 중 하나다.
PSD에는 Schema를 반드시 할당해야 한다. Schema가 정의한 채널 기준으로 PSD 안의 모든 애니메이션이 인덱싱(색인)되기 때문이다.
1-3. Pose Search Normalization Set (PSN) — 채점 규격표
서로 다른 데이터의 단위를 공평하게 맞춰주는 평준화 도구다.
예를 들어 컴퓨터는 "발 높이 1cm 차이"와 "몸 속도 100cm/s 차이"를 그냥 숫자 1과 100으로만 본다.
규격화 없이 비교하면 '숫자가 큰' 속도에만 맞추려 하거나, 반대로 발 위치에만 집착하게 된다.
PSN은 이 데이터들을 0에서 1 사이의 점수로 평준화(Normalize)시켜서, 서로 다른 종류의 정보를 같은 저울 위에 올려놓는다.
⚠️ 중요한 점: PSN은 선택 사항이다. PSD가 하나뿐이면 모든 포즈가 같은 데이터 분포 안에 있으니 자기끼리 비교해도 공평하다. PSN이 진짜 필요한 순간은 "걷기 PSD"와 "달리기 PSD"처럼 서로 다른 PSD를 동시에 비교해야 할 때다. 창고마다 점수 스케일이 다르니까, 같은 잣대로 통일하는 역할이다.
💡 Schema의 Weight와 PSN의 차이가 뭔가? Weight는 설계자가 “발 위치를 더 중시할지, 궤적을 더 중시할지” 의도적으로 배점을 조절하는 것이다. PSN은 “cm와 cm/s라는 서로 다른 단위를 같은 스케일로 비교할 수 있게” 자동으로 단위를 통일하는 것이다.
1-4. Chooser Table (CHT) — 판사
조건에 따라 “어떤 창고(PSD)를 열 건지” 결정하는 사서다.
지금 캐릭터가 가만히 있는지, 걷고 있는지, 뛰고 있는지에 따라 PSD를 골라준다.
실제 구조는 스프레드시트(엑셀 표)와 같다.
세로 열(Column)에 애니메이션 블루프린트의 변수들(속도, 이동 각도, IsCrouching 같은 Bool 값 등)을 배치하고,
가로 행(Row)에 각 PSD나 애니메이션 에셋을 배치한다.
각 셀에 조건(범위값, true/false 등)을 적으면, 런타임에 현재 캐릭터 상태와 조건이 맞는 행의 에셋이 선택된다.
⚠️ Chooser Table을 쓰려면 Context Data에 어떤 애니메이션 블루프린트의 변수를 읽을지 클래스를 반드시 지정해야 한다. 이 설정이 빠지면 Column에서 변수를 참조할 수 없다.
Chooser Table이 없다면? 걷다가 뛰기, 뛰다가 멈추기, 멈췄다 돌기… 이 수천 개의 Transition을 손으로 잇는 건 불가능하다. Chooser는 이 복잡한 화살표들을 싹 걷어내고, "지금 속도가 빨라? 그럼 그냥 뛰는 거 틀어!"라고 판결해주는 판사다. 덕분에 애니메이션 블루프린트가 깨끗해진다.
1-5. Proxy Asset & Proxy Table — 대역 어댑터
캐릭터가 100명이라도 애니메이션 로직을 100번 짤 필요가 없게 해주는 구조다.
ABP에서는 "Seeker"라는 추상적인 이름표(Proxy Asset)만 부른다.
구체적으로 어떤 Chooser를 쓸지는 안 적혀 있다. 그냥 "오늘의 추천 메뉴"라는 빈 라벨이다.
Motion Matching 노드의 Output 핀에서 끌어 Pose History 노드를 연결한다.
Pose History 노드에서 Trajectory를 바인딩 한다.
Schema가 질문지라면, Pose History는 "시험을 치는 학생의 현재 답안"이다.
매 프레임 캐릭터의 포즈와 궤적을 수집해서 "지금 상태"를 만들어야 PSD의 포즈들과 비교할 수 있다.
이것 없이 Motion Matching 노드만 놓으면, 질문지는 있는데 학생이 안 온 시험이다.
2. 전체 흐름: 여섯 개 에셋은 이렇게 연결된다
전체 흐름을 한 문장으로 압축하면 이렇다.
Pose History가 "지금 캐릭터가 이렇게 생겼고 이렇게 움직이고 있어"라고 수집하면, Schema가 "이 항목들을 비교해"라는 질문지를 만들고, Chooser가 "이 상황이면 이 창고를 열어"라고 판단하고, Motion Matching 노드가 그 창고(PSD) 안에서 PSN의 공평한 잣대로 점수를 매겨 가장 높은 점수의 포즈를 골라 재생한다.
순서
에셋
역할
비유
①
Pose Search Schema
어떤 데이터를 비교할지 정의
시험 문제지
②
Pose Search Database
실제 애니메이션 데이터 저장
답안 보기 창고
③
Normalization Set
서로 다른 PSD 간 점수 단위 통일 (선택)
저울 눈금 통일
④
Chooser Table
상황별로 어떤 PSD를 열지 분기
검사자
⑤
Proxy Asset / Table
캐릭터별로 어떤 Chooser를 쓸지 매핑
대역 이름표
⑥
Pose History
매 프레임 현재 포즈·궤적 수집
학생의 현재 답안
3. 해결 과정: 실전에서 만나는 세 가지 문제와 디버깅
🔍 문제 ① — 풋 슬라이딩
증상: 캐릭터는 앞으로 전진하는데, 발이 제자리에서 미끄러지듯 움직인다. 스케이트를 타는 것처럼 보인다.
원인 체크리스트:
순서
확인 항목
설명
1
루트 모션 활성화 여부
PSD에 넣은 애니메이션의 Root Motion이 꺼져 있으면, 이동 정보가 없어 발이 미끄러진다
2
PSN 설정 여부
여러 PSD를 동시에 비교하는데 PSN이 없으면, 단위 불균형으로 속도 정보를 무시하고 발 위치만 맞추려 든다
3
Schema Weight 균형
Trajectory 채널의 Weight가 너무 낮으면, 시스템이 이동 방향보다 포즈 일치만 우선시한다
해결: 이 세 항목을 순서대로 점검한다. 루트 모션이 가장 기본적인 원인이고, PSN과 Weight는 튜닝의 영역이다. 루트 모션을 먼저 확인하는 이유는, 이것이 빠져 있으면 나머지 두 항목을 아무리 조절해도 근본적으로 해결되지 않기 때문이다.
🔍 문제 ② — 포즈 떨림 (Jitter)
증상: 캐릭터가 전력 질주 중인데, 순간적으로 걷기 애니메이션으로 전환됐다가 다시 달리기로 돌아오는 깜빡임이 반복된다.
원인: Chooser Table의 속도 조건이 걷기/달리기 경계값에 걸쳐 있고, 캐릭터의 속도가 그 경계를 왔다 갔다 하면 매 프레임 다른 PSD가 선택된다. 여기에 Motion Matching 노드의 Continuing Pose Cost Bias(현재 포즈 유지 편향)가 0에 가까우면, 시스템이 현재 포즈를 고수하려는 관성이 없어서 쉽게 다른 포즈로 넘어간다.
해결:
Chooser Table의 속도 조건에 히스테리시스(Hysteresis, 전환 경계에 여유 구간을 두는 것)를 적용한다.
예를 들어 <걷기→달리기> 전환은 속도 600에서, <달리기→걷기> 전환은 속도 400에서 일어나게 하면 경계에서 왔다 갔다 하는 현상이 사라진다.
동시에 PSD의 Continuing Pose Cost Bias를 음수로 설정해서, 현재 재생 중인 포즈를 좀 더 오래 유지하도록 관성을 부여한다.
🔍 문제 ③ — Anim Notify 중복 발생
증상: 걷기 애니메이션에서 발소리가 연속으로 재생된다. 한 발짝에 소리 하나가 나야 하는데, 두세 번씩 겹친다.
원인: 모션 매칭이 비슷한 구간의 포즈를 반복 선택하면서, 같은 프레임 근처의 Anim Notify(애니메이션 특정 시점에 이벤트를 발생시키는 기능)가 중복 트리거된다.
해결:
Motion Matching 노드에서 Should Filter Notifies를 활성화하고, Notify Recency Time Out 값을 설정한다.
이 값은 "같은 Notify가 한 번 발생한 후, 이 시간 동안은 동일 Notify를 무시한다"는 윈도우다.
발소리 간격이 0.3초라면, 0.25초 정도로 설정하면 중복 없이 자연스러운 간격이 유지된다.
4. Rewind Debugger: “왜 이 포즈가 골라졌는지” 들여다보는 법
모션 매칭은 내부에서 매 프레임 점수를 계산한다.
뭔가 어색할 때 가장 먼저 해야 할 일은 "왜 이 포즈가 골라졌지?"를 확인하는 것이다.
이때 쓰는 도구가 Rewind Debugger다.
사전 준비: Pose Search 플러그인과 Animation Insights 플러그인을 둘 다 활성화해야 한다. 툴 - 디버그 - 리와인드 디버거
게임플레이를 녹화한 뒤 타임라인을 앞뒤로 돌리면서, 각 프레임에서 세 가지를 확인할 수 있다.
탭
내용
Active Pose
현재 선택되어 재생 중인 포즈
Continuing Pose
다음에 이어질 포즈
Pose Candidates
탈락한 나머지 후보들
각 후보에는 다음 값들이 히트맵으로 표시된다. 초록색은 유리, 빨간색은 불리, 회색은 완전 무시(예: PoseReselectHistory로 최근에 사용된 포즈)를 의미한다.
Channel Breakdown을 켜면, 전체 Cost가 어떤 채널에서 얼마나 발생했는지 분해해서 보여준다.
"이 포즈가 탈락한 이유가 궤적이 안 맞아서인지, 발 위치가 안 맞아서인지"를 정확히 짚을 수 있다.
이걸 보고 Schema의 채널 Weight를 조절하거나, PSD에 부족한 애니메이션을 추가하거나, Bias 값을 튜닝한다.
값
의미
Cost
종합 비용. 낮을수록 유리하다
Trajectory Total
궤적 일치도. 캐릭터의 이동 경로와 얼마나 맞는가
Pose Total
포즈 일치도. 현재 자세에서 얼마나 자연스럽게 이어지는가
Bias
편향값. Continuing Pose Cost Bias, Looping Cost Bias 등이 반영된다
5. 결과
항목
Before (State Machine)
After (Motion Matching)
애니메이션 블루프린트 복잡도
상태 10개 이상에서 Transition 스파게티
Chooser Table 하나로 조건 분기, 노드 수 대폭 감소
새 동작 추가 비용
기존 모든 상태와의 전이를 수동 연결
PSD에 애니메이션을 드래그 앤 드롭하면 끝
캐릭터 종류 확장
캐릭터별로 로직 복제
Proxy Table만 교체, 로직은 하나로 공유
풋 슬라이딩
전이 타이밍이 안 맞으면 빈번히 발생
루트 모션 + PSN + Weight 튜닝으로 구조적 해결
디버깅
“어떤 전이가 발동했는지” 추적 어려움
Rewind Debugger로 매 프레임 점수표를 열어볼 수 있음
모션 매칭은 애니메이션의 양이 곧 품질이 되는 구조다. 더 많은 애니메이션을 PSD에 넣을수록, 전이 로직을 하나도 추가하지 않아도 캐릭터의 움직임이 자연스러워진다. 이것이 State Machine과의 근본적인 차이다.
요약
모션 매칭은 "질문 → 검색 → 채점 → 선택"의 루프다.
Schema가 “뭘 비교할지” 질문지를 만든다. Pose History가 "지금 캐릭터 상태"를 수집한다. Chooser가 “어떤 창고를 열지” 상황을 판단한다. PSD라는 창고에서 PSN의 공평한 잣대로 점수를 매겨, 가장 높은 점수의 포즈가 재생된다. Proxy는 이 전체 구조를 캐릭터가 바뀌어도 재사용할 수 있게 해주는 어댑터다.
문제가 생기면 Rewind Debugger로 점수표를 연다. 풋 슬라이딩이 나면 루트 모션 → PSN → Schema Weight 순서로 확인한다. 필수 플러그인: Pose Search, Chooser, Animation Insights(디버깅용).