저자: DarkFlameMaster
최근 언리얼 엔진의 골격 애니메이션 관련 지식을 공부하고 있다. 가르치면서 배우자는 생각으로, 여기서 애니메이션 관련 글을 좀 써서 방금 배운 것을 바로 팔아먹어보려 한다.
제자리 회전이 쓸모를 발휘하는 경우는 주로 이렇다. 캐릭터가 계속 “네가 지정한 방향”을 바라보게 하고 싶고, 동시에 캐릭터가 그냥 Actor 자체가 제자리에서 휙 도는 것이 아니라 제대로 몸을 돌리는 애니메이션을 갖기를 원할 때다. 예를 들어 세키로에서 적을 록온한 상태라고 하자. 너는 제자리에 서 있고, 적이 네 주변을 빙빙 돈다. 이때 비교적 이상적인 표현은 당연히 네 캐릭터가 제자리에서 잔걸음을 밟으며 적을 따라 함께 도는 것이다. 이것이 바로 제자리 회전이 쓰이는 곳이다.
먼저 최종 완성 효과 이미지를 하나 올려 독자를 붙잡아보겠다. (급하게 이 글을 닫지 말고) 어떻게 만드는지 궁금하다면, 같이 아래로 따라와 보면 된다.

설령 이 글이 네 흥미를 끌지 못하더라도, 떠나기 전에 좋아요 하나만 눌러주고 가주면 좋겠다. 부탁이다 ≥﹏≤
내가 쓴 기술 블로그는 예전에 많은 사람에게 도움이 된 적이 있다. 이제는 나도 독자 여러분께 한번 도움을 부탁드리고 싶다! (작은 좋아요 버튼 한 번만 누르면 된다!)
ALS의 제자리 회전 관련 지식을 더 깊이 배우고 싶은 독자는 다음 글을 읽어도 좋다.
1. 기본 지식
오늘의 주제가 회전인 이상, 캐릭터 블루프린트에서 제공하는 몇 가지 기본 회전 옵션을 반드시 이야기해야 한다. UE를 막 배우기 시작한 사람들(나 자신을 가리킨다) 중에는 처음에 이 옵션들에 대해 의문을 품었던 사람이 꽤 많을 것이라고 믿는다. 이 기회에 이 몇 가지 옵션을 한꺼번에 놓고 이야기해보자. (잠시 후 2절에서도 그중 일부를 써야 하기 때문이다.) 이미 이 내용이 머릿속에 훤히 들어 있는 독자라면 그냥 건너뛰어도 된다.
캐릭터 무브먼트 컴포넌트

“컨트롤러가 요구하는 회전 사용” 옵션의 효과는 캐릭터의 회전이 컨트롤러가 위치한 회전값으로 부드럽게 전이되도록 하는 것이다. 전이 속도는 “회전 속도”에서 조정한다. 즉 마우스를 회전하면 캐릭터가 약간의 지연을 두고 마우스 회전을 따라잡는다.
“회전을 이동 방향으로 향하게 하기” 옵션의 효과는 캐릭터의 회전 방향이 가속도에 의해 결정되도록 하는 것이다. 즉 일반적인 3인칭 게임에서 흔히 보이는 방식이다. 마우스를 돌려도 사람은 돌지 않지만, WASD 방향키를 눌러 이동하면 캐릭터가 새로운 이동 방향을 향해 돌아간다.
Pawn 디테일 패널
그다음은 Pawn(또는 Character) 디테일 패널 안의 설정이다. 여기 있는 “컨트롤러 회전 P/Y/R 사용”은 위에서 설명한 “컨트롤러가 요구하는 회전 사용”과 비교적 비슷하다. 만약 “컨트롤러 회전 Yaw 사용”만 체크한다면, 효과는 “컨트롤러가 요구하는 회전 사용”과 거의 같다. 다만 회전 지연 효과가 빠져 있을 뿐이다. 나머지 두 개, “컨트롤러 회전 Pitch 사용”, “컨트롤러 회전 Roll 사용”은 인간형 캐릭터를 제어할 때 일반적으로 체크하지 않으므로 여기서는 설명하지 않는다.

카메라와 스프링 암 디테일 패널
카메라에는 “Pawn 컨트롤 회전 사용”이라는 설정이 있다. 이름만 들으면 의미가 마치 “자신의 회전을 Pawn과 같게 만들고, Pawn의 회전값을 자신에게 대입한다”처럼 들린다.

사실은 그렇지 않다. 왜냐하면 그렇게 설명하면 모순되는 부분이 하나 생기기 때문이다.

Pawn(또는 Character)의 디테일 패널에서는 이 세 옵션을 조정할 수 있다. 컨트롤러의 회전을 사용해 자기 자신을 회전시킬지 여부가 세 개의 성분으로 나뉘어 있다. 만약 이 세 옵션을 모두 False로 두면, 이론적으로 Pawn의 회전은 더 이상 컨트롤러의 제어를 받지 않아야 한다. 그러면 우리가 마우스를 회전해도 캐릭터를 돌릴 수 없어야 한다.
맞다. 만약 의존 관계가 우리가 위에서 말한 것처럼 카메라 → Pawn → 컨트롤러라면, Pawn이 돌지 못하니 카메라도 돌 수 없어야 한다. 하지만 독자가 실제 게임에서 이렇게 설정해보면, 실제 결과는 일반적인 3인칭 게임과 같다. 마우스를 움직이면 카메라는 돌고, 캐릭터는 돌지 않는다.
분명히 이때 카메라의 회전은 Pawn이 아니라 컨트롤러에 의존한다. 소스 코드에서도 이 점은 쉽게 검증할 수 있다.
cpp">//CameraComponent.h //Pawn 컨트롤 회전을 사용하는 경우(이 소스 코드를 보고 나면 사실 이 변수 이름이 그다지 적절하지 않고 사람을 오해하게 만든다는 것을 알 수 있다) if (bUsePawnControlRotation)
{
const APawn* OwningPawn = Cast<APawn>(GetOwner());
const AController* OwningController = OwningPawn ? OwningPawn->GetController() : nullptr;
//유효성 판단 if (OwningController && OwningController->IsLocalPlayerController())
{
//자신을 소유한 Pawn 객체의 GetViewRotation 함수를 호출한다 const FRotator PawnViewRotation = OwningPawn->GetViewRotation();
if (!PawnViewRotation.Equals(GetComponentRotation()))
{
SetWorldRotation(PawnViewRotation);
}
}
}
//Pawn.cppFRotator APawn::GetViewRotation() const
{
if (Controller != nullptr)
{
//자신을 제어하는 컨트롤러로 전달해, 컨트롤러의 GetControlRotation 함수를 호출한다. //이것이 바로 이때 카메라가 실제로 컨트롤러의 회전에 의존한다는 증거다. return Controller->GetControlRotation();
}
2. 간단하지만 실행 불가능한 구현 방안
아이구, 1절을 다 읽었으니 아마 여러분은 어떻게 하면 되는지 이미 마음속으로 다 알고 있을 것이다. 그러니 여기서 지면을 낭비하지 말고 바로 다음 절로 넘어가자.
……
……
……
농담, 농담이다. 그래도 언급은 해야 한다.
여기서 “컨트롤러가 요구하는 회전 사용”을 체크하고, “회전을 이동 방향으로 향하게 하기”의 체크를 해제한다. 그리고 캐릭터 디테일 패널의 Pawn 섹션에서 “컨트롤러 회전 Yaw 사용”을 해제한다.

이렇게 하면 캐릭터가 마우스 회전에 따라 회전하게 만들 수 있다. 회전 지연 효과를 더 뚜렷하게 만들고 싶다면 회전 속도 안의 Z값을 조금 낮추면 된다. Z값이 200일 때의 효과는 다음과 같다.

물론 이렇게 하는 문제는 매우 명확하다. 표현되는 효과는 캐릭터 모델 전체가 제자리에서 한 바퀴 돈다는 것이다. 마치 회전판 위에 올려진 피규어가 회전판을 따라 도는 것처럼 보인다. 어떤 애니메이션도 없고, 당연히 신뢰감 같은 것은 말할 것도 없다. 그러므로 이제부터는 신뢰할 수 있고 그럴듯한 제자리 회전 애니메이션을 만들기 시작해야 한다.
3. ALSV4의 제자리 회전
3.1 통속적이고 이해하기 쉬운 사고 정리
위에서 말했듯, 캐릭터가 회전할 때 아무 애니메이션도 없으면 좀 안 된다. 자연스러운 생각은 카메라 시점과 캐릭터 방향 사이의 각도가 일정 각도(예를 들어 45도)를 넘으면 회전 애니메이션을 재생하는 것이다.
매번 회전해야 하는 각도는 45~180도 사이의 어떤 값도 될 수 있다. 그렇다고 해서 서로 다른 회전 각도 크기의 애니메이션을 잔뜩 만드는 것은 명백히 매우 비경제적이다. (게임 안의 캐릭터가 많다면, 회전 애니메이션 애셋만으로도 상당한 공간을 차지할 것이다.)
따라서 회전 애니메이션을 “작은 회전”과 “큰 회전”, “좌회전”과 “우회전”으로 나눌 수 있다. 이렇게 하면 총 4개의 애니메이션 애셋만 있으면 된다.
작은 회전은 45~130도 범위의 회전을 담당하고, 큰 회전은 130~180도 회전을 담당하게 한다.
이때 어떤 독자는 이렇게 물을 것이다. “어? 방금 각도가 다른 회전을 표현하려고 애니메이션 애셋을 잔뜩 쓰는 것은 너무 비경제적이라 어렵다고 했잖아. 그런데 왜 이제는 이 4개 애니메이션만으로 된다는 거지? 46도 회전과 129도 회전을 같은 애니메이션으로 표현하고, 만약 그 애니메이션이 90도만 회전한다면, 80도나 100도 바깥쪽 각도에서는 육안으로도 꽤 뚜렷한 오차가 생기지 않나?”
맞다. 볼 수 있듯, 애니메이션을 많이 만들면 너무 비경제적이고, 애니메이션을 적게 만들면 표현이 지나치게 부정확해지는 문제를 마주하게 된다. 그렇다면 관점을 바꿔보자. 애니메이션으로 캐릭터의 회전을 제어하지 않는다면, 캐릭터의 회전을 제어할 수 있는 다른 방법은 무엇이 있을까?
……
답은 이미 입 밖으로 나오려 하고 있다. 바로 코드 로직을 사용해 제어하는 것이다. SetWorldRotation, AddActorWorldRotation 같은 함수로 캐릭터 회전을 제어하고, 애니메이션은 캐릭터가 발을 두어 번 움직여 “발을 옮겨 회전하는 중”처럼 보이게 만들면 된다.

또한 애니메이션의 현실감을 높이기 위해, 캐릭터가 제자리 회전할 때(이동 중 회전은 별도 이야기다) 마우스를 돌리자마자 캐릭터가 즉시 따라 도는 것은 그다지 적절하지 않다. 약간의 지연이 있는 편이 좋다. 우리가 마우스를 돌린 뒤, 캐릭터는 잠시 멈춰 있다가 그제야 따라오기 시작해야 한다. 이 글에서는 이것을 “회전 지연 시작 시간”이라고 부르겠다.
주의해야 할 것은 이것을 회전 래그와 구분해야 한다는 점이다. 달리기를 예로 들어보자. 회전 래그가 없다는 것은 출발점에서 종점으로 곧바로 순간이동한 것과 같다. 중간에 “달려가는” 과정이 없는 것이다. 중간에 달려가는 이 과정이 바로 “회전 래그”다. 반면 회전 지연 시작 시간이 없다는 것은 출발점에서 심판이 “준비”라고 말하자마자 바로 뛰쳐나간 것과 같다. 회전 지연 시작 시간이 있다는 것은 “출발점에서 잠깐 머무는 것”이다.
3.2 간명하고 이해하기 쉬운 구체 구현
먼저 우리는 당연히 캐릭터의 현재 방향과 컨트롤러 사이의 각도를 얻어야 한다. 이 각도가 임계값보다 커야만 제자리 회전을 실행할 수 있다. 또한 제자리 회전인 이상, 이때 캐릭터는 움직이고 있으면 안 된다.
(PS: 아래 블루프린트 코드는 ALSV4를 써본 적 없는 독자도 막힘 없이 읽을 수 있도록, 가능한 한 가장 통속적이고 이해하기 쉬운 방식으로 보여주었다.)

만약 속도가 150보다 크거나, 캐릭터가 움직이고 있을 뿐 아니라 플레이어에게도 이동 입력이 있다면(예를 들어 방향키를 눌렀다면) 조건에서 제외한다.
속도 크기만 직접 판단하지 않고, 이런 약간 복잡한 판단 로직을 사용한 것은, 캐릭터가 컨베이어 벨트에 실려 움직이지만 캐릭터 본인은 움직이지 않는 상황 같은 것을 고려했기 때문이다. 우리는 이런 경우 캐릭터도 정지 상태로 간주되기를 원한다.

위 조건을 만족하면, 이제 제자리 회전을 준비할 수 있다. 이때 우리가 해야 할 일은 이번 회전 지연 시작 시간이 얼마면 적절한지 계산하고, 시간이 흐르기를 조용히 기다리다가, 회전 지연 시작 시간 요구를 만족하면 실제로 애니메이션을 재생하고 캐릭터를 회전시키는 것이다.
(DeltaTimeX는 “Get World Delta Seconds” 노드가 반환하는 값, 즉 두 프레임 사이에 흐른 초 단위 시간이다.)

위에서 우리는 회전을 허용하는 최소 임계값을 45도로 가정했다. 또한 각도가 클수록 더 빨리 회전을 시작하기를 원한다. 이런 상황에서 너무 많은 회전 지연 시작 시간은 캐릭터 반응이 느려 보이게 만들고, 회전 각도가 작을 때에는 약간의 지연이 있는 편이 더 자연스럽다. 따라서 이번 회전 지연 시작 시간을 계산하는 방법은 45~180도의 목표 회전량을 0.75~0초의 회전 지연 시작 시간으로 매핑하는 것이다.
마지막으로 회전 애니메이션을 재생하기 전에, 이번에 사용할 회전 애니메이션이 무엇인지 결정해야 한다.
(TurnAngle이 이번 목표 회전량이다.)

우리는 회전값이 45~130도 사이면 90도 회전(작은 회전 애니메이션)을 사용하고, 130~180도 사이면 180도 회전(큰 회전 애니메이션)을 사용하도록 설정한다. 또 양수/음수로 좌우를 판단하고, 보행 상태로 앉아서 도는지 서서 도는지를 판단한다. 총 8가지 경우가 있으며, ALSV4는 미리 설정해둔 8개의 애니메이션 리소스 중 상황에 맞는 하나를 이번에 재생할 애니메이션 애셋으로 선택한다.
애니메이션 재생을 시작한 뒤에는 곧바로 한 가지를 생각해야 한다. 애니메이션 재생 시간은 2초이고, 이제 우리는 캐릭터의 몸이 이 2초 안에 시작점에서 종점까지 회전하도록 해야 한다.
자연스럽게 보이게 하려면, 캐릭터의 회전 속도가 이 2초 안에서 균일한 선형 회전이 되어서는 안 된다. 시작점과 끝점 양쪽은 느리고, 중간은 빨라야 한다. 분명히 커브는 괜찮은 선택이다. 우리는 커브 값이 곧바로 이 프레임에서 캐릭터의 회전량(회전 각도)을 대표하도록 만들 수 있다.
사용하는 커브는 애니메이션 시퀀스 안에서 편집해도 되고, 별도의 커브 애셋을 만들어도 된다. (왜 ALSV4가 후자를 쓰지 않았는지는 잘 모르겠다.)【1】

예를 들어 이 오른쪽 90도 회전 커브에는 총 60개의 키프레임이 있고, 그것들의 총합은 정확히 90이 된다.
물론 우리는 실제로 90도를 도는 것이 아니다. 여기서 90도 회전은 단지 “작은 회전 애니메이션”의 별칭일 뿐이다. 우리는 이 커브 값을 실제 회전량에 따라 보정해야 한다. 따라서 첫 번째 보정은 커브 값 / 90(또는 /180)을 한 뒤 실제 회전량을 곱하는 것이다.

두 번째 보정은 재생 속도를 곱하는 것이다. (그림의 RotationScale은 뒤에서 커브 값을 스케일링하는 데 사용된다.)
여기서 먼저 UE 애니메이션 시퀀스 재생 로직을 언급해야 한다. 애니메이션의 실제 재생 시간이 프레임레이트 변동의 영향을 받지 않도록 하기 위해, 애니메이션의 시간 단위는 프레임이 아니라 초다.
만약 프레임을 시간 단위로 삼는다면, 게임에서 1프레임이 지나면 애니메이션도 1프레임 재생된다. 애니메이션이 60프레임으로 만들어졌다고 가정하면, 60FPS에서는 애니메이션이 1초 만에 끝나지만, 30FPS에서는 2초가 걸린다. 이것은 분명히 안 된다.
애니메이션이 초를 시간 단위로 삼는다면, 게임에서 1프레임이 지날 때 애니메이션은 DeltaTime(두 프레임 사이의 시간 차)만큼 진행된다. 이렇게 하면 프레임레이트가 높을 때 DeltaTime은 낮아지고, 애니메이션의 한 번 진행량은 적지만 1초 안의 진행 횟수는 많아진다. 프레임레이트가 낮을 때는 DeltaTime이 커지고, 애니메이션의 한 번 진행량은 많지만 1초 안의 진행 횟수는 적어진다.
애니메이션을 2배속으로 재생하면, 애니메이션은 이 1프레임에서 DeltaTime * 2만큼 진행된다. 이것이 바로 배속 재생 애니메이션의 원리다.
우리는 캐릭터의 회전도 매 프레임 한 번씩 보정한다. (어쨌든 시작점에서 종점까지 회전하는 이 과정을 표현해야 하기 때문이다.) 이는 곧 우리가 커브 값을 가져오는 것도 1프레임에 1번이라는 뜻이다.
조금 극단적인 상황을 상상해보자. 지금 게임 프레임레이트가 30FPS라고 가정한다. 애니메이션을 정상 속도로 재생하면, 게임이 1프레임 진행될 때 애니메이션도 정확히 1프레임 진행된다. 만약 애니메이션을 30배속으로 재생하면, 매번 진행되는 시간 길이가 바로 30배가 된다. 시작 시의 1프레임까지 계산해도, 게임은 총 3프레임 정도밖에 실행되지 않았는데 이 애니메이션은 이미 끝나버린다.
아래 그림과 같다. (ALSV4는 이 커브를 RotationAmount, 즉 회전량이라고 이름 붙였다.)

게임이 3프레임밖에 실행되지 않았다는 것은, 우리가 커브 값을 3번밖에 가져오지 않았고, 점도 3개만 샘플링했다는 뜻이다. 분명히 이 3개 점을 더해도 90에는 한참 못 미친다. (원래는 60개 점을 더해야 90이 되니까.) 그럼 어떻게 해야 할까? 비교적 거친 시뮬레이션 방법은 이 3개 점의 값을 각각 30배 하는 것이다.
어떤 독자는 곧바로 소리칠 것이다. “어? 이 오차 너무 심한 거 아니야? 이 세 프레임 값을 더한 뒤 30을 곱해도, 딱 봐도 90이 안 될 것 같은데!”
뭐, 이건 결국 30배속으로 애니메이션을 재생하는 극단적인 상황이다. 실제 적용에서는 3배속 재생도 거의 보기 어려울 수 있다. 따라서 이 시뮬레이션 효과로 생기는 오차는 사실 받아들일 수 있는 범위 안에 있다. 재생 속도가 2배를 넘지 않을 때에는 일반적으로 플레이어가 알아차리기 어렵다.【2】
세 번째 보정은 게임 자체의 프레임레이트 변동이 가져오는 영향을 보정하는 것이다.

앞의 배속 재생 원리와 비슷하게, 게임 프레임레이트가 높아지면 각 프레임에서 애니메이션의 진행 거리가 짧아진다. 프레임레이트가 너무 높아서 게임 프레임 델타(DeltaTime)가 애니메이션 프레임 델타보다 작아지면, 게임은 몇 프레임이나 진행됐는데 애니메이션은 아직 다음 프레임으로 넘어가지 않은 상황이 생긴다.
예를 들어 현재 게임이 60FPS이고, ALSV4 애니메이션의 기본 프레임레이트가 30FPS라고 하자. 즉 게임이 2프레임 진행되어야 애니메이션이 1프레임 진행된다. 그런데 우리는 애니메이션 커브 값을 가져와 캐릭터를 회전시키는 작업을 매 프레임 실행하므로, 애니메이션 커브 안의 같은 키프레임 값이 두 번 읽히게 된다. 캐릭터 회전량도 그 때문에 정확히 2배가 된다.
이 현상을 피하기 위해 우리는 커브 값 ÷ 게임 프레임레이트 × 기본 애니메이션 프레임레이트를 해야 한다. 위 그림에서는 커브 값 × 게임 프레임 델타 × 30으로 표현되어 있는데, 의미는 같다.
이렇게 하면 회전량이 2배가 될 수 있는 60FPS에서, 우리가 커브 값 × 30 ÷ 60, 즉 × 0.5를 해주기 때문에, 2배가 된 커브 값이 다시 보정된다. 마찬가지로, 이 보정은 재생 속도에 대한 보정과 마찬가지로 완전히 정확한 것은 아니다.【3】
본문에 넣으면 글의 상세함과 흐름에 영향을 줄 수 있는 작은 여담:
【1】사용하는 커브는 애니메이션 시퀀스 안에서 편집해도 되고, 별도의 커브 애셋을 만들어도 된다. (왜 ALSV4가 후자를 쓰지 않았는지는 잘 모르겠다.)
필자 개인적으로는 후자가 전자에 비해 가진 유일한 단점은 커브에 입력하는 시간값을 조금 신경 써야 한다는 점이라고 생각한다.
애니메이션은 배속 재생될 수 있으므로, 이때 실제 소요 시간이 꼭 2초라고 할 수 없다. 예를 들어 2배속 재생에서는 애니메이션 각 프레임의 진행 시간이 2 * DeltaTime이 된다. 그에 맞춰 우리가 커브에 입력하는 진행 시간도 2를 곱해야 한다. (그렇지 않으면 애니메이션은 이미 끝났는데 우리는 아직 애니메이션이 절반쯤 재생될 때 써야 하는 커브 값을 가져오고 있는 상황이 된다.) 반면 애니메이션 시퀀스 안의 커브는 그 자체가 애니메이션 안에 내장되어 있으므로, 커브 값을 얻는 위치가 애니메이션 재생 진행도에 직접 의존한다. 따라서 입력 시간 문제를 신경 쓸 필요가 없다.
후자를 사용하는 장점은 여러 회전 애니메이션이 같은 커브를 재사용할 수 있다는 것이다. ALSV4는 좌우 회전, 90도 회전과 180도 회전을 구분하기 위해 총 4개의 회전 커브를 만들었다. 그런데 이 4개는 사실 대동소이하다. 90도와 180도 회전 커브의 차이는 각 키프레임 샘플링 포인트의 값이 2배 차이 나는 것뿐이고, 좌회전과 우회전은 값의 양수/음수 차이일 뿐이다. 그렇다면 커브 애셋 하나를 만들고, 위에서 이미 작성한 90 or 180, left or right 구분 로직에 따라 커브에 대응하는 곱셈 처리를 해주면 된다. 굳이 4개의 애니메이션 시퀀스마다 커브를 한 번씩 편집할 필요는 없다.
【2】애니메이션 감속 재생으로 생기는 커브 값 누적 오차는 가속 재생보다 작다. 이는 가속이 빨라질수록 샘플링 간격이 점점 커지고, 커브가 어떤 구간에서 급격히 변화한다면 샘플이 희소해져 눈에 띄는 오차가 생기기 때문이다. 감속 재생에서는 애니메이션 진행 시간 간격이 애니메이션 안의 두 프레임 사이 거리보다 작아져, 같은 키프레임이 여러 번 읽힌다. 그래서 모든 키프레임이 적어도 읽히게 보장되며, 커브 변화가 급격하더라도 점을 놓쳐 지나가는 일로 과도한 오차가 생기지는 않는다.
【3】게임 프레임레이트가 높아지는 결과는 애니메이션 감속 재생과 비슷하다. 따라서 게임 프레임레이트가 30보다 높을 때 애니메이션 재생에 생기는 오차는 매우 작다. 반대로 게임 프레임레이트가 30보다 낮을 때에는 애니메이션 배속 재생과 마찬가지로 비교적 큰 오차가 생긴다. (말이 나온 김에 말하자면, 게임 프레임레이트가 30프레임보다 낮아지면 이미 뚜렷한 끊김이 생기므로, 플레이어는 애니메이션의 신뢰감 하락까지 그다지 신경 쓰지 않을 것이다. ALSV4 애니메이션의 기본 프레임레이트를 30으로 설정한 것은 꽤 영리하다고 할 수 있다.)
3.3 블렌드 시간이 커브에 가져올 수 있는 영향
3.2절의 커브 설명을 보고 나면, 게임 프레임레이트 변동과 애니메이션 배속 재생이 오차를 일으키는 이유가 모두 애니메이션 커브의 샘플링 횟수가 변하기 때문이라는 것을 알 수 있다.
하지만 블렌드 시간도 사실 다른 방식으로 커브 샘플링에 오차를 가져온다. 블렌드 시간이 길수록 오차는 커진다.

제자리 회전 애니메이션에서는 RotationAmount 커브가 활성화되어 있지만, 제자리 대기 상태에서는 이 커브를 사용하지 않는다. (즉 값이 0이다.) 제자리 회전과 제자리 대기를 블렌드할 때, RotationAmount 값도 함께 블렌드된다.
다시 말해, 만약 블렌드 인 시간을 0.4초로 설정했다면, 커브상에서는 상당히 긴 구간의 커브 값이 제자리 대기 상태의 “0값”과 가중 평균 블렌드를 하면서 영향을 받게 된다. (값이 낮아진다.) 블렌드 인/아웃 시간이 길수록 커브 값이 영향을 받는 구간도 많아지고, 마지막에 표현되는 회전 효과도 더 부정확해진다.

또 하나 언급할 만한 점은, 애니메이션 배속 재생은 애니메이션의 총 재생 시간을 줄인다는 것이다. (가속 재생을 말한다.) 그러면 원래 0.4초였던 블렌드 시간이 전체 길이의 20%를 차지했더라도, 2배속 재생에서는 40%를 차지하는 것으로 변한다. (애니메이션 배속 재생은 블렌드 시간 길이까지 함께 스케일링하지 않는다.)
그러면 블렌드의 영향을 받는 커브 값의 “피해 구역”도 크게 늘어난다.

즉 배속 재생은 블렌드 시간이 가져오는 오차를 대폭 확대한다.
블렌드 시간을 높이면 물론 애니메이션 사이의 전환을 더 자연스럽고 매끄럽게 만들 수 있다. 하지만 커브 값이 블렌드에 의해 훼손되어, 애니메이션 신뢰감 요구가 높은 상황(예를 들어 이 글의 제자리 회전처럼, 오차가 10도를 넘으면 매우 뚜렷해지는 경우)에서는 더 큰 오차를 만들 수도 있다. 따라서 맹목적으로 블렌드 시간을 늘리는 것은 현명한 선택이 아니다.
맺음말(필자의 관례적인 잡담을 뜻함)
지난번 ALSV4 8방향 이동 편 업데이트로부터 이미 1개월 18일이 지났다. 매달 부지런하고 성실하게 붓을 놓지 않고 글을 올리던 나로서는, 최근 한 달 넘게 게으름을 피우며 글을 올리지 않았는데도, 知乎의 팔로우와 조회수가 나를 놀라게 할 속도로 오르고 있어서 정말 부끄러워 몸 둘 바를 모르겠다 = =. 그래서 모레 이번 학기의 첫 기말고사를 맞이해야 하는 상황임에도, 필자는 야근하듯 이 글을 먼저 업데이트하고 나서 복습하러 가기로 했다.
다음 글은 ALSV4의 발 IK를 업데이트할 계획이다. 결국 애니메이션을 깊이 공부해본 적 없는 사람이라도, 8방향 이동과 IK는 들어봤거나(혹은 인터넷 튜토리얼을 따라 간단히 구현해보려 시도했거나) 했을 것이다. 5월 20일부터 6월 중순까지는 시험 주간이라, 다음 글 업데이트는 빨라도 6월은 되어야 나올 것 같다.
이번 절의 제목은 “제자리 회전”이지 “회전”이 아니다…… 왜냐하면 ALSV4 안의 회전을 한 번에 다 설명하려고 하면 이 글의 내용량이 너무 방대하고 뒤섞이기 때문이다. 이동 과정 중의 회전 같은 것은 많은 움직임 디테일을 포함한다. 예를 들어 자세(무게중심) 기울기, 카메라 변화, 보행 상태 제한과 전이 등등……
그리고 같은 창작자인 몇몇 선배들에게 감사드리고 싶다. @聆枫LingFeng, @小木子. 내가 며칠 전 블렌드 시간 때문에 생기는 여러 오차 현상으로 혼란스러워하고 있을 때, 그룹에서 인내심 있게 귀중한 조언을 제공해주었다. (특히 小木子 선배가 제공한 디버깅 조언 덕분에 정말 많은 우회로를 피할 수 있었다.)

마지막은 좋아요 구걸 시간이다! 여기까지 봤다면, 설령 이 글이 비루하고 얕다고 느껴지더라도, 필자가 글 쓰느라 고생했다는 점을 생각해 좋아요 하나만 누르고 가주면 좋겠다. 부탁이다 ≥﹏≤
내가 쓴 기술 블로그는 예전에 많은 사람에게 도움이 된 적이 있다. 이제는 나도 여러분이 나에게 손을 내밀어주기를 간절히 부탁하고 싶다. (작은 좋아요 버튼 한 번만 누르면 된다!)
PS: 덧붙여 여기서 필자가 막 만든 UE 골격 애니메이션 교류방을 살짝 광고한다. 916274600 각위 대佬들의 매서운 지적을 환영합니다.

'TECH.ART.FLOW.IO' 카테고리의 다른 글
| [번역] UE4 UE5 골격 애니메이션 고급 로코모션 시스템: 점프 (0) | 2026.07.23 |
|---|---|
| [번역] UE4 UE5 골격 애니메이션 고급 로코모션 시스템: 8방향 이동 (0) | 2026.07.22 |
| [INDEX] ANIMATION SYSTEM (0) | 2026.07.21 |
| [번역] UE4/UE5 골격 애니메이션 고급 로코모션 시스템: 걷기/달리기 블렌드 기초 (0) | 2026.07.21 |
| [번역] UE4 UE5 골격 애니메이션 고급 로코모션 시스템 (ALSV4) (1) | 2026.07.21 |