3D 애플리케이션에서 회전은 일반적으로 쿼터니언 또는 오일러 각으로 표현됩니다. 각 방법에는 고유한 용도와 단점이 있습니다. Unity는 내부적으로 쿼터니언을 사용하지만 쉽게 편집할 수 있도록 인스펙터에 해당 오일러 각의 값을 표시합니다.
오일러 각은 절차적으로 적용되는 X, Y, Z의 각도 값 3개로 더 간단하게 표시됩니다. 특정 오브젝트에 오일러 회전을 적용하기 위해 각 회전 값을 해당 축 주위의 회전으로 적용합니다.
쿼터니언은 오브젝트의 오리엔테이션 또는 회전을 나타내기 위해 사용할 수 있습니다. 내부적으로 (Unity에서 x, y, z, w라고 하는) 네 숫자로 표시되지만, 이 숫자는 각도나 축을 나타내지 않고 일반적인 경우 직접 액세스할 필요가 없습니다. 쿼터니언 수학에 대해서 특별한 관심이 없는 경우, 쿼터니언이 3D 공간의 회전을 나타낸다는 것만 이해하면 되며, (일반적인 경우)x, y 및 z 프로퍼티를 이해하거나 수정할 필요가 없습니다.
벡터가 포지션 또는 방향(원점에서 측정되는 방향)을 나타내는 것과 같이, 쿼터니언은 오리엔테이션 또는 회전을 나타낼 수 있습니다. 회전은 회전의 “원점” 또는 “Identity”으로 측정됩니다. 회전은 위와 같이 한 오리엔테이션에서 다른 오리엔테이션으로 측정되기 때문에, 쿼터니언으로 180도보다 큰 회전을 나타낼 수 없습니다.
Unity 내부에서는 모든 게임 오브젝트 회전이 쿼터니언으로 저장됩니다. 단점보다 장점이 더 많기 때문입니다.
하지만 트랜스폼 인스펙터에는 회전이 오일러 각으로 표시됩니다. 이해하고 편집하는 것이 더 쉽기 때문입니다. 인스펙터에 입력하는 게임 오브젝트 회전 값은 백그라운드에서 새로운 쿼터니언 회전 값으로 변환됩니다.
인스펙터에서 게임 오브젝트의 회전 값을 (예를 들어, X: 0, Y: 365, Z: 0로)입력할 수 있지만, 이 값을 쿼터니언으로 나타낼 수 없으므로 재생을 누르면 오브젝트의 회전값이 X: 0, Y: 5, Z: 0(또는 기타 유사한 값)으로 변경되는 부작용이 있습니다. “360도 전체 회전 더하기 5도”라는 개념을 이해하지 못하고 단순히 회전 결과와 동일한 방법으로 오리엔테이션되도록 설정된 쿼터니언으로 회전이 변환되었기 때문입니다.
스크립트에서 회전 처리를 다루는 경우 Quaternion 클래스와 이 클래스의 함수를 사용하여 회전 값을 만들고 수정해야 합니다. 오일러 각을 사용할 수 있는 상황도 있지만, 다음 사항을 염두에 둬야 합니다. - 오일러 각을 처리하는 Quaternion 클래스 함수를 사용해야 합니다. - 회전의 오일러 값을 검색 및 수정하고 다시 적용하면 의도하지 않은 부작용이 발생할 수 있습니다.
Unity Quaternion 클래스의 여러 함수를 통해 오일러 각을 전혀 사용하지 않고도 회전을 만들고 조정할 수 있습니다. 예:
생성:
조정:
하지만 때로는 스크립트에서 오일러 각을 사용하는 것이 좋습니다. 이 경우 각을 변수로 유지하고 회전에 오일러 각으로 적용하는 데만 사용해야 합니다. 오일러 각을 쿼터니언에서 검색해서 가져올 수 있지만, 검색해서 가져온 후 수정하고 다시 적용하면 문제가 발생합니다.
아래에는 흔히 발생하는 잘못된 방법에 대한 몇 개의 예제가 있습니다. 설명을 위해 오브젝트를 X축을 중심으로 초당 10도씩 회전시키려는 가상의 예제를 사용합니다. 다음은 잘못된 방법입니다.
// rotation scripting mistake #1
// the mistake here is that we are modifying the x value of a quaternion
// this value does not represent an angle, and will not produce desired results
void Update () {
var rot = transform.rotation;
rot.x += Time.deltaTime * 10;
transform.rotation = rot;
}
// rotation scripting mistake #2
// the mistake here is that we are reading, modifying then writing the Euler
// values from a quaternion. Because these values calculated from a Quaternion,
// each new rotation may return very different Euler angles, which may suffer from gimbal lock.
void Update () {
var angles = transform.rotation.eulerAngles;
angles.x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(angles);
}
그리고 다음은 스크립트에서 오일러 각을 올바르게 사용하는 예입니다.
// rotation scripting with Euler angles correctly.
// here we store our Euler angle in a class variable, and only use it to
// apply it as a Euler angle, but we never rely on reading the Euler back.
float x;
void Update () {
x += Time.deltaTime * 10;
transform.rotation = Quaternion.Euler(x,0,0);
}
많은 3D 저작 패키지와 Unity의 자체적인 내부 애니메이션 창에서는 오일러 각을 사용하여 회전을 애니메이션 중에 지정할 수 있습니다.
이러한 회전 값은 쿼터니언으로 표시할 수 있는 범위를 벗어나는 경우가 많습니다. 예를 들어 오브젝트가 제자리에서 720도 회전해야 하는 경우 오일러 각을 사용하여 X: 0, Y: 720, Z:0으 나타낼 수 있지만, 쿼터니언 값으로는 나타낼 수 없습니다.
Unity의 자체적인 애니메이션 창에는 회전을 보간하는 방법을 쿼터니언 또는 오일러 보간 중에서 선택할 수 있는 옵션이 있습니다. 오일러 보간을 지정하면 Unity가 각도로 지정된 전체 동작 범위를 나타내도록 설정됩니다. 하지만 쿼터니언 회전으로 지정하면 회전이 특정 오리엔테이션에서 끝나도록 설정되고 Unity는 쿼터니언 보간을 사용하여 해당 지점에 이르는 최단 거리로 회전합니다. 자세한 내용은 애니메이션 커브 사용을 참조하십시오.
애니메이션을 외부 소스에서 임포트하는 경우 파일에는 일반적으로 회전 키프레임 애니메이션이 오일러 포맷으로 포함됩니다. Unity의 디폴트 동작은 키프레임 간 회전이 쿼터니언의 유효 범위를 초과하는 상황을 방지하기 위해 애니메이션을 리샘플링하고 애니메이션의 모든 프레임마다 새로운 쿼터니언 키프레임을 생성합니다.
예를 들어 서로 6 프레임 떨어진 키프레임 2개가 있고 첫 번째 키프레임의 X 값이 0이고 두 번째 키프레임의 X 값이 270인 경우를 생각해 보십시오. 리샘플링하지 않으면 두 키프레임 사이에 쿼터니언 보간을 적용할 경우 반대 방향으로 90도 회전합니다. 그래야 첫 번째 오리엔테이션에서 두 번째 오리엔테이션까지 최단 거리로 갈 수 있기 때문입니다. 하지만 리샘플링하고 모든 프레임에 키프레임을 추가하면 키프레임 간 각도가 45도로 작아지므로 회전이 올바르게 작동합니다.
리샘플링을 해도 경우에 따라 쿼터니언으로 나타낸 임포트된 애니메이션이 오리지널과 충분히 유사하지 않을 수 있습니다. 그렇기 때문에 Unity 5.3 이상에는 런타임 시점에 오리지널 오일러 애니메이션 키프레임을 사용할 수 있도록 애니메이션 리샘플링을 끄는 옵션이 있습니다. 자세한 내용은 오일러 커브 회전 애니메이션 임포트를 참조하십시오.