[UE5] MotionWarping 고찰

윤정민·2026년 3월 2일

Unreal Engine

목록 보기
36/36

1. 개요

요즘 DX11로 애니메이션 기능들을 하나씩 만들어보고있다. 그 중 최근에 RootMotion을 구현했는데, 취준 때 루트모션과 비슷한 기능인 모션워핑을 사용한 경험이 생각났다. 모션 워핑에서는 어떻게 루트 모션을 사용했고, 달성한 결과는 무엇인지 알아보자.

[UE5] Assassin14 - Motion Warping을 사용한 암살1: https://velog.io/@jm450_/UE5-Assassin13-Motion-Warping%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-Assassination

[UE5] Assassin14 - Motion Warping을 사용한 암살2: https://velog.io/@jm450_/UE5-Assassin13-Motion-Warping%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%95%94%EC%82%B42

2. 모션 워핑

Motion Warping은 캐릭터의 루트 모션이 워프 타깃과 일치하도록 애니메이션의 특정 구간을 동적으로 정렬해주는 기능이다.

1) 사용자 인터페이스

애님 몽타주

언제부터 언제까지 워핑할지를 AnimNotifyState(모션 워핑) 로 워핑 구간을 만든다.

  • 애님에서 RootTransform의 변화값이 있는 구간으로 설정해 자연스러운 이동을 설정 가능
  • Notify 프로퍼티
    • Root Motion Modifier 타입
      • Scale: 스케일을 “균등하게” 바꿔서 맞추는 워프
      • Skew Warp: 워핑 구간 끝에 레벨상의 위치/회전이 타깃과 딱 맞도록 루트모션을 워프
    • Warp Target Name: 블루프린트에서 연결할 “타깃 이름”(이름이 반드시 일치해야 함)
    • Warp Translation / Warp Rotation: 이동/회전 워핑을 각각 켤지
    • Ignore ZAxis: 이동 워핑에서 Z를 무시할지
    • Rotation Type
      • Default: 타깃의 회전과 일치
      • Facing: 타깃을 “바라보도록” 회전
    • Warp Rotation Time Multiplier: 회전이 얼마나 빨리 목표 회전에 도달할지(예: 2초 구간에서 0.5면 1초만에 회전 완료)

모션 워핑 컴포넌트

“워프 타깃(목표 위치/회전)이 어디인지”를 이름으로 등록(Add/Update Warp Target) 한다.

AnimNotifyState를 동적으로 추가할 수도 있다.

  • 하지만 WarpTarget도 동적으로 정하는데 구간도 동적으로 넣어줘야할까?
  • 에셋 관리하는 입장에선 불안할 것 같다.
  • 조건에 따라 넣어줘야 된다면 Notify에 Condition을 추가하는 방식으로 확장하는게 더 좋을 것 같다.

주의할 점

해당 기능은 RootMotion을 기반으로 동작하기 때문에 RootMotion을 활성화해줘야한다.

2) 내부 로직 보기

AnimNotifyState_MotionWarping 생성자를 보면 RootMotionModifier_SkewWarp를 사용하는 것을 알 수 있다.

Modifier는 MotionWarpingComponent가 관리한다

MotionWarpingComponent는 CharacterMovmentComponent, Character 등과 연결하기 위한 Adapter를 가지고 있고 해당 인스턴스의 이벤트를 받아 RootMotion을 Modify한다.

  • Adapter를 쓰는 이유는 이동을 담당하는 Component가 여러개 인데, 여러개의 Componenet의 기능을 공통 인터페이스로 사용하기 위함이다
  • 궁금한 사람은 MovementComponent, MoverComponent를 보길 바람
    • Mover가 5.x에 나왔던걸로 기억하는데 두 기능 유지보수 하느라 에픽애들 좀 고생하는 것 같다. 예전엔 이슈도 많았는데 이젠 꼼꼼히 챙기는듯... (사실 안써봐서 잘모름)

ProcessRootMotionPreConvertToWorld 쪽 로직을 타면서 Modify된다.

이런식으로 MovementComp(또는 Mover)에서 RootMotion 데이터를 저장할 때 딜리게이트를 Broadcast하여 다른 시스템에서 PreProcess할 기회를 준다.

모션 워핑에서는 Pre 시점에 연결해서 PreProcess하고 있음

이후에는 RootMotion이 적용되는 것과 같다.

  • RootMotionParams 데이터로 설정되고

    • 최종 RootMotion의 AnimTransform에 Accumulate 된다.
    • Translation은 Velocity로 적용
    • Rotation은 추가해서 MovementUpdate로 적용
  • 궁금한 사람은 void UCharacterMovementComponent::PerformMovement(float DeltaSeconds) 참고

3) 의견

기능적으로는 RootMotion에서 추가되는데, 코드적으로는 많이 분리해서 만들어둔 플러그인 기능이다.
RootMotion의 장점은 AnimSequence에서 잡은 키값을 그대로 Character에 적용함으로서 캐릭터 움직임을 현실적으로 할 수 있다는 장점이 있다.

반면에 모션 워핑의 경우 TargetTransform으로 이동시키는 기능이다보니 Transform계산을 코드 내부에서 하고 있고 이 부분에서 연출적으로 어색한 부분이 생길 수 밖에 없는 구조이다.
따라서 해당 기능을 사용한다면 걸음 같은 RootMotion Transform의 정확도가 중요한 애님보다 특정위치까지 점프해서 도달하는 등 역동적인 애님에 효과적인 기능이 될 수 있다. 전투 시스템에서 많이 사용할 수 있을 것으로 기대된다.

데이터 유지보수 관점에서 보면 모션 워핑 Notify를 사용함에도 RootMotion을 활성화 하지 않았다면 Warning Message를 출력하고 모션 워핑 이름도 휴먼에러가 날 수 있기 때문에 규칙화해서 넣어두면 ComboBox로 선택할 수 있는 구조로 만드는게 좋을 것 같다.
Settings같은 곳에 넣어두고 매핑된 이름만 사용하는 구조다. Settings에서 지울 때는 이미 이름을 사용하고 있는곳을 찾아서 제거할지 다이얼로그 띄워줘 데이터를 클린하게 핸들링 할 수 있어야된다.

결론적으론 제한적으로 사용할 수 밖에 없는 기능이고(자연스러운 연출적 관점) 그대로 사용하기엔 데이터 유지보수에서 어려운 부분이 있기 때문에 사용 전 규칙을 정하는 과정이 필요해보인다.

profile
그냥 하자

0개의 댓글