Motion Matching 아키텍처
PoseSearch 플러그인, PoseSearchDatabase, Schema, Cost 함수의 내부 동작을 심층 분석합니다.
Motion Matching 개요
전통적 State Machine 방식과 Motion Matching의 근본적 차이
Motion Matching은 애니메이션 데이터베이스에서 현재 게임 상태에 가장 적합한 포즈를 실시간으로 검색하여 재생하는 기법입니다. State Machine의 수동 전이 규칙 대신, 비용 함수(Cost Function)로 자동으로 최적의 애니메이션을 선택합니다.
전통적 방식 (State Machine)
개발자가 상태와 전이 규칙을 수동으로 정의합니다. 상태 수가 많아지면 복잡성이 기하급수적으로 증가하고, 자연스러운 전이를 위한 블렌딩 튜닝이 필요합니다.
Motion Matching
애니메이션 데이터베이스에 포즈를 등록하면, 런타임에 입력/Trajectory에 가장 가까운 포즈를 자동 선택합니다. 전이가 자연스럽고 확장이 용이합니다.
UE5.4부터 PoseSearch 플러그인이 공식 지원됩니다. 에디터 → Edit → Plugins에서 Pose Search와 Motion Trajectory 플러그인을 활성화해야 합니다. 이 두 플러그인이 Motion Matching 시스템의 핵심입니다.
PoseSearchDatabase와 Schema
애니메이션 데이터베이스의 구조와 피처 스키마 정의
| Schema Channel | 입력 데이터 | 역할 |
|---|---|---|
| Pose | 본 위치, 본 속도 | 현재 캐릭터의 포즈와 DB 포즈 비교 |
| Trajectory | 미래 위치/방향, 과거 위치/방향 | 이동 궤적 매칭으로 반응성 확보 |
| Tag | GameplayTag | 상태 기반 필터링 (전투/비전투 등) |
Schema의 Pose Channel에 너무 많은 본을 추가하면 검색 비용이 증가합니다. 일반적으로 발 2개 + 손 2개 + 골반 정도의 핵심 본만 포함합니다. Trajectory Channel은 미래 3~4 포인트(0.1s, 0.3s, 0.5s, 1.0s)가 표준입니다.
Cost 함수와 검색 알고리즘
최적 포즈를 선택하는 비용 계산과 KD-Tree 검색
Motion Matching의 핵심은 Cost 함수입니다. 현재 게임 상태를 피처 벡터로 변환하고, DB의 모든 포즈 피처 벡터와의 거리(비용)를 계산하여 가장 낮은 비용의 포즈를 선택합니다.
// Motion Matching Cost 계산 (개념)
float CalculateCost(const FPoseSearchQuery& Query, const FPoseSearchPose& DBPose)
{
float Cost = 0.f;
// Pose Cost: 현재 포즈와 DB 포즈의 본 위치/속도 차이
for (int32 i = 0; i < Schema->PoseBones.Num(); ++i)
{
float PosDiff = FVector::DistSquared(
Query.BonePositions[i], DBPose.BonePositions[i]);
Cost += PosDiff * Schema->PoseBones[i].Weight;
}
// Trajectory Cost: 예측 궤적과 DB 궤적의 차이
for (int32 t = 0; t < Schema->TrajectorySamples.Num(); ++t)
{
float TrajDiff = FVector::DistSquared(
Query.TrajectoryPositions[t], DBPose.TrajectoryPositions[t]);
Cost += TrajDiff * Schema->TrajectorySamples[t].Weight;
}
// Continuing Pose Cost: 현재 포즈에서 계속 재생하는 비용
if (DBPose.IsContinuingPose())
{
Cost -= ContinuingPoseBias; // 현재 포즈 유지 선호
}
return Cost;
}
Continuing Pose Bias는 현재 재생 중인 애니메이션을 유지하는 데 보너스를 부여합니다. 이 값이 너무 낮으면 포즈가 너무 자주 전환되어 떨림(jitter)이 발생하고, 너무 높으면 입력 변화에 반응이 느려집니다. 0.1~0.3 범위에서 조정하는 것이 일반적입니다.
AnimBP에서 Motion Matching 사용
AnimGraph의 Motion Matching 노드 설정과 데이터 흐름
// AnimGraph에서 Motion Matching 노드 사용
// 1. Motion Matching 노드 추가
// - Database: PoseSearchDatabase 애셋 참조
// - Trajectory: CharacterMovement에서 자동 생성
// 2. Trajectory Component 설정 (캐릭터 BP에서)
// - UCharacterTrajectoryComponent 추가
// - HistoryCount, PredictionCount 설정
// - SampleRate 설정
// 3. AnimBP EventGraph
void UMotionMatchingAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
// CharacterTrajectoryComponent에서 Trajectory 자동 수집
// Motion Matching 노드가 자동으로 Query 생성 및 DB 검색
}
// 4. 결과: 최적 포즈의 AnimSequence + StartTime이 자동 재생
// 5. Inertialization으로 포즈 전환 블렌딩
Motion Matching을 사용하려면 다음 플러그인을 활성화해야 합니다: Pose Search(핵심 검색 엔진), Motion Trajectory(궤적 예측), Chooser(조건부 DB 선택, 선택적). 프로젝트 설정에서 해당 모듈의 의존성도 추가해야 합니다.
핵심 요약
- Motion Matching은 Cost 함수로 DB에서 최적 포즈를 자동 선택하여, State Machine의 수동 전이를 대체한다.
- PoseSearchDatabase에 애니메이션을 등록하고, Schema로 검색 피처(Pose/Trajectory)를 정의한다.
- Cost = PoseCost + TrajectoryCost + ContinuingCost이며, KD-Tree로 효율적으로 검색한다.
- Continuing Pose Bias로 포즈 전환 빈도를 제어하여 떨림을 방지한다.
- UE5.4+에서 PoseSearch + Motion Trajectory 플러그인을 활성화하여 사용한다.
도전 과제
배운 내용을 직접 실습해보세요
PoseSearch 플러그인을 활성화하고, PoseSearchDatabase를 생성하세요. Schema를 만들어 Bone Position Channel(foot_l, foot_r)과 Trajectory Channel을 추가하고, 이동 애니메이션 시퀀스 3개 이상을 Database에 등록하세요.
AnimBP의 AnimGraph에 Motion Matching 노드를 배치하고, 생성한 Database를 할당하세요. 캐릭터를 이동시키며 자동으로 최적의 포즈가 선택되는지 확인하고, 디버그 드로잉으로 Trajectory와 매칭 결과를 시각화하세요.
Schema의 Channel Weight를 조절하여 발 위치 정확도 vs 궤적 예측 정확도 간의 트레이드오프를 실험하세요. Database Group으로 Locomotion/Combat/Traversal을 분리하고, 상황별로 활성 Database를 전환하는 시스템을 구현하세요.