[ 쿼터니언 ]
쿼터니언은 3차원 회전을 표현할 때 사용되고, 유니티에서는 오브젝트의 회전을 처리한다. 유니티 인스펙터 창의 회전은 3차원 벡터로 표현되고, 이를 오일러 각이라고 한다.
오일러 각은 피치(Pitch)는 x축, 요(Yaw)는 y축, 롤(Roll)은 z축을 기준으로 회전한다. 이때 하나의 축에서 과한 회전이 일어나 다른 회전축과 평행하게 됐을 때 짐벌락(Gimbal Lock)이 발생한다. 두 개의 회전축이 겹쳐지면서 기존의 축이 방향을 잃어버리는 것이다. 쿼터니언을 이용하면 이러한 짐벌락 문제를 피할 수 있다.
쿼터니언은 수학적으로 (x, y, z, w) 형태의 4가지 숫자로 구성되어 있고, 이를 직접 조정할 수는 없다. 대신 Quaternion.Euler, Quaternion.LookRotation, Quaternion.Slerp와 같은 유니티 내장 함수를 사용해서 회전 작업을 처리할 수 있다.
Quaternion.Euler
Quaternion rotation = Quaternion.Euler(50, 35, 0);
transform.rotation = rotation;
Quaternion.Euler는 오일러 각을 쿼터니언으로 변환한다. 객체를 x축으로 50도, y축으로 35도 회전시키고 싶다면, Quaternion.Euler(50, 35, 0)를 쿼터니언으로 변환해서 할당한다.
Quaternion.LookRotation
Quaternion lookRotation = Quaternion.LookRotation(direction);
transform.rotation = lookRotation;
Quaternion.LookRotation은 객체의 앞과 위의 벡터를 매개변수로 받아서, 객체가 바라보는 방향을 나타낸다. 이를 통해 특정 방향을 바라보도록 회전을 준다. 위 방향을 나타내는 매개변수는 생략될 수 있으며, 디폴트 값은 y축을 의미한다.
Quaternion.Slerp
Quaternion resultRotation = Quaternion.Slerp(startRotation, endRotation, 0.3f);
Quaternion.Slerp은 구면 선형 보간법을 이용해서 쿼터니언과 다른 쿼터니언 사이의 내분점을 구해 지정한 비율만큼만 회전한다. 위 코드는 시작 회전 지점에서 끝 회전 지점까지 30%만 회전한다.
또한 선형 보간은 2차원 공간에서 단순히 두 점 사이의 직선거리를 따라 이동하지만, 구면 선형 보간은 3차원 공간에서 구면의 최단 거리를 따라 곡선으로 회전하기 때문에 움직이는 애니메이션을 부드럽게 할 수 있다.
[ 아크탄젠트 ]
삼각함수
삼각함수는 각도를 가지고 비율을 알아내는 함수이다. 그중 탄젠트는 밑변과 높이의 비이고, 즉 가로와 세로를 의미해서 좌표를 표현할 수 있다.
삼각함수에 아크(arc)가 붙으면, 삼각함수의 역함수인 역삼각함수가 된다. 따라서 비율을 가지고 각도를 알 수 있게 된다. 마찬가지로 아크탄젠트는 탄젠트의 역함수이고, 가로와 세로의 비에 따른 각도를 계산할 수 있다.
기존의 아크탄젠트는 180도 범위 내에서만 구할 수 있었는데, x와 y의 부호를 통해 360도 범위 내에서 구분이 가능해졌고 이를 Atan2라고 부른다.
Math.Atan2(y, x)
Math.Atan2(y, x) 함수는 원점에서 좌표 평면 위의 점 (x, y)까지의 벡터와 x축 사이의 각도를 계산한다. 각도의 범위는 -180도에서 180도인 [-π, π]이기 때문에, 360도를 모두 나타낼 수 있다. 그리고 x와 y의 부호를 통해 모든 사분면에 대한 정확한 각도를 계산한다. 예를 들어 (1, 1)과 (-1, -1)은 같은 y/x 값을 가지지만, 위치와 각도는 다르다. Atan2 함수를 사용하면 (1, 1)은 45도(π/4 라디안)로 나타내고, (-1, -1)은 225도(5π/4 라디안)로 나타낼 수 있다. 이를 통해 플레이어가 마우스가 가리키는 방향으로 오브젝트를 정확히 회전시킬 수 있다.
위에서는 이해하기 쉽도록 일반적으로 사용되는 각도의 단위인 디그리로 설명했지만, Atan2 함수의 결과값은 라디안 단위로 나타난다. 그러나 실제 유니티에서는 오일러 각을 사용하기 때문에, 라디안 단위에서 디그리 단위로 변환시킬 필요가 있다. 따라서 라디안 단위를 디그리 단위로 표현하기 위해 각도(디그리) × (π/180)의 계산을 해야하는데, 이를 Mathf.Rad2Deg 함수를 이용해서 변환할 수 있다.
Math.Atan2(y, x)와 Mathf.Atan2(y, x)은 동일한 기능을 하지만, 정밀도, 메모리, 속도에 약간의 차이가 있다.
Math.Atan2(y, x) | Mathf.Atan2(y, x) | |
사용처 | .NET 프레임워크 | Unity 스크립트 |
타입 | double | float |
메모리 | 64비트 | 32비트 |
Math.Atan2(y, x)은 .NET 프레임워크의 일부로 C# 언어에서 사용된다. double 타입으로 계산하고 64비트 메모리를 사용해서 정밀도는 높지만, 많은 메모리를 사용하고 속도가 느리다.
Mathf.Atan2(y, x)은 Unity 스크립트에서 사용된다. float 타입으로 계산하고 32비트 메모리를 사용해서 정밀도는 낮지만, 적은 메모리를 사용하고 속도가 빨라서 성능이 중요할 때 사용한다.
[ 회고 ]
갑자기 수학 개념이 나와서 1차 당황. 아무리 들어도 이해가 안 돼서 2차 당황. 정말 나를 곤혹스럽게 한 챕터였다. 아무리 강의를 반복해서 들어도 알 수 없어서 정말 많은 자료를 찾아봤다. 그렇게 여러 정보가 조합되면서 이해가 된 순간에는 너무 깊게 파고들었나 하는 생각이 들었다. 하지만 이 정도가 아니면 캐릭터가 어떤 원리로 움직이는지도 모른 채 코딩을 했을 것이다. 게임의 기본인 캐릭터의 회전에 대한 내용이니까 확실히 짚고 넘어가는 것이 좋다고 생각했다. 저녁 시간은 이거 하나 때문에 많은 시간을 뺏긴 것 같아서, 내일은 나머지 강의를 착실히 듣는 것을 목표로 해야겠다.
'Coding > Unity' 카테고리의 다른 글
[내일배움캠프 20일차 TIL] 카메라 추적, 보간 적용 (0) | 2024.05.13 |
---|---|
[내일배움캠프 19일차 TIL] New Input System, 이벤트 처리 (0) | 2024.05.10 |
[내일배움캠프 17일차 TIL] 게임 엔진, PPU, 계층 구조, Input.GetAxis, 직렬화 (0) | 2024.05.08 |
[내일배움캠프 5일차 TIL] 복습, 체력바, isKinematic, isTrigger, 레벨 (1) | 2024.04.19 |
[내일배움캠프 4일차 TIL] 복습, 마우스 포인터 추적, 점수 저장 (1) | 2024.04.18 |