이번 튜토리얼에서는 Unity에서 Quaternion의 Slerp 함수를 사용하여 지정된 시간 동안 초기 방향에서 최종 방향으로 부드럽게 전환하는 방법을 살펴보겠습니다.
이 튜토리얼의 동영상 버전은 현재 이 언어로 제공되지 않습니다.
영상 자막 텍스트
안녕하세요 여러분!
이번 튜토리얼에서는 Unity에서 Quaternion의 Slerp 함수를 사용하여 지정된 시간 동안 초기 방향에서 최종 방향으로 부드럽게 전환하는 방법을 살펴보겠습니다.
이 튜토리얼에서는 여러분이 이미 Time.deltaTime에 익숙하다고 가정합니다. Time.deltaTime에 대해서는 이전에 게시한 비디오 튜토리얼에서 다루었습니다. 아직 Time.deltaTime에 익숙하지 않다면, 이 영상을 진행하기 전에 해당 튜토리얼을 먼저 시청하는 것을 강력히 권장합니다.
이 튜토리얼은 Unity 2022 버전으로 녹화되었습니다. 하지만 Slerp 함수는 여러 버전에서 제공되어 왔으며, 앞으로의 릴리스에서도 계속 제공될 가능성이 높습니다.
방향 A에서 방향 B로의 회전, 더 일반적으로는 지정된 시간 동안 값 A에서 값 B로의 보간은 여러 방식으로 수행될 수 있습니다. 값은 선형 진행을 따를 수도 있고, 구면 진행을 따를 수도 있으며, 그 외에도 사용자 정의된 다양한 방식이 존재합니다.
영상에서는 보간의 예시로 큐브를 수직 축을 기준으로 90도 회전시키는 장면을 보여줍니다. 단순한 예제이지만, 개념을 효과적으로 전달해 줍니다.
회전 시간은 [0, 1] 범위로 매핑됩니다. 0 시점에서는 초기 값을 가지며, 1 시점에서는 최종 값을 가집니다. 이 범위 사이의 중간 값들은 선택한 보간 방식에 따라 결정되는 값에 해당합니다.
예제에서 모든 큐브는 5초 동안 90도 회전합니다. 그러나 애니메이션의 4초 시점, 즉 [0, 1] 범위에서 0.8에 해당하는 순간에는 각 큐브의 보간 방식이 다르기 때문에 서로 다른 방향을 가지게 됩니다.

회전을 수행할 때는, 이 예제와 같은 경우 선형 보간보다 구면 보간이 더 적합합니다. 그 결과가 더 자연스럽고 보기 좋기 때문입니다.
Unity에서 구면 보간은 Slerp 함수로 계산합니다. 여기서 S는 Spherical을 의미합니다. 반면 선형 보간은 Lerp 함수로 계산하며, L은 Linear를 의미합니다.
앞서 언급했듯이, Slerp는 Quaternion 클래스의 일부입니다. Quaternion은 3D 공간에서 방향과 회전을 표현하기 위한 수학적 개념입니다. 이 튜토리얼에서는 Quaternion의 수학적 이론은 설명하지 않겠습니다. 단지 방향을 표현하는 데 사용된다는 점만 말씀드리고, Slerp 함수의 사용 방법에 집중하겠습니다.
Slerp는 방향 A에서 방향 B로 전환할 때 사용합니다.
이 함수는 세 개의 매개변수를 받습니다. 초기 방향, 목표 방향, 그리고 [0, 1] 범위에서 우리가 알고 싶은 시점 값입니다. 즉, 보간을 평가할 시점입니다.
Slerp는 지정된 시점에서의 방향을 나타내는 Quaternion을 반환합니다.
예를 들어 다음과 같이 작성하면:
Quaternion.Slerp(A, B, 0.2);
이는 A 방향에서 B 방향으로 회전하는 과정 중 0.2 시점, 즉 전체 구간의 1/5 지점에서의 방향을 Unity에 요청하는 것입니다. 0.2는 1의 1/5이기 때문입니다.
애니메이션을 1초 동안 지속하고 싶다면 Update에서 Time.deltaTime을 사용할 수 있습니다. 0에서 1까지의 보간 범위는 Time.deltaTime을 사용하여 정확히 1초짜리 애니메이션으로 변환할 수 있습니다. 이는 Time.deltaTime 튜토리얼에서 설명한 내용입니다.
임의의 초 단위 시간 동안 애니메이션을 수행하려면 Time.deltaTime을 해당 시간으로 나누어야 합니다. 이에 대해서는 곧 실제 예제를 통해 자세히 살펴보겠습니다.
대부분의 경우 초기 방향은 객체의 방향, 즉 transform.rotation입니다. 회전은 Quaternion으로 표현되기 때문입니다.
예를 들어 초기 방향에 특정 각도를 더해 목표 방향을 계산하는 과정은 다소 까다로울 수 있습니다. 하지만 이 부분도 곧 실제 예제에서 다루겠습니다. 이제 실제 예제로 넘어가겠습니다.
영상에서는 3D 모델이 있는 씬을 보여줍니다.

구체적으로 이 모델은 네 개의 요소로 구성되어 있습니다. 문틀, 두 개의 문짝, 그리고 손잡이입니다.
원래 모델에서는 손잡이가 달린 문짝의 Pivot이 경첩 위치에 있어 올바르게 회전하도록 되어 있었지만, 어떤 이유로 Unity가 이를 약간 앞으로 이동시켰습니다.
이 문제를 해결하기 위해 문틀의 자식으로 Empty 오브젝트를 추가하고, 이를 애니메이션을 적용할 문짝의 경첩 위치에 배치합니다.
그 다음, 해당 문짝을 이 Empty의 자식으로 설정합니다.
이 새로운 Empty 오브젝트에 회전 스크립트를 추가합니다. 예를 들어 "doorOpening"이라는 이름으로 생성합니다.
게임 시작 시 문짝이 자동으로 열리도록 설정하겠습니다. 이때 LOCAL 수직 축, 이 경우 Z 축을 기준으로 90도 회전합니다.

초기 방향은 transform.rotation입니다.
코드를 더 유연하게 만들기 위해 "startRotation"이라는 Quaternion 변수를 선언하고, Start에서 다음과 같이 초기화합니다:
startRotation = transform.rotation;
최종 방향을 나타내는 Quaternion은 초기 방향에 로컬 Z 축 기준 90도 회전을 더한 값이어야 합니다. 그렇다면 이 회전을 Quaternion으로 어떻게 정의할까요?
Quaternion.Euler 함수를 사용합니다. 이 함수는 XYZ 세 축에 대한 회전 각도를 도 단위로 받습니다.
따라서 수행할 회전을 다음과 같이 정의합니다:
Quaternion rotationToBePerformed;
Start에서 다음과 같이 초기화합니다:
rotationToBePerformed = Quaternion.Euler(0f, 0f, 90f);
이 Quaternion은 수행할 회전을 나타내지만, 아직 최종 방향은 아닙니다.
최종 방향은 초기 방향에 이 회전을 더해서 계산해야 합니다.
여기서 중요한 점이 있습니다. 수행할 회전을 초기 방향에 더하려면 두 Quaternion을 곱해야 합니다.
따라서 최종 Quaternion을 다음과 같이 정의합니다:
Quaternion targetRotation;
Start에서 다음과 같이 초기화합니다:
targetRotation = startRotation * rotationToBePerformed;
이제 Update 함수로 이동합니다. Update는 매 프레임마다 호출됩니다. 다음과 같이 작성합니다:
transform.rotation = Quaternion.Slerp(startRotation, targetRotation
하지만 여기서 멈춥니다. 아직 보간 평가 시점을 나타내는 변수를 정의하지 않았기 때문입니다.
이 변수는 0에서 시작해야 하므로 Update 밖에서 다음과 같이 선언하고 초기화합니다:
float evaluation = 0f;
그 다음, 이를 Quaternion.Slerp 함수의 세 번째 매개변수로 전달합니다.
또한 매 프레임마다 값이 증가해야 하므로 Update에서 다음과 같이 작성합니다:
evaluation += Time.deltaTime;

최종 평가 값은 1.0이므로, 매 프레임 evaluation에 Time.deltaTime을 더하면 애니메이션은 정확히 1초 동안 진행됩니다.
이제 게임을 실행하면 Empty 오브젝트는 수직 축을 기준으로 회전하지만, 문짝은 열리지 않는 것을 볼 수 있습니다.
그 이유는 해당 오브젝트를 처음에 Static으로 설정했기 때문입니다. 원래는 애니메이션할 예정이 아니었고 Unity가 전역 조명을 계산하도록 하기 위함이었습니다. 이제 애니메이션을 적용하려면 Inspector에서 Static 체크박스를 해제하고, 자식 오브젝트인 손잡이에도 적용을 확인합니다.
다시 게임을 실행하면, 이번에는 문이 1초 동안 부드럽게 열리는 것을 볼 수 있습니다.

이제 애니메이션 시간을 다르게 설정하려면 어떻게 해야 할까요?
방법은 매우 간단합니다. 매 프레임 evaluation에 더해지는 값이 Time.deltaTime을 애니메이션 지속 시간으로 나눈 값이 되도록 하면 됩니다.
Time.deltaTime만 사용하면 애니메이션은 1초 동안 진행됩니다. 예를 들어 5초 동안 진행하려면 매 프레임 evaluation에 Time.deltaTime의 1/5을 더해야 합니다.
다음과 같이 변수를 정의합니다:
float openingDuration = 5f;
그리고 Update에서 evaluation 증가 코드를 다음과 같이 수정합니다:
evaluation += (Time.deltaTime / openingDuration);

스크립트를 저장하고 Unity 에디터로 돌아가 게임을 실행하면, 이번에는 애니메이션이 5초 동안 진행됩니다.
이 실제 예제를 통해 Quaternion.Slerp를 사용하여 두 방향 사이를 지정된 시간 동안 부드럽게 보간하는 방법을 확인할 수 있습니다.
이 스크립트를 다양한 상황이나 오브젝트에 적용하여 Unity 프로젝트에서 부드러운 회전과 애니메이션을 구현할 수 있습니다.
정리하자면, 이번 튜토리얼에서는 다음을 다루었습니다. 수행할 회전을 Quaternion으로 표현하는 방법, 시작 Quaternion에 수행할 회전을 곱하여 목표 Quaternion을 얻는 방법, 그리고 Time.deltaTime을 활용하여 프레임 속도와 관계없이 일정한 속도로, 가변적인 지속 시간 동안 Slerp를 사용해 구면 보간 회전을 수행하는 방법입니다.
이 튜토리얼이 도움이 되었기를 바랍니다. 곧 다시 만나요!