TECHARTNOMAD | MAZELINE.TECH

TECH.ART.FLOW.IO

[번역] UE4 UE5 스켈레탈 애니메이션 고급 로코모션 시스템 ALS 회전

jplee 2026. 7. 28. 15:16

저자: DarkFlameMaster

안녕하세요. 또 한 분기 한 번, 신작 시즌이 돌아왔습니다. 본 방송에서는 고급 로코모션 시스템 신춘 특별편, 회전! 을 전해 드립니다.

하하, 농담은 이쯤 하고 본론으로. 최근 원고를 쓰다 ALS 회전 부분까지 왔는데, 이 내용은 이미 손바닥 보듯 알아서 금방 끝낼 줄 알았다. 막상 펜을 잡으니 민망하게도 좀 까먹고 있었다. 그래서 ALS 프로젝트를 열어 복습하려다, 뜻밖에도 ALS 회전 부분이 꽤 번잡하다는 걸 발견했다——맞아, 어렵기보다는 번잡하다(그리고 귀찮다).

그런데 온라인에 ALS 회전을 자세히 정리한 글은 상당히 적다. ALS 시리즈 튜토리얼을 했던 블로그를 뒤져 봐도 거의 안 다루더라……

그럼 내가 그 일을 해 보겠다(글 하나 물타기 해 보겠다).

시청 전 안내, 이 글은 이전의 제자리 회전 글과 같이 보면 더 좋다. 나는 새 글에서 예전에 쓴 내용을 다시 써서 분량을 불리는 걸 별로 안 좋아해서, 이번 글과 이전 글의 겹침은 적다. 특히 초심자에게는 이전 글을 먼저 보는 편이 낫다.

 

[번역] UE4 UE5 골격 애니메이션 고급 로코모션 시스템: 제자리 회전

저자: DarkFlameMaster최근 언리얼 엔진의 골격 애니메이션 관련 지식을 공부하고 있다. 가르치면서 배우자는 생각으로, 여기서 애니메이션 관련 글을 좀 써서 방금 배운 것을 바로 팔아먹어보려 한

techartnomad.tistory.com

 

1.머리말

게임에서 캐릭터 회전은 크게 두 가지다. 하나는 캐릭터 회전을 이동 방향으로 맞추는 것;(ALS 실행 중 숫자 키 “1”을 누르면 이 모드로 바뀐다. “2”를 누르면 돌아간다.)이 모드에서는 캐릭터가 멈춰 있을 때 보통 회전이 일어나지 않는다.

다른 하나는 캐릭터 회전을 카메라(혹은 컨트롤러, 마우스)가 바라보는 방향으로 맞추는 것이다. 이 모드에서 캐릭터는 보통 여덟 방향 이동(Strafe)을 쓴다. 이 모드에서는 캐릭터가 멈춰 있어도, 플레이어가 카메라 방향을 다른 각도로 돌리면 “제자리 회전(Turn in place)”으로 자기 회전을 카메라에 맞춰야 한다.

ALS에서는 첫 번째를 Velocity Direction(줄여서 속도 모드)이라 부르고, 두 번째를 Looking Direction(줄여서 주시 모드)이라 부른다. 사실 세 번째로 Aiming(조준) 모드도 있지만, 핵심 사고는 주시 모드와 비슷하고 구현만 상대적으로 번잡해서 이번 글에서는 잠시 건너뛴다.

비교적 전형적인 예가 FS사 소울 시리즈다. 주인공이 적을 락온하면 Looking Direction을 쓰고, 이때 카메라 시점은 적을 정면으로 바라보며 캐릭터 회전도 적을 향한다. 락온이 없으면 Velocity Direction을 쓴다.

(다만 FS사는 최적화를 좀 해 두었다. 예를 들어 적을 락온한 채 뒤로 갈 때 walk면 여전히 주시 모드고, run(달리기)이면 캐릭터가 화면을 향해 서서 속도 모드를 쓴다).

이 두 회전 모드를 최소한의 비용으로 구현하는 방법은 2년 전 글에서 말한 적 있다. UE 기본 3인칭 템플릿은 속도 모드를 쓰고, “Orient Rotation to Movement”를 켜면 주시 모드가 된다.

 

이제 시선을 ALS 구현 정리로 옮기자.

2.ALS의 구현

속도 모드는 비교적 단순하니, 이번 글의 중심은 주시 모드에 둔다. 필자는 두 가지 질문을 실마리 삼아, 그 답을 통해 ALS 전체 로직 설계 사고를 끌어내고, “무엇인가” 너머의 “왜인가”까지 답해 보려 한다.

【질문】

1.캐릭터 회전을 제어할 때, 코드 주도여야 할까, 애니메이션 주도여야 할까?

2.캐릭터가 제자리에서 돌 때, 자유 각도로 완전히 컨트롤러 방향을 향해야 할까; 아니면 고정 각도만 돌려 컨트롤러 방향에 가깝게 한 뒤, 머리(혹은 상반신 척추 체인 전체)를 컨트롤러 방향으로 보게 해야 할까?

2.1 ALS 흐름 설계 사고에 답해 보기

ALS가 택한 것은 코드 주도 + 자유 각도 방안이다. Lyra의 회전은 고정 각도다(일종의 게으른 트릭에 가깝다).

코드 주도를 쓰면, 애니메이션 속 루트 모션 데이터를 무브먼트 컴포넌트에 자동으로 넣어 캐릭터를 돌릴 수 없고, 손으로 캐릭터를 돌려야 한다. 즉 한 번의 제자리 회전은 애니메이션 그래프의 “캐릭터가 도는 애니메이션을 연기하는 것”과 캐릭터 블루프린트의 “캐릭터 모델이 실제로 회전하는 것”이 맞물려 루트 모션 연출을 흉내 낸다.

바꿔 말하면, 실제 제자리 회전 연출은 두 부분으로 이뤄진다. 하나는 “양발이 도는 동작을 하는” 연출, 다른 하나는 “캐릭터 모델이 그에 맞게 실제로 회전하는” 연출. 루트 모션 효과를 흉내 내려면 이 두 연출을 잘 동기화해야 하고, 동시에 진행돼야 한다. 그래서 애니메이션 블루프린트와 캐릭터 블루프린트 통신을 잘 잡아야 한다.

애니메이션 블루프린트 재사용성을 높이려면, 애니 BP와 캐릭터 BP는 최대한 디커플링하는 편이 좋다. 서로 상대가 누군지 모르는 상태가 이상적이다. 어떤 통신 방식이 그걸 만족할까? 에, 맞아, 애니메이션 커브다.

캐릭터 블루프린트에서는 현재 스켈레탈 메시의 커브 값을 읽을 수 있고, 애니 BP가 누구인지는 몰라도 된다. 애니 BP 쪽에서도 커브 값을 직접 읽고 쓸 뿐, 캐릭터 BP가 누구인지는 전혀 건드리지 않는다.

통신 방식을 애니메이션 커브로 정했다면, 통신 과정의 시작과 끝도 또렷해진다. 캐릭터 BP는 애니메이션 커브를 수정할 수 없고 애니 BP는 할 수 있으니, 애니 BP가 통신의 시작점이 되어 원본 애니메이션 시퀀스의 커브 데이터를 처리·덮어쓴 뒤, 캐릭터 BP가 읽어 실제 회전을 수행한다.

애니메이션 커브로 통신하면 다른 이점도 있다.

1.모델 회전과 애니메이션 재생을 맞추는 즉시성 문제를 잘 해결한다. 애니메이션 커브는 시퀀스에 베이크되어 있어서, 애니메이션이 재생되기 시작하면 커브 값이 캐릭터 스켈레톤에 덮어씌워지고, 캐릭터 BP의 Tick 갱신에서 그 변화를 바로 읽는다.

2.코드 주도에서도 가능한 한 루트 모션 회전 효과를 흉내 내고 싶다. 그게 애니메이션에 가장 잘 맞으니까. 그런데 회전 애니메이션의 각속도는 보통 등속이 아니라서, 모델이 등속으로 돌면 효과가 조금 떨어진다. Animation Modifier로 애니메이션 루트 모션 데이터를 뽑아 커브에 베이크하면, 커브 값이 가리키는 회전량으로 비등속 회전 과정 전체를 거의 완벽하게 흉내 낼 수 있다.

3.애니메이션 블루프린트 쪽 구체 구현

통신은 애니 BP가 시작점이니, 관련 데이터 갱신도 애니 BP에서 시작한다. Update Graph의 다음 함수들(아래 그림)이 관련 진입점이다.

그중 Update Rotation Values는 주시 모드에서 이동 중 회전량을 갱신한다(여덟 방향 이동에도 쓰인다). 아래 첫 줄 Rotate가 들어간 두 함수는 조준 모드용이고, 둘째 줄 Turn이 들어간 두 함수는 주시 모드 제자리 회전용이다. 셋째 줄은 FootLock 아래 발 보정 동작이라 회전과는 큰 관련이 없다.

하나씩 소개하자.

3.1 여덟 방향 이동과 Update Rotation Values 함수

예전에 지금보다 실력이 훨씬 약할 때 쓴 여덟 방향 이동 글에 잘못된 인식이 하나 있었다. 지난 2년 동안 많은 독자를 오해하게 했을 수 있어, 여기서 사과드린다.

 

[번역] UE4 UE5 골격 애니메이션 고급 로코모션 시스템: 8방향 이동

저자: DarkFlameMaster최근 언리얼 엔진의 골격 애니메이션 관련 지식을 공부하고 있다. 가르치면서 배우자는 생각으로, 여기서 애니메이션 관련 글을 좀 써서 방금 배운 것을 바로 팔아먹어보려 한

techartnomad.tistory.com

 

그 글에서 나는 ALS 여덟 방향 이동이 Move-F 같은 노드에서 멀티 핀 블렌드로 나온다고, 속도 블렌드량이 블렌드 파라미터라고 했다. 하지만 실제로는 그것만이 아니다. 더 중요한 것은 속도 끼인각으로 FYaw, BYaw 같은 값을 계산해 YawOffset 커브에 넘기고, 캐릭터 BP가 그 커브 값을 읽어 캐릭터 Actor를 회전시키는 쪽이다.

Update Rotation Values 함수에서 캐릭터 회전량 계산

Update Rotation Values 함수에서 캐릭터 회전량 계산

애니메이션 그래프에서 그 회전량을 애니메이션 커브에 입력

애니메이션 그래프에서 그 회전량을 애니메이션 커브에 입력

캐릭터 블루프린트에서 애니메이션 커브의 회전량을 꺼내 실제 회전 수행

캐릭터 블루프린트에서 애니메이션 커브의 회전량을 꺼내 실제 회전 수행

멀티 핀 블렌드의 역할은 캐릭터가 빠르게 원을 그리며 걸을 때 미끄러짐을 막는 쪽에 더 가깝고, 좌전·우전 같은 이동 방향 제작에서 가장 중요한 역할은 아니다.

3.2Turn In Place Check

CanTurnInplace 함수가 검사하는 내용은 단순하다. 3인칭 시점 & 주시 모드 & Transition 허용. 제자리 회전은 Third Person 시점과 주시 모드에서만 의미가 있으니까.

바로 Turn In Place Check 함수를 보자. 이 함수가 하는 일은 크게 몇 가지다.

1.캐릭터 회전과 컨트롤러 회전의 끼인각(Yaw)이 45도를 넘는지 검사

2.플레이어가 시점을 돌리는 속도가 너무 빠르지 않은지 검사. 이건 아주 중요하다. 이 양을 검사하지 않으면, 180도, 심지어 360도 회전을 할 때도 캐릭터가 90도 회전 동작을 쓸 가능성이 크다. 이 설계의 본뜻은, 마우스 감도가 높은 플레이어가 시점을 빨리 돌릴 때 원하는 캐릭터 방향은 분명히 시점 회전 속도가 느려진 뒤의 방향이지, 고속 회전 도중의 어떤 위치가 아니라는 점이다.

정상 상황

시점 회전 속도를 검사하지 않았을 때

3.이번에 돌릴 각도량에 따라 회전 딜레이를 정한다(돌릴 각이 클수록 딜레이는 짧다). 그리고 변수 하나를 타이머로 두고, 딜레이를 채우면 Turn In Place 함수를 트리거한다. 온라인 글 중에는 회전 딜레이가 별로 쓸모없어 보여 빼도 표현이 그대로라고 한 글도 있다. 사실 역할은 2번의 시점 회전 속도 검사와 같다.

독자는 Turn In Place 함수 앞 Branch를 바로 True로 바꿔 보고, 회전 딜레이가 없을 때의 차이를 느껴 보면 된다. 회전 속도만 잘 조절하면(변수를 통제하려면 시점 회전 속도를 비교적 낮게 둬야 한다), 똑같이 360도를 돌릴 때 원래 나오지 말았어야 할 회전 애니메이션이 또 트리거되는 걸 볼 수 있다.(빨리 돌리면 안 나오는데, 시점 회전 속도 제한이 이미 이번 회전을 막아 버리기 때문이다)

3.이번에 돌릴 각도량에 따라 회전 딜레이를 정한다(돌릴 각이 클수록 딜레이는 짧다). 그리고 변수 하나를 타이머로 두고, 딜레이를 채우면 Turn In Place 함수를 트리거한다. 온라인 글 중에는 회전 딜레이가 별로 쓸모없어 보여 빼도 표현이 그대로라고 한 글도 있다. 사실 역할은 2번의 시점 회전 속도 검사와 같다.

독자는 Turn In Place 함수 앞 Branch를 바로 True로 바꿔 보고, 회전 딜레이가 없을 때의 차이를 느껴 보면 된다. 회전 속도만 잘 조절하면(변수를 통제하려면 시점 회전 속도를 비교적 낮게 둬야 한다), 똑같이 360도를 돌릴 때 원래 나오지 말았어야 할 회전 애니메이션이 또 트리거되는 걸 볼 수 있다.(빨리 돌리면 안 나오는데, 시점 회전 속도 제한이 이미 이번 회전을 막아 버리기 때문이다)

3.3 Turn In Place 함수와 그다음

Turn In Place 함수 자체는 특별히 말할 게 많지 않다. 이번에 쓸 회전 애니메이션을 정하고, 몽타주 형태로 재생한 뒤, 미리 잡아 둔 재생 속도 같은 데이터로 Rotation Scale 변수 값을 세팅한다.

ALS에 익숙하지 않은 독자는 여기서 좀 헷갈릴 수 있다. 그다음은? 데이터는 어디로 가나?

사실 BaseLayer의 Locomotion States 상태 머신 Not Moving 상태로 온다. 이 제자리 회전 애니메이션들은 몽타주로 재생될 때 쓰는 슬롯이 전부 Turn/Rotate다.

Not Moving 상태 안에도 그 슬롯이 보인다. 제자리 회전 애니메이션은 바로 여기서 불려 나온다. 동시에 방금 수정한 Rotation Scale도 여기서 Rotation Amount 커브를 스케일하는 데 쓰인다(“Modify Curve” 노드를 클릭하면 오른쪽 디테일 패널에서 적용 모드가 스케일인 걸 볼 수 있다).

4.캐릭터 블루프린트 쪽

캐릭터 BP 쪽은 Tick Graph에서 매 프레임 커브 값을 검사해 회전을 시작한다. 같이 보자.

4.1 Update Grounded Rotation

Tick Graph에서 Update Grounded Rotation 함수가 대부분의 회전 작업을 하는 곳이다. Aim Yaw Rate 같은 것들은 Set Essential Values 등 함수에 흩어져 있으니, 독자가 직접 참조 찾기로 보면 되고, 여기서는 길게 반복하지 않는다.

이 함수는 회전 모드, 걸음걸이 등을 많이 스위칭해서 겉보기엔 복잡해 보인다.

내용을 간단히 요약하면 이렇다.

이동 상태에서 세 회전 모드 처리는 대체로 비슷하다. 전부 Smooth Character Rotation 함수를 호출하고, 이 함수는 Actor Rotation을 파라미터로 넣은 목표 회전 쪽으로 두 단계 보간해 다가가게 하는 유틸이다. 세 처리의 가장 큰 차이는 입력 파라미터, 즉 목표 회전과 보간 속도뿐이다.

1.속도 모드(Velocity Direction) 또는 전력 질주 걸음걸이(Sprint)에서는 속도를 향한다.

2.조준 모드(Aiming)에서는 컨트롤 회전을 향한다.

3.주시 모드(Looking Direction)에서는 컨트롤러를 향하는 기반 위에, 여덟 방향 이동 시 캐릭터를 돌리는 증분을 더한다(걸음걸이가 walk 또는 run일 때. Sprint면 속도 모드 처리로 간다). 여기서 2.2.1절 여덟 방향 이동 때 넘긴 커브 값 YawOffset을 읽는 걸 볼 수 있다.

비이동 상태(Not Moving)에서 1인칭 시점이거나 조준 모드면, Limit Rotation으로 캐릭터와 컨트롤러 회전 끼인각을 대략 ±100도 안으로 꽤 강하게 제한한다. 이때는 앞에서 말한 회전 속도 제한이나 회전 딜레이를 거의 보지 않는다. 이런 상황에서는 캐릭터 회전 반응이 빠르고 민감한 쪽이 더 중요하다.

마지막이 제자리 회전 부분이다. 여기서는 매 Tick마다 RotationAmount 커브 값을 읽고, 0보다 클 때만(제자리 회전 애니메이션이 재생되기 시작하면, 그 시퀀스에 RotationAmount 커브가 있어서 값이 0보다 커진다) 프레임레이트 보정을 한 뒤 캐릭터 회전 갱신에 쓴다.

RotationAmount 회전량은 여기서 프레임레이트 보정을 받을 뿐 아니라, 앞에서 Rotation Scale로 스케일될 때도 이미 한 번 보정된다(재생 속도와 실제 회전량 보정). 자세한 내용은 이전 글 3.2절을 참고하면 된다.

 

후기

앞 이야기에 이어, 원고가 제자리 회전까지 왔는데 나는 좀 까먹고 있었다. 그래서 온라인에서 참고할 글을 찾아보기로 했다. 금방, 탁, 검색 결과가 나왔다. 좋은 소식은 ALS 회전을 다룬 글을 단숨에 3편 찾았다는 것, 나쁜 소식은 전부 합쳐도 그 3편뿐이고, 그중 한 편은 심지어 2년 전 내가 쓴 글이었다는 것.

【위 이미지 대화 내용 · 한국어 번역】
선배 여동생(学姐小迷妹): 빙의 좀 해 봐.
선배 여동생(学姐小迷妹): 과거의 자신!
못 참겠음(受不鸟了): 못 참겠음.

내 글을 다시 훑어보니, 그 글은 핵심 디테일 처리와 사고의 개요만 강조했을 뿐이었다. 전체 흐름 처리는 온전히 다루지 않았다. 애니 BP의 Tick에서 애니메이션 그래프의 Modify Curve로 뛰고, 다시 캐릭터 BP의 Tick으로 뛰는 ALS 회전 통신은 꽤 은밀해서, ALS에 익숙하지 않은 초보가 전체 흐름을 이어 붙이려면 조금 어렵다.

이 글 내용은 기초라고 하면 꽤 기초다. 최근 몇 년 다들 ALS를 아주 익숙하게 다루니까. 기초가 아니라고 하면 또 기초가 아니다. ALS를 막 접한 초보는 이 부분이 흐릿한데 참고 자료를 찾기 어렵기 때문이다.

그래서 이 글이 태어났다. 여기서 독자 여러분께 미리 새해 복 많이 받으세요!

UE 스켈레탈 애니메이션 교류방: 916274600

이 글이 왜 이렇게 빨리 나왔는지 궁금해하는 분도 있을 것이다. 주된 이유는 요 며칠 집 인터넷이 터져서 발로란트를 못 쳐서…… 할 일이 없으니 원고랑 글만 썼다 = = 금단 증상이다, 발로란트 치고 싶다. 칼라비츄도 요 며칠 오픈했는데, 나는 구경만 하는 신세……

이 글이 왜 이렇게 빨리 나왔는지 궁금해하는 분도 있을 것이다. 주된 이유는 요 며칠 집 인터넷이 터져서 발로란트를 못 쳐서…… 할 일이 없으니 원고랑 글만 썼다 = = 금단 증상이다, 발로란트 치고 싶다. 칼라비츄도 요 며칠 오픈했는데, 나는 구경만 하는 신세……

가짜일지라도

용자의 이름에 부끄럽지 않다면