유니티에서의 회전과 방향
어떻게 회전을 나타낼까?
유니티는 오브젝트의 회전과 방향을 타나 낼 때 오일러 각과 쿼터니언 각 두 가지를 사용한다.
오일러 각은 우리가 흔히 사용하는 (x, y ,z) 형태이다. 반면 쿼터니언은 사원수를 사용하여 (w, x, y, z)를 사용한다.
오일러 각만 사용하면 될텐데 복잡하게 왜 쿼터니언까지 사용하는 것일까.
짐벌락 문제
오일러 각은 3차원을 3개의 축으로 회전을 나타낸다. 문제는 회전을 하다가 두 개의 축이 평행할 수(겹치게 될 수) 있다는 것이다. 이렇게 될 경우 2차원 회전으로만 가능하게 되고 더 이상 3차원 회전으로 돌아올 수 없게 된다. 이러한 현상을 짐벌락이라고 하며 3D 엔진에서는 치명적인 문제이다.
이를 방지하기 위해 쿼터니언(사원수)을 사용한다. 쿼터니언은 짐벌락 문제가 발생하지 않으며 모든 방향을 나타낼 수 있다. 하지만 쿼터니언은 우리에게 익숙하지 않기 때문에 유니티는 오일러 각도를 쿼터니언으로 바꿀 수 있는 여러 장치를 마련해 두었다.
Quaternion.Euler | (함수) 오일러 각에서 쿼터니언으로 변경 |
quaternion.eulerAngles | (프로퍼티) 쿼터니언에서 오일러 각으로 변경 |
//오일러각을 쿼터니언으로 변환
transform.rotation = Quaternion.Euler(Vector3.forward);
//쿼터니언을 오일러 각으로 변환
Vector3 transformRotationVector = transform.rotation.eulerAngles;
회전과 방향 관련 스크립팅
Quaternion 전역 함수
Quaternion.LookRotation(Vector3 forward, Vector3 upwards = Vector3.up)
- 특정 벡터 방향을 쿼터니언 값으로 리턴
- 특정 오브젝트를 바라보게 하고 싶을 때 사용
//타겟 오브젝트를 바라보도록 할 때
void Start()
{
transform.rotation = Quaternion.LookRotation(target.position - transform.position);
}
Quaternion.RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)
- from 각도에서 to 각도까지 degree delta 만큼 회전
- update문에서 사용하여 두 각도 사이를 부드럽게 회전하고 싶을 때 사용
void Update()
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, target.rotation, 20 * Time.deltaTime);
}
Quaternion.Angle(Quaternion a, Quaternion b)
- 두 개의 쿼터니언 각도 차이를 반환
float angle = Quaternion.Angle(targetA.transform.rotation, targetB.transform.rotation);
Quaternion.AngleAxis(float angle, Vector3 axis)
- 축(axis)을 기준으로 각(angle)만큼 회전
- 오브젝트 자체를 회전시킬 때 유용한 함수
void Update()
{
transform.rotation *= Quaternion.AngleAxis(180 * Time.deltaTime, Vector3.forward);
}
Quaternion.Euler(Vector3 euler)
- 오일러 각도 값을 쿼터니언으로 변환
void Update()
{
transform.rotation *= Quaternion.Euler(Vector3.right);
}
Quaternion.Lerp(Quaternion a, Quaternion b, float t)
- a와 b 사이를 t만큼 보간
- update문에서 사용하여 매 프레임마다 t만큼 보간하여 회전
- 아래 예제는 특정 오브젝트를 부드럽게 바라보도록 한 예제
void Update()
{
Quaternion lookTarget = Quaternion.LookRotation(target.position - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, lookTarget, Time.deltaTime);
}
Quaternion.Slerp(Quaternion a, Quaternion b, float t)
- a와 b 사이를 t만큼 구의 표면 위에서 보간
- Quaternion.Lerp는 각 값들의 수치만을 보간하는 반면 Slerp는 구의 표면을 기준으로 보간하므로 실질적인 각도 보간 기법
void Update()
{
Quaternion lookTarget = Quaternion.LookRotation(target.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, lookTarget, Time.deltaTime);
}
Quaternion.Inverse(Quaternion rotation)
- 매개변수로 입력된 rotation의 반대 방향을 반환
void Start()
{
transform.rotation = Quaternion.Inverse(transform.rotation);
}
Quaternion.FromToRotation(Vector3 fromDirection, Vector3 toDirection)
- fromDirection과 toDirection사이의 각도에 해당하는 쿼터니언을 반환
- 월드 좌표계에서 특정 축이 특정 방향으로 따르도록 할 때 사용
void Start()
{
transform.rotation = Quaternion.FromToRotation(Vector3.right, Vector3.up);
}
Transform 퍼블릭 함수
transform.LookAt(Transform target)
- transform이 target transform을 바라보도록 하는 함수
- 오브젝트를 바라보게 할 경우 Quaternion.LookRotation을 transform에 넣어주는 것과 동일한 결과 도출
void Update()
{
transform.LookAt(target);
}
transform.Rotate(Vector3 eulers, Space relativeTo = Space.Self)
- 여러 개로 오버로드 되어 있지만 모두 오브젝트를 특정 값만큼 회전하는 함수
- 오브젝트를 회전할 때 가장 보편적으로 사용
void Start()
{
transform.Rotate(target.rotation.eulerAngles, Space.World);
}
transform.RotateAround(Vector3 point, Vector3 axis, float angle)
- point를 기준으로 angle만큼 회전 (up vector는 axis)
- 공전하는 물체를 나타낼 때 유용
void Update()
{
transform.RotateAround(target.position, Vector3.up, 180 * Time.deltaTime);
}
'유니티 > 워크플로' 카테고리의 다른 글
[Unity] 개발 속도를 대폭 늘리는 단축키 (Shortcuts) (1) | 2023.07.02 |
---|---|
[Unity] 공간 변환 (World <-> Local) (0) | 2023.06.26 |
[Unity] 지형 복사 (Duplicate terrain data) (0) | 2022.11.10 |
[Unity] 버전 관리 시스템(VCS) - Git, Plastic SCM (0) | 2022.11.05 |
[Unity] 모노비헤이비어 (MonoBehaviour) (0) | 2022.05.17 |