이 장에서는 3 차원에서 물체의 방향을 기술하는 어려운 문제를 다룹니다. 또한 밀접하게 관련된 회전과 각변위 개념도 논의합니다. 3 차원에서 방향과 각변위를 표현하는 여러 가지 방법이 있습니다. 여기서는 가장 중요한 세 가지 방법인 행렬, 오일러 각, 쿼터니언과 덜 알려진 두 가지 형태인 회전축 - 각도 및 지수 사상을 논의합니다. 각 방법에 대해 표현 방식이 어떻게 작동하는지를 정확히 정의하고, 그 특이점과 장점 및 단점을 논의합니다.
상황에 따라 다른 기법이 필요하며, 각 기법마다 장단점이 있습니다. 각 방법이 어떻게 작동하는지뿐만 아니라 특정 상황에 가장 적합한 기법이 무엇인지, 그리고 표현 방식 간에 어떻게 변환하는지를 아는 것이 중요합니다.
3 차원에서의 방향성에 대한 논의는 다음과 같은 섹션으로 나뉩니다:
•
8.1 절에서는"방향 (orientation)", "방향 (direction)", "각변위 (angular displacement)"와 같은 용어들의 미묘한 차이점을 다룹니다.
•
8.2 절에서는 행렬을 사용하여 방향성을 표현하는 방법을 설명합니다.
•
8.3 절에서는 오일러 각을 사용하여 각 변위를 표현하는 방법을 설명합니다.
•
8.4 절에서는 회전축 - 각도 형식과 지수 사상 형식을 설명합니다.
•
8.5 절에서는 쿼터니언을 사용하여 각 변위를 표현하는 방법을 설명합니다.
•
8.6 절에서는 다양한 방법들을 비교하고 대조합니다.
•
8.7 절에서는 한 형태의 방향을 다른 형태로 변환하는 방법을 설명합니다.
이 장에서는 객체 공간과 수직 공간이라는 용어를 광범위하게 사용합니다. 이러한 용어에 익숙하지 않다면, 해당 용어가 처음 소개된 3.2 절로 돌아가 확인하시기 바랍니다.
8.1'방향 (Orientation)'이란 정확히 무엇인가?
3 차원에서 방향을 기술하는 방법에 대해 논의하기 전에, 우리가 정확히 무엇을 기술하려는지 먼저 정의해야 합니다. 방향 (orientation) 이라는 용어는 다음과 같은 다른 유사한 용어들과 관련이 있습니다.
•
방향 (direction)
•
각변위 (angular displacement)
•
회전 (rotation)
직관적으로, 물체의" 방향(orientation)"은 기본적으로 물체가 어느 방향을 향하고 있는지를 나타낸다는 것을 알 수 있습니다. 그러나"자세"는"방향"과 정확히 같은 개념은 아닙니다.
예를 들어, 벡터는 방향은 있지만 자세는 없습니다. 그 차이는 벡터가 특정 방향을 가리킬 때, 벡터를 길이 방향으로 비틀어도 (그림 8.1 참조) 벡터에는 실제 변화가 없다는 점입니다. 벡터는 길이 외에는 두께나 다른 차원이 없기 때문입니다.
그림 8.1
벡터를 비틀어도 벡터에는 눈에 띄는 변화가 발생하지 않습니다.
단순한 벡터와 달리, 특정 방향을 향하고 있는 제트기와 같은 물체를 생각해 보십시오. 벡터를 비튼 것과 동일한 방식으로 제트기를 비틀면 (그림 8.2 참조), 제트기의 방향이 바뀝니다. 8.3 절에서는 물체 방향의 이러한 비틀기 성분을 뱅크 (bank) 라고 부릅니다.
그림 8.2
물체를 비틀면 그 방향이 바뀝니다.
방향과 방향성의 근본적인 차이는 3 차원에서 방향을 단지 두 개의 숫자 (구면 좌표계의 각도) 로 매개변수화할 수 있는 반면, 방향성은 최소 세 개의 숫자 (오일러 각) 이 필요하다는 사실에서 구체적으로 드러납니다.
데카르트 좌표계 절에서는 물체의 위치를 절대적인 용어로 기술하는 것은 불가능하며, 항상 특정 기준 좌표계의 맥락 안에서만 기술해야 한다고 논의했습니다."점"과"벡터"의 관계를 조사했을 때, 위치를 지정하는 것은 실제로 다른 주어진 기준점 (보통 어떤 좌표계의 원점) 으로부터의 평행 이동량을 지정하는 것과 동일하다는 점을 알게 되었습니다.
마찬가지로 방향도 절대적인 용어로 설명할 수 없습니다. 위치가 어떤 알려진 점으로부터의 평행 이동으로 주어지듯, 방향은 어떤 알려진 기준 방향 (종종"항등"또는"홈"방향이라 함) 으로부터의 회전으로 주어집니다. 이 회전량을 각변위라고 합니다. 즉, 방향을 기술하는 것은 수학적으로 각변위를 기술하는 것과 동일합니다.
수학적으로 동등하다고 말하는 이유는 본서에서"방향"과"각변위", "회전"같은 용어 사이에 미묘한 차이를 두기 때문입니다."각변위"를 입력을 받아 출력을 생성하는 연산자로 생각하는 것이 도움이 됩니다. 여기에는 특정한 변환 방향이 내포되어 있는데, 예를 들어 이전 방향에서 새로운 방향으로의 각변위이거나 수직 공간에서 객체 공간으로의 각변위와 같습니다. 각변위의 한 예로는" z축을 중심으로 90도 만큼 회전하라"가 있습니다. 이는 벡터에 수행할 수 있는 동작입니다.
그러나 상태 변수나 기타 상황에서 입력/출력 연산자 프레임워크가 도움이 되지 않고 부모/자식 관계가 더 자연스러운 경우를 자주 마주치게 됩니다. 이러한 상황에서는"배향 (orientation)"이라는 용어를 사용하는 경향이 있습니다. 배향의 한 예로는"서서 동쪽을 향해 있는 상태"를 들 수 있습니다. 이는 어떤 상태를 기술합니다.
물론"서서 동쪽을 향해 있는 상태"라는 배향을"북쪽을 향해 선 상태에서 축을 중심으로 만큼 회전한다"라고 말함으로써 각 변위로 표현할 수도 있습니다. 배향과 각 변위 사이의 이러한 차이는 점과 벡터 사이의 차이와 유사한데, 이 둘은 수학적으로는 동등하지만 개념적으로는 동일하지 않은 또 다른 용어 쌍입니다. 두 경우 모두 첫 번째 용어는 주로 단일 상태를 기술하는 데 사용되고, 두 번째 용어는 주로 두 상태 간의 차이를 기술하는 데 사용됩니다. 물론 이러한 관례는 순전히 선호의 문제이지만 유용할 수 있습니다.
특히 해당 물체가 항공기인 경우, 물체의 배향을 지칭하는 데"자세 (attitude)"라는 단어가 사용되는 것도 들어보셨을 것입니다.
8.2 행렬 형식
3D 에서 좌표공간의 방향을 설명하는 한 가지 방법은 해당 좌표공간의 기저 벡터 (+x축, +y축, +z축) 가 어느 방향을 가리키는지 명시하는 것입니다. 물론 우리가 설명하려는 바로 그 좌표공간 내에서 이 벡터들을 측정하지는 않습니다. 정의상 좌표공간의 방향과 무관하게 이들은 항상 (1, 0, 0), (0, 1, 0), (0, 0, 1) 이기 때문입니다. 따라서 기저 벡터들을 설명하려면 다른 좌표공간을 사용해야 합니다. 이렇게 함으로써 두 좌표공간 간의 상대적 방향을 설정하게 됩니다.
이러한 기저 벡터들을 3×3 행렬의 행으로 구성하면 방향을 행렬 형태로 표현한 것이 됩니다. 1 이를 다르게 표현하면, 한 좌표공간에서 다른 좌표공간으로 벡터를 변환하는 데 사용할 수 있는 회전 행렬을 제공함으로써 두 좌표공간의 상대적 방향을 표현할 수 있다는 뜻입니다.
그림 8.3
행렬을 사용한 방향 정의
8.2.1 어떤 행렬?
우리는 이미 행렬을 사용하여 한 좌표 공간에서 다른 좌표 공간으로 점을 변환하는 방법을 살펴보았습니다. 그림 8.3 에서 오른쪽 상단에 있는 행렬은 제트기의 객체 공간에 있는 점들을 수직 공간으로 회전시키는 데 사용될 수 있습니다. 이 행렬의 행들을 분리하여 제트기 몸체 축의 좌표와 직접적인 관계가 있음을 강조했습니다. 이 회전 행렬에는 수직 공간으로 표현된 객체 축들이 포함되어 있습니다. 동시에 이것은 회전 행렬이기도 합니다: 행 벡터에 이 행렬을 곱함으로써 해당 벡터들을 객체 공간 좌표에서 수직 공간 좌표로 변환할 수 있습니다.
다음과 같은 합리적인 질문을 할 수 있습니다: 왜 행렬에는 수직 공간 좌표를 사용하여 표현된 몸체 축이 포함되어 있는가? 왜 객체 공간 좌표로 표현된 수직 축이 아닌가? 이를 다르게 표현하면, 왜 우리는 벡터를 객체 공간에서 수직 공간으로 변환하는 회전 행렬을 선택했는가? 왜 수직 공간에서 객체 공간으로 변환하는 행렬을 선택하지 않았는가?
수학적 관점에서 보면 이 질문은 다소 터무니없습니다. 회전 행렬은 직교 행렬이므로 그 역행렬은 전치행렬과 동일하기 때문입니다 (6.3.2 절 참조). 따라서 이 선택은 순전히 외형적인 문제에 불과합니다.
하지만 실용적인 측면에서 볼 때, 저희 의견으로는 이는 매우 중요합니다. 쟁점은 코드를 직관적으로 읽고 첫 시도부터 정상 작동하게 작성할 수 있는지, 아니면 해독하는 데 많은 노력이 필요하거나, 당신을 제외한 모든 사람에게'자명하다'는 이유로 명시되지 않은 관례에 대한 지식을 요구하는지에 있습니다. 그러니 좌표 공간 변환의 수학이 코드로 구현될 때 발생하는 실제적 측면에 대해 3.2.4 절에서'직립 공간 (upright space)'이라는 용어를 소개하며 시작했던 논의를 이어가기 위해 잠시 본론에서 벗어나도록 허락해 주십시오. 또한 프로그래머들이 회전 행렬을 다루며 고군분투하는 모습을 지켜보며 얻은 저희의 관찰을 바탕으로 몇 가지 의견을 피력할 여지를 허용해 주시기 바랍니다. 저희의 주장에 모두가 동의하리라 기대하지는 않지만, 적어도 모든 독자가 이러한 문제들을 고려하는 것의 가치를 이해해 주시길 바랍니다.
물론 모든 우수한 수학 라이브러리에는 임의의 변환을 표현할 수 있는 4×4 행렬 클래스가 있으며, 이는 행렬 요소의 값에 대해 어떠한 가정도 하지 않는다는 것을 의미합니다. (아니면 투영을 수행할 수 있는 4×4 행렬이거나, 평행 이동은 가능하지만 투영은 불가능한 4×3 일 수도 있습니다. 그러나 이러한 구분은 여기서는 중요하지 않습니다.) 이러한 행렬의 연산은 본질적으로 어떤 입력 좌표계와 출력 좌표계를 기준으로 정의됩니다. 이는 행렬 곱셈 개념에 내포된 당연한 사실입니다. 출력에서 입력으로 변환해야 한다면 해당 행렬의 역행렬을 구해야 합니다.
객체의 방향을 설명하기 위해 일반적인 변환 행렬 클래스를 사용하는 것이 일반적입니다. 이 경우 회전은 다른 모든 변환과 동일하게 취급됩니다. 인터페이스는 여전히 소스 공간과 대상 공간의 관점으로 정의됩니다. 불행히도, 우리의 경험에 따르면 다음 두 행렬 연산이 압도적으로 가장 자주 사용됩니다.
•
객체 공간 벡터를 수직 좌표계로 표현합니다.
•
수직 공간 벡터를 객체 좌표계로 표현합니다.
양방향으로 변환할 수 있어야 함에 유의하십시오. 한 방향이 다른 방향보다 훨씬 더 자주 사용된다는 경험이나 증거는 없습니다. 그러나 더 중요한 것은 연산의 본질과 프로그래머가 연산을 생각하는 방식이'오브젝트 공간'과'수직 공간'(또는'부모 공간'과'자식 공간'과 같은 다른 동등한 용어)이라는 관점에서 이루어진다는 점입니다. 이를 소스 공간과 대상 공간의 관점으로 생각하지 않습니다. 바로 이러한 맥락에서 본 장 시작 부분에서 제기된 질문, 즉'어떤 행렬을 사용해야 하는가?'를 고려하고자 합니다.
먼저, 방향과 각 변위 사이의 수학적으로는 무의미하지만 개념적으로 중요한 구분을 다시 한번 상기해 봅시다. (8.1 절 말미의 용어에 관한 주석을 참조하십시오.) 특정 각 변위를 수행하는 행렬을 생성하는 것이 목적이라면 (예를 들어" 축을 중심으로 30 도 회전하라"와 같은 경우), 위에서 언급한 두 연산은 아마도 여러분이 머릿속에 그리던 것과 실제로는 다를 것이며, 변환의 암시적 방향을 가진 일반적인 변환 행렬을 사용해도 문제가 없으므로 이 논의는 해당되지 않습니다. 현재 우리는 어떤 객체의 방향이 상태 변수로 저장되어 있는 상황에 초점을 맞추고 있습니다.
일반적인 변환 행렬을 사용하여 방향을 저장한다는 일반적인 정책을 채택한다고 가정해 봅시다. 임의의 규약을 선택해야 하므로, 이 행렬에 곱함으로써 객체 공간에서 기준 공간으로 변환되도록 정하겠습니다. 기준 공간에 있는 벡터를 객체 공간 좌표로 표현해야 한다면, 이 벡터에 해당 행렬의 역행렬 3 을 곱해야 합니다.
이제 우리의 정책이 평균적인 게임 프로그래머가 수백 번씩 작성하고 읽는 코드에 어떤 영향을 미치는지 살펴보겠습니다.
업라이트 공간(upright space)은 “월드 좌표계” 그 자체라기보다는, 월드에서 ‘위쪽(up)’이 항상 고정돼 있는 기준 좌표계를 말해요. 책에서는 이걸 기준 공간(reference space), 부모 공간(parent space) 같은 의미로도 씁니다.
핵심만 정리하면:
Object space (객체/로컬 공간): 물체에 붙어있는 좌표계
물체가 회전하면 축도 같이 돌아감
Upright space (업라이트/직립 공간): “중력 방향 기준으로 똑바로 서 있는” 좌표계
+y가 항상 “위”, 수평면(xz)이 항상 “바닥”인 느낌
그래서 heading(방위) 같은 걸 정의하기 편함 (수직축 기준으로 도는 회전)
왜 굳이 “월드”라고 안 하고 upright라고 따로 부르냐면,
게임에서 “월드”는 기울어진 지형, 이동 플랫폼, 부모 오브젝트 회전, 카메라 공간 등 때문에 “위쪽이 항상 고정된 절대 기준”이 아닐 때가 많고,
그럴 때도 우리는 보통 “캐릭터는 중력 기준으로 서 있다 / 위는 위다” 같은 계산을 하고 싶어서
‘항상 위가 고정된 기준 프레임’을 따로 잡아 그걸 upright space라고 부르는 경우가 많습니다.
즉, 실무적으로는 대부분 이렇게 대응시켜 이해하면 됩니다:
upright space ≈ (중력 up이 고정된) world-like 기준 좌표계
object space ≈ local 좌표계
그리고 책에서 자주 나오는 두 변환이 딱 이거예요:
object → upright : 로컬 벡터를 월드(기준)에서 어떻게 보이게 할까?
upright → object : 월드(기준) 벡터를 로컬 좌표로 표현하면 뭐가 될까?
•
오브젝트 공간에서 업라이트 공간으로 벡터를 회전시키는 것은 행렬 곱셈으로 코드로 변환됩니다.
•
업라이트 공간에서 오브젝트 공간으로 벡터를 회전시키는 것은 행렬의 역행렬 (또는 전치행렬) 과의 곱셈으로 코드로 변환됩니다.
이 코드는 프로그래머의 고 수준 의도와 일대일로 대응하지 않습니다. 행렬을 사용할 때마다 매번 사용자가 규약을 기억하도록 강요합니다. 우리의 경험에 따르면, 이러한 코딩 스타일은 초보 프로그래머가 행렬 사용법을 배우는 데 어려움을 겪는 요인 중 하나입니다. 결과가 제대로 나오지 않을 때 그들은 종종 무작위로 전치 (transpose) 하거나 부호를 반전 (negate) 하는 실수를 저지르곤 합니다.
우리는 임의의 변환이 아닌 객체의 방향 (orientation) 을 저장하는 데만 전용되는 특별한 행렬 클래스를 두는 것이 유용하다고 판단했습니다. 이 클래스는 행렬이 직교 (orthogonal) 한다는 불변량 (invariant) 을 전제로 하며, 이는 행렬이 회전만 포함한다는 것을 의미합니다. (직교 행렬에서 반사 (reflection) 가 가능함에도 불구하고, 우리는 일반적으로 행렬에 반사가 포함되지 않는다고 가정합니다.) 이러한 가정을 바탕으로 이제 행렬을 사용하여 더 높은 수준의 추상화에서 회전을 수행할 수 있게 되었습니다. 우리의 인터페이스 함수들은 프로그래머의 고수준 의도와 정확히 일치합니다. 또한 행 벡터 대 열 벡터, 공간이 왼쪽에 있는지 오른쪽에 있는지, 어떤 방식이 정규 방식이고 어떤 방식이 역변환인지 등과 같이 혼란스러울 수 있는 선형대수학적 세부 사항들을 제거했습니다. 또는 차라리 그러한 세부 사항들을 클래스 내부로 한정했다고 표현하는 것이 더 적절할 것입니다. 물론 클래스를 구현하는 사람은 반드시 하나의 규약 (convention) 을 선택해야 하며 (바람직하게는 이를 문서화해야 합니다). 실제로 이 특수화된 행렬 클래스에서는"벡터 곱하기"와"이 행렬의 역행렬 구하기"연산이 그다지 유용하지 않습니다. 우리는 이 전용 행렬 클래스를 벡터와 곱하는 연산보다는 직교 공간과 객체 공간 관련 연산으로만 제한하여 사용하는 것을 권장합니다.
따라서 본 장 시작 부분에서 제기된 질문, 즉"어떤 행렬을 사용해야 하는가?"로 돌아가 보겠습니다. 우리의 답변은"상관없어야 한다"입니다. 이는 어떤 선택이 이루어졌는지 알지 못하더라도 행렬 코드를 설계하여 사용할 수 있는 방법이 있다는 뜻입니다. C++ 코드 관점에서 이는 순수하게 외형적인 변경에 불과합니다. 예를 들어, 단순히 함수명 multiply() 를 objectToUpright() 로 대체하고, 마찬가지로 multiplyByTranspose() 를 uprightToObject() 로 대체할 수 있습니다. 설명적이고 이름 붙여진 좌표 공간을 사용한 코드 버전이 읽고 작성하기 더 쉽습니다.
8.2.2 방향 코사인 행렬
행렬로 방향을 기술하는 맥락에서 ‘방향 코사인’(매우 구식 용어)이라는 표현을 접할 수 있습니다. 방향 코사인 행렬은 회전 행렬과 동일하지만, 이 용어는 행렬을 해석하거나 구성하는 특정 방식을 가리킬 뿐입니다. 이 해석은 흥미롭고 교육적이므로 잠시 멈추어 자세히 살펴보겠습니다. 회전 행렬의 각 요소는 한 공간의 기본 축과 다른 공간의 기본 축 사이의 내적과 같습니다. 예를 들어 3×3 행렬의 중앙 요소는 한 공간의 y축과 다른 공간의 y축이 이루는 내적을 제공합니다.
보다 일반적으로, 어떤 좌표공간의 기저 벡터가 서로 직교하는 단위 벡터 p, q, r 라고 하고, 같은 원점을 가지지만 다른 (역시 정규직교인) 기저 p’, q’, r’ 를 갖는 두 번째 좌표공간이 있다고 합시다. (이 절에서는 수식의 불필요한 복잡성을 피하기 위해 관례를 깨고 단위 벡터 위의 모자 기호를 모두 생략하겠습니다.) 첫 번째 공간에서 두 번째 공간으로 행 벡터를 회전시키는 회전 행렬은 각 기저 벡터 쌍 사이의 각도의 코사인으로 구성할 수 있습니다. 물론 두 단위 벡터의 내적은 정확히 그들 사이 각도의 코사인과 같으므로, 행렬 곱은 다음과 같습니다.
이 축들은 수치적 실체가 아닌 기하학적 실체로 해석될 수 있으므로, 축을 기술하는 데 어떤 좌표를 사용하든 (모든 축을 동일한 좌표계로 기술한다는 전제 하에) 회전 행렬은 동일합니다.
예를 들어, 축이 첫 번째 기저에 상대적인 좌표로 기술된다고 가정해 봅시다. 그러면 p, q, r는 각각 (1, 0, 0), (0, 1, 0), (0, 0, 1)라는 자명한 형태를 가집니다. 두 번째 공간의 기저 벡터인 p’, q’, r’는 임의의 좌표를 갖습니다. 자명한 벡터 p, q, r을 식 (8.1) 의 행렬에 대입하고 내적을 전개하면 다음을 얻습니다.
즉, 회전 행렬의 각 행은 출력 좌표공간의 기저 벡터를 입력 좌표공간의 좌표를 사용하여 표현한 것입니다. 물론 이 사실은 회전 행렬뿐만 아니라 모든 변환 행렬에 대해 성립합니다. 이것이 변환 행렬이 작동하는 핵심 아이디어이며, 이는 4.2 절에서 다루었습니다.
이제 다른 경우를 살펴보겠습니다. 첫 번째 기저에 상대적인 좌표를 사용하는 대신, 두 번째 좌표계 (출력 공간) 를 사용하여 모든 것을 측정합니다. 이번에는 p’, q’, r’는 자명한 형태를 가지며, p, q, r는 임의의 값입니다. 이를 방향 코사인 행렬에 대입하면
이는 회전 행렬의 열이 출력 공간의 좌표를 사용하여 표현된 입력 공간의 기저 벡터들로 구성된다는 것을 의미합니다. 이는 일반적인 변환 행렬에는 해당하지 않으며, 회전 행렬과 같은 직교 행렬에만 적용됩니다.
또한, 우리의 관례는 왼쪽에 행 벡터를 사용한다는 점을 기억하세요. 만약 오른쪽에 열 벡터를 사용한다면, 모든 것이 전치됩니다.
8.2.3 행렬 형태의 장점
행렬 형태는 방향을 나타내는 매우 명시적인 방식입니다. 이러한 명시성은 몇 가지 이점을 제공합니다.
•
벡터의 회전은 즉시 수행할 수 있습니다. 행렬 형태의 가장 중요한 특성은 객체 공간과 기준 공간 사이에서 벡터를 회전시키는 데 행렬을 사용할 수 있다는 점입니다. 방향을 나타내는 다른 어떤 표현도 이를 허용하지 않습니다. 벡터를 회전시키려면 방향을 행렬 형태로 변환해야 합니다.
•
그래픽스 API 에서 사용하는 형식입니다. 앞서 언급한 이유들로 인해 그래픽스 API 는 방향을 표현할 때 행렬을 사용합니다. (API 는 애플리케이션 프로그래밍 인터페이스의 약자로, 기본적으로 그래픽스 하드웨어와 통신하기 위해 사용하는 코드입니다.) API 와 통신할 때는 변환을 행렬 형태로 표현해야 합니다. 프로그램 내부에서 변환을 어떻게 저장할지는 개발자의 선택에 달려 있지만, 다른 표현 방식을 선택하더라도 그래픽스 파이프라인의 어느 시점에서는 반드시 행렬로 변환해야 합니다.
•
여러 각 변위의 연결. 행렬의 세 번째 장점은 중첩된 좌표계 관계를"축소"할 수 있다는 점입니다. 예를 들어, 객체 A 가 객체 B 에 대해 갖는 방향을 알고 있고, 객체 B 가 객체 C 에 대해 갖는 방향을 알고 있다면, 행렬을 사용하여 객체 A 가 객체 C 에 대해 갖는 방향을 결정할 수 있습니다. 이러한 개념은 3 장에서 중첩된 좌표계를 논의할 때 이미 다루었으며, 이후 5.6 절에서 행렬을 어떻게 연결할 수 있는지 논의했습니다.
•
행렬 역변환. 각 변위가 행렬 형태로 표현될 때, 행렬 역변환을 사용하여"반대"각 변위를 계산할 수 있습니다. 더욱이 회전 행렬은 직교 행렬이므로, 이 계산은 단순히 행렬을 전치하는 사소한 작업에 불과합니다.
8.2.4 행렬 형태의 단점
방금 논의한 바와 같이 행렬의 명시적 성질은 몇 가지 장점을 제공합니다. 그러나 행렬은 방향을 저장하는 데 아홉 개의 숫자를 사용하는 반면, 방향은 단지 세 개의 숫자로만 매개변수화할 수 있습니다. 행렬에 포함된 이러한"추가"숫자들은 일부 문제를 일으킬 수 있습니다.
•
행렬은 더 많은 메모리를 차지합니다. 많은 방향을 저장해야 하는 경우 (예: 애니메이션 시퀀스의 키프레임), 세 개 대신 아홉 개의 숫자를 저장하는 데 필요한 추가 공간이 누적될 수 있습니다. 간단한 예를 들어보겠습니다. 인체 모델을 15 개의 서로 다른 신체 부위로 나누어 애니메이션을 만든다고 가정해 봅시다. 애니메이션은 각 부위가 부모 부위에 대해 갖는 방향을 제어함으로써 구현됩니다. 프레임당 각 부위의 방향을 하나씩 저장하고, 애니메이션 데이터가 초당 15Hz 라는 적당한 속도로 저장된다고 가정하면, 초당 225 개의 방향 데이터를 저장하게 됩니다. 행렬과 32 비트 부동소수점 숫자를 사용할 경우 각 프레임은 8,100 바이트를 차지합니다. 반면 오일러 각도 (다음 섹션 8.3 에서 다룰 예정) 를 사용하면 동일한 데이터는 불과 2,700 바이트만 필요합니다. 고작 30 초 분량의 애니메이션 데이터라도 행렬로 저장할 경우 오일러 각도로 저장했을 때보다 162KB 더 많은 공간이 소요됩니다!
•
사람이 사용하기 어렵습니다. 행렬은 사람이 직접 다루기에 직관적이지 않습니다. 숫자가 너무 많을 뿐만 아니라 모두 과 사이에 있습니다. 더욱이 사람은 일반적으로 방향을 각도로 생각하지만, 행렬은 벡터로 표현됩니다. 연습을 통해 주어진 행렬에서 방향을 해석하는 방법을 배울 수 있습니다. (이를 위해 4.2 절의 행렬 시각화 기법이 큰 도움이 됩니다.) 하지만 여전히 오일러 각보다 훨씬 어렵습니다. 반대로 비자명한 방향에 대한 행렬을 손으로 구성하려면 엄청난 시간이 걸립니다. 일반적으로 행렬은 사람이 방향을 자연스럽게 생각하는 방식과 맞지 않습니다.
•
행렬은 형태가 불완전할 수 있습니다. 앞서 언급했듯이, 행렬은 9 개의 숫자를 사용하지만 실제로 필요한 것은 3 개뿐입니다. 즉, 행렬에는 6 개의 중복 차수가 존재합니다. 행렬이 방향을 나타내는 데"유효"하려면 충족해야 할 6 가지 제약 조건이 있습니다. 행 벡터들은 단위 벡터여야 하며, 서로 직교해야 합니다 (6.3.2 절 참조).
마지막 요점을 더 자세히 살펴봅시다. 임의로 선택한 9 개의 숫자로 행렬을 만들 경우, 이 6 가지 제약 조건이 충족될 가능성은 매우 낮으므로 해당 9 개 숫자는 유효한 회전 행렬을 형성하지 못합니다. 즉, 행렬은 적어도 방향을 표현하는 목적에서는 잘못 형성될 수 있습니다. 잘못 형성된 행렬은 수치 예외, 이상하게 늘어난 그래픽, 기타 예상치 못한 동작을 초래할 수 있으므로 문제가 됩니다.
어떻게 잘못된 행렬이 생성될 수 있을까요? 여러 가지 방법이 있습니다:
•
행렬에 스케일, 전단, 반사 또는 투영이 포함될 수 있습니다. 이러한 연산의 영향을 받은 객체의"방향"이란 무엇일까요? 이에 대한 명확한 정의는 사실상 존재하지 않습니다. 비직교 행렬은 모두 잘 정의된 회전 행렬이 아닙니다. (직교 행렬에 대한 완전한 논의는 6.3 절을 참조하십시오.) 또한 반사 행렬 (직교 행렬임) 역시 유효한 회전 행렬이 아닙니다.
•
외부 소스에서 잘못된 데이터를 얻을 수도 있습니다. 예를 들어 모션 캡처와 같은 물리적 데이터 수집 시스템을 사용하는 경우, 캡처 과정으로 인해 오류가 발생할 수 있습니다. 많은 모델링 패키지는 형태가 불완전한 행렬을 생성하는 것으로 악명이 높습니다.
•
부동소수점 반올림 오류로 인해 실제로 잘못된 데이터를 생성할 수도 있습니다. 예를 들어 객체의 방향을 사용자가 상호작용적으로 제어할 수 있는 게임이나 시뮬레이션에서 흔히 발생하듯, 방향에 대해 수많은 점진적인 변화를 적용한다고 가정해 봅시다. 부동소수점 정밀도가 제한된 상태에서 수많은 행렬 곱셈을 수행하면 형태가 불완전한 행렬이 만들어질 수 있습니다. 이러한 현상을 행렬 드리프트 (matrix creep) 라고 합니다. 이미 6.3.3 절에서 논의한 바와 같이, 행렬을 직교화함으로써 행렬 드리프트를 방지할 수 있습니다.
8.2.5 행렬 형태의 요약
8.2 절에서 행렬에 대해 설명한 내용을 요약해 보겠습니다.
•
행렬은 방향을 표현하는"강력한"방법으로, 한 공간의 기저 벡터들을 다른 공간의 좌표로 명시적으로 나열합니다.
•
방향 코사인 행렬이라는 용어는 회전 행렬의 각 요소가 입력 기저 벡터 하나와 출력 기저 벡터 하나의 내적과 같다는 사실을 암시합니다. 모든 변환 행렬과 마찬가지로, 이 행렬의 행들은 입력 공간 기저 벡터들의 출력 공간 좌표입니다. 또한 회전 행렬의 열들은 출력 공간 기저 벡터들의 입력 공간 좌표인데, 이는 회전 행렬의 직교성 덕분에 성립하는 사실입니다.
•
방향을 행렬 형태로 표현하는 것은 주로 좌표 공간 간에 벡터를 회전시킬 수 있게 해주기 때문에 유용합니다.
•
현대 그래픽스 API 는 행렬을 사용하여 방향을 표현합니다.
•
행렬 곱셈을 사용하여 중첩된 좌표 공간에 대한 행렬들을 하나의 행렬로 통합할 수 있습니다.
•
행렬 역변환은"반대"방향의 각도 변위를 구하는 메커니즘을 제공합니다.
•
행렬은 다른 기법들에 비해 2~3 배 더 많은 메모리를 소모할 수 있습니다. 이는 애니메이션 데이터와 같이 대량의 방향 정보를 저장할 때 중요한 문제가 될 수 있습니다.
•
행렬 내의 숫자들은 인간이 직관적으로 다루기 어렵습니다.
•
모든 행렬이 방향을 설명하는 데 유효한 것은 아닙니다. 일부 행렬에는 반사나 전단이 포함될 수 있습니다. 외부 소스에서 잘못된 데이터를 얻거나 행렬 크리프 현상으로 인해 형식이 잘못된 행렬이 생성될 수 있습니다.
8.3 오일러 각
방향을 표현하는 또 다른 일반적인 방법은 오일러 각입니다. 이 기법은 이를 개발한 유명한 수학자 레온하르트 오일러 (1707–1783) 의 이름에서 유래했습니다. 8.3.1 절에서는 오일러 각의 작동 원리를 설명하고 가장 일반적으로 사용되는 오일러 각의 관례를 논의합니다. 8.3.2 절에서는 고정 축 시스템을 포함한 오일러 각의 다른 관례를 다룹니다. 오일러 각의 장단점은 8.3.3 절과 8.3.4 절에서 검토합니다. 8.3.5 절에서는 오일러 각과 관련된 가장 중요한 개념들을 요약합니다.
본 절에서는 구면 좌표계와 관련된 7.3.2 절의 많은 아이디어, 용어 및 관례를 활용합니다.
8.3.1 오일러 각이란 무엇인가?
오일러 각의 기본 개념은 서로 수직인 세 축을 중심으로 한 세 번의 회전 순서로 각 변위를 정의하는 것입니다. 이는 복잡해 보일 수 있지만, 실제로는 매우 직관적입니다. (사실, 인간이 사용하기 쉽다는 점이 오일러 각의 주요 장점 중 하나입니다.)
따라서 오일러 각는 서로 수직인 세 축을 중심으로 한 세 번의 회전을 통해 방향을 설명합니다. 하지만 어떤 축이며, 어떤 순서일까요? 사실 어떤 세 축을 어떤 순서로 사용하든 작동하지만, 대부분의 사람들은 특정 순서로 기저 축을 사용하는 것이 실용적이라고 판단했습니다. 가장 일반적인 관례이자 본서에서 사용하는 관례는 소위"헤딩 - 피치 - 뱅크"관례입니다. 이 시스템에서는 방향을 헤딩 각도, 피치 각도, 뱅크 각도로 정의합니다.
헤딩, 피치, 뱅크라는 용어를 정확히 정의하기 전에, 이 책에서 사용하는 좌표계 관례를 간단히 복습해 보겠습니다. 우리는 오른손이 아닌 왼손 좌표계를 사용하며, 여기서 +x 은 오른쪽, +y 은 위쪽, +z 은 앞쪽을 가리킵니다. (그림 1.15 를 참고하세요.) 또한, 왼손 법칙에 따른 양의 회전 방향을 잊어버렸다면 그림 1.14 로 돌아가 기억을 되살리는 것이 좋습니다.
헤딩, 피치, 뱅크 각도가 주어지면, 간단한 4 단계 과정을 통해 이러한 오일러 각이 설명하는 방향을 결정할 수 있습니다.
1 단계: "항등" 방향에서 시작합니다. 즉, 객체 공간의 축이 수직 축과 정렬된 상태입니다.
그림 8.4
1 단계: 단위 방향에 있는 물체
2 단계: 그림 8.5 에 표시된 대로 +y 축을 중심으로 방향 (heading) 회전을 수행합니다. 양의 회전은 오른쪽으로 회전하며 (위에서 내려다볼 때 시계 방향).
그림 8.5
2 단계: 요 (heading) 는 첫 번째 회전으로, 수직 축을 중심으로 회전합니다.
3 단계: 요가 적용된 후, 피치 (pitch) 는 +x 축을 중심으로 한 회전량을 측정합니다. 이는 객체 공간의 +x 축이며, 세계 좌표계의 수직 +y 축이 아닙니다. 왼손 법칙과 일관되게 유지할 때, 양의 회전은 아래쪽으로 회전함을 의미합니다. 즉, 피치는 실제로 하강각을 측정합니다. 이는 그림 8.6 에 설명되어 있습니다.
그림 8.6
3 단계: 피치는 두 번째 회전으로, 물체의 횡축을 중심으로 회전합니다.
4 단계: 헤딩 각도와 피치 각도가 적용된 후, 뱅크는 +z 축을 중심으로 한 회전량을 측정합니다. 다시 말해, 이는 원래의 수직 공간 +y 축이 아닌 객체 공간의 +z 축입니다. 왼손 법칙에 따르면, 원점에서 +z 방향을 바라볼 때 양의 뱅크는 반시계 방향으로 회전합니다. 이는 그림 8.7 에 설명되어 있습니다.
그림 8.7
4 단계: 뱅크는 세 번째이자 마지막 회전으로, 물체의 종축을 중심으로 회전합니다.
뱅크 (bank) 의 양의 방향이 반시계 방향인데, 헤딩 (heading) 의 양의 방향은 시계 방향이라는 점이 모순처럼 보일 수 있습니다. 하지만 이는 회전 방향을 판단하는 관점이 서로 다르기 때문입니다. 헤딩 (heading) 은 +y 축의 양 끝에서 원점을 바라볼 때 시계 방향으로 회전하는 것으로 정의합니다. 반면 뱅크 (bank) 는 그와 반대 관점에서 시계/반시계를 판단합니다.
원점에서 +y 축의 양 끝을 바라보면 헤딩 (heading) 은 실제로 반시계 방향으로 회전합니다. 또한 +z 축의 양 끝에서 원점을 향해 바라보면 (물체 정면에서 뒤를 보는 관점), 뱅크 (bank) 는 물체를 시계 방향으로 회전시키는 것처럼 보입니다. 어느 경우든 왼손 법칙이 적용됩니다.
이제 오일러 각으로 설명되는 방향에 도달했습니다. 1~3 단계가 구면 좌표계 각도로 방향을 찾는 데 사용되는 7.3.2 절의 절차와 유사하다는 점에 주목하십시오. 즉, 요 (heading) 와 피치 (pitch) 가 객체가 향하는 기본 방향을 정의하고, 뱅크 (bank) 가 비틀림의 양을 정의한다고 볼 수 있습니다.
8.3.2 기타 오일러 각 규약
이전 섹션에서 설명한 헤딩 - 피치 - 뱅크 시스템은 서로 수직인 세 축에 대한 세 각도를 사용하여 회전을 정의하는 유일한 방법이 아닙니다. 이 주제에는 많은 변형이 존재합니다. 이러한 차이 중 일부는 단순히 명칭의 문제일 뿐이지만, 다른 일부는 더 의미 있는 차이를 가집니다. 설령 우리의 규약이 마음에 든다 하더라도, 이 섹션을 건너뛰지 않기를 권장합니다. 매우 중요한 개념들이 논의되기 때문입니다. 이러한 주제들은 많은 혼란의 원천이 되어 왔으며, 우리는 이러한 혼란을 해소하고자 합니다.
먼저, 명칭에 관한 사소한 문제가 있습니다. 가장 흔히 쓰이는 변형은 항공우주 분야에서 널리 알려진 요 - 피치 - 롤 (yaw-pitch-roll) 방식입니다.5'롤 (roll)'이라는 용어는 뱅크 (bank) 와 완전히 동의어이며, 모든 목적에서 두 용어는 동일합니다. 마찬가지로 요 - 피치 - 롤이라는 제한된 맥락 내에서'요 (yaw)'라는 용어는 헤딩 (heading) 과 사실상 동일합니다. (다만 더 넓은 의미에서'요'라는 단어는 미묘하게 다른 의미를 지니며, 바로 이 미묘한 차이 때문에 우리는'헤딩'이라는 용어를 선호합니다. 이러한 지나치게 세세한 구분은 잠시 후에 논의하겠지만, 당분간은 요와 헤딩을 동일한 것으로 간주합니다.) 따라서 본질적으로 요 - 피치 - 롤 시스템은 헤딩 - 피치 - 뱅크 시스템과 같습니다.
덜 일반적인 다른 용어들도 자주 사용됩니다. 헤딩은 방위각 (azimuth) 이라고도 불리며, 우리가 피치라고 부르는 수직 각도는 자세 (attitude) 나 고도 (elevation) 라고도 합니다. 마지막으로 뱅크라고 부르는 회전 각도는 때로 틸트나 트위스트라고도 불립니다.
물론, 칠판에 글을 쓸 때 공간을 절약해야 한다는 필요성 (아마도?) 에 의해 동기부여를 받아 그리스 문자들을 마구잡이로 들이밀며 여러분의 눈알을 공격하는 고집스러운 수학자들도 있습니다. 다음과 같은 기호들을 보게 될 수도 있습니다:
물론 이는 외형적인 차이일 뿐입니다. 아마도 더 흥미로운 점은 이 세 단어가 종종 반대 순서인 롤 - 피치 - 요 (roll-pitch-yaw) 로 나열된다는 사실입니다. ("롤 피치 요"또는"요 피치 롤"로 구글을 검색하면 두 형태 모두 수많은 결과가 나오며, 어느 한 쪽이 더 우세하지도 않습니다.) 회전 순서가 그토록 중요한데도 사람들이 고의로 역순으로 나열할 정도로 괴팍한 걸까요? 우리는 단순히 용어 문제에 머무는 것이 아닙니다. 용어의 차이에서 암시되는 사고방식의 구분은 오일러 각도를 회전 행렬로 변환하는 방법을 고려할 때 실제로 유용하게 쓰일 것입니다. 사실 이"거꾸로 된"관례에는 지극히 타당한 이유가 있습니다. 바로 컴퓨터 내부에서 회전을 실제로 수행하는 순서이기 때문입니다!
고정 축 시스템은 오일러 각 시스템과 매우 밀접하게 관련되어 있습니다. 오일러 각 시스템에서는 회전이 매 회전마다 변하는 물체 축을 중심으로 발생합니다. 따라서 예를 들어, 뱅크 각도의 물리적 축은 항상 물체의 종방향 공간 축이지만, 일반적으로 수직 공간에서는 임의의 방향을 가집니다. 반면 고정 축 시스템에서는 회전 축이 항상 고정된 수직 축입니다. 그러나 실제로는 회전 순서를 반대로 취하면 고정 축 시스템과 오일러 각 시스템이 사실상 동일하다는 사실이 밝혀졌습니다.
다음 예시를 시각화하여 이것이 참임을 직접 확인해 보시기 바랍니다. 예를 들어, 요잉 (헤딩) 각도가 30°이고 피치 각도가 20°라고 가정해 봅시다 (이때는 뱅킹/롤링은 무시합니다). 오일러 각 규약에 따르면, 먼저 헤딩 축인 수직 축 (+y 축) 을 기준으로 30°만큼 회전한 후, 객체 공간의 횡축 (+x 축) 을 기준으로 20°만큼 회전합니다. 고정 축 방식을 사용하면 회전 순서를 반대로 수행하더라도 동일한 최종 방향에 도달할 수 있습니다. 즉, 먼저 피치 회전을 수행하여 수직 +x 축을 기준으로 20°만큼 회전하고, 이어 헤딩 회전을 수행하여 수직 +y 축을 기준으로 30°만큼 회전합니다. 우리는 오일러 각을 시각적으로 상상할 수는 있지만, 컴퓨터 내부에서 벡터를 수직 공간에서 객체 공간으로 회전시킬 때는 실제로 고정 축 시스템을 사용합니다. 이에 대한 자세한 내용은 오일러 각을 회전 행렬로 변환하는 방법을 설명하는 8.7.1 절에서 다룹니다. 고정 축 규약은 외재적 (extrinsic) 이라고도 하며, 일반적인 오일러 각 규약은 내재적 (intrinsic) 이라고 부릅니다.
오일러 각은 물체 축을 기준으로 회전하므로, 특정 단계의 회전축은 이전 회전에서 사용된 각도에 따라 달라집니다. 고정 축 시스템에서는 회전축이 항상 동일합니다. 즉, 기준 축입니다. 두 시스템은 회전을 반대 순서로 수행할 경우 서로 동등합니다.
이제"요 (yaw)"라는 용어를 더 정확하게 사용해야 한다는 겸손한 주장을 간략히 펼치고자 합니다. 항공 용어 상당 부분은 해상 용어에서 유래했습니다. 6 해상 맥락에서"요"라는 단어의 원래 의미는 절대 각도와 그 각도의 변화 모두 측면에서 본질적으로 진행 방향 (heading) 과 동일했습니다. 그러나 비행기나 기타 자유롭게 회전하는 물체의 맥락에서는 요와 진행 방향이 동일한 것이라고 보지 않습니다. 요 운동은 물체의 +y 축을 중심으로 한 회전을 생성하는 반면, 진행 방향의 변화는 수직인 +y 축을 중심으로 한 회전을 생성합니다. 예를 들어, 비행기 조종사가 페달을 사용하여 방향타를 조작할 때 이는 요 회전을 수행하는 것입니다. 왜냐하면 방향타에 의해 유발된 회전은 항상 비행기의 객체 공간 +y 축을 중심으로 이루어지기 때문입니다. 비행기가 수직으로 급강하하고 있는 상황을 상상해 보십시오. 만약 조종사가 +y 요를 수행하면, 비행기는 더 이상 아래를 향하지 않고 지평선을 향하며 90°로 기울어진 상태, 즉"옆으로 누운"상태가 될 것입니다. 이는 그림 8.8 에 설명되어 있습니다.
그림 8.8
헤딩 대 요
반면 1인칭 슈팅 게임에서 사용자가 마우스를 왼쪽에서 오른쪽으로 움직일 때는 헤딩 회전을 수행합니다. 이 회전은 항상 수직축, 즉 위쪽을 향하는 +y축을 중심으로 일어납니다. 사용자가 아래를 바라본 상태에서 마우스를 수평으로 움직여 헤딩 회전을 해도, 여전히 아래를 바라본 채 제자리에서 돌게 됩니다.
중요한 점은, 1인칭 슈팅 게임에서 그렇게 하기 때문에 헤딩이 요보다 더 낫다는 뜻이 아니라는 것입니다. 핵심은 요 운동은 단일 오일러 각을 조정하는 것만으로는 구현할 수 없지만, 헤딩 운동은 가능하다는 데 있습니다. 이런 이유로 우리는 '헤딩'이라는 용어가 더 적절하다고 생각합니다. 이는 첫 번째 오일러 각에 점진적인 변화를 가했을 때 나타나는 동작이기 때문입니다.
안타깝게도 '피치(pitch)'라는 용어에도 비슷한 비판을 제기할 수 있습니다. 뱅크(bank)가 0이 아닌 경우, 중간 오일러 각에 대한 미소 변화는 객체의 횡축을 중심으로 한 회전을 만들지 않기 때문입니다. 그러나 객체의 종축이 수평과 이루는 각도, 즉 중간 오일러 각이 실제로 지정하는 값을 설명할 간단하고 적절한 단어는 사실상 존재하지 않습니다. ('인클리네이션(inclination)'은 우향 규칙에 국한되므로 적합하지 않습니다.)
우리가 의도한 겸손한 태도로 우리의 의견을 읽어 주시길 바라며, 더 중요한 메시지 또한 전달되었기를 바랍니다. 겉보기에는 사소해 보이는 관례의 차이를 파고드는 일이 때로는 세부 사항에 대한 더 깊은 이해로 이어질 수 있습니다. 반면, 때로는 그저 지나친 트집에 불과할 수도 있습니다. 수십 년 동안 항공우주 엔지니어들은 달에 인간을 보내고 화성에 로봇을 착륙시켰으며, 저자들을 먼 도시까지 안전하게 왕복시킨 비행기를 만들어 왔습니다. 그 과정에서 그들은 계속 '요(yaw)'와 '롤(roll)'이라는 용어를 사용해 왔습니다. 그런데도 이들 중 일부는 우리가 누구인지조차 모른다면 믿으시겠습니까? 자신만의 용어를 선택할 기회가 있다면, 가능할 때는 '헤딩(heading)'이라는 단어를 쓰시길 권합니다. 하지만 누군가가 '요(yaw)'라는 단어를 쓴다 해도, 부디 이 책에서 우리가 그랬던 것처럼 이를 지나치게 문제 삼지는 마십시오. 특히 대화 상대가 당신보다 더 현명하다면 더욱 그렇습니다.
비록 이 책에서는 우향 항공우주 좌표계 관례를 따르지 않으며(용어에 대해 약간의 이견이 있지만), 오일러 각의 기본 전략과 관련해 물리적 의미에서 '지상'이라는 개념이 존재하는 우주라면 항공우주 선구자들의 지혜를 완전히 따르는 것이 유일한 길이라고 믿습니다. 이론적으로는 회전축으로 임의의 세 축을 임의의 순서로 사용할 수 있음을 기억하십시오. 그러나 실제로 개별 각도가 유용하고 의미를 갖도록 하려면, 그들이 선택한 관례만이 실질적으로 타당합니다. 축을 어떻게 명명하든 첫 번째 각도는 수직축을 중심으로, 두 번째 각도는 기체의 횡축을 중심으로, 세 번째 각도는 기체의 종축을 중심으로 회전해야 합니다.
이러한 복잡성만으로도 충분하지 않은 듯, 몇 가지를 더 추가해 보겠습니다. 지금까지 설명한 시스템에서는 각 회전이 서로 다른 물체 축을 중심으로 발생합니다. 그러나 오일러가 처음 제안한 원래 시스템은 첫 번째와 마지막 회전이 동일한 축을 중심으로 수행되는 "대칭" 시스템이었습니다. 이러한 방법은 세 각도가 세차 운동, 장동, 자전에 해당하는 팽이의 운동을 설명하는 등 특정 상황에서 더 편리합니다. 때로는 비대칭 시스템에 "오일러 각"이라는 이름을 붙이는 것에 반대하는 순수주의자들을 만날 수도 있지만, 이 용법은 많은 분야에서 널리 사용되므로 그들이 소수임을 안심하셔도 됩니다. 두 시스템을 구별하기 위해 대칭 오일러 각은 때로 "진정한(proper)" 오일러 각이라고 부르며, 더 일반적인 관례는 우리가 앞서 언급한 항공우주 분야의 선구자들이 처음 기록한 테이트-브라이언 각이라고 합니다 [1]. 오라일리 [10]는 진정한 오일러 각뿐만 아니라 로드리게스 벡터, 케일리-클라인 매개변수와 같은 회전을 기술하는 더 다양한 방법과 흥미로운 역사적 주석들을 다루고 있습니다. 제임스 디벨의 요약 [3]은 이 장에서와 마찬가지로 다양한 오일러 각 규약과 회전을 기술하는 다른 주요 방법들을 비교하지만, 더 높은 수준의 수학적 소양을 전제로 합니다.
선호하는 규약과 다른 오일러 각을 다뤄야 한다면, 두 가지 조언을 드립니다:
•
먼저 다른 오일러 각 시스템이 정확히 어떻게 작동하는지 이해해야 합니다. 양의 회전 정의나 회전 순서와 같은 사소한 세부 사항이 큰 차이를 만듭니다.
•
둘째, 오일러 각을 원하는 형식으로 변환하는 가장 쉬운 방법은 이를 행렬 형태로 변환한 뒤, 다시 해당 행렬을 자신이 사용하는 오일러 각 스타일로 되돌리는 것입니다. 이러한 변환을 수행하는 방법은 8.7절에서 배울 것입니다. 각도를 직접 조작하는 것은 겉보기보다 훨씬 어렵습니다. 자세한 내용은 [12]를 참조하십시오.
8.3.3 오일러 각의 장점
오일러 각은 단 세 개의 숫자, 즉 각도를 사용해 방향을 매개변수화합니다. 이 특성은 다른 방향 표현 방식에 비해 몇 가지 장점을 제공합니다.
•
오일러 각은 행렬이나 쿼터니언보다 사람이 사용하기 훨씬 쉽습니다. 오일러 각 삼중체가 각도이기 때문인데, 사람은 보통 방향을 각도로 생각합니다. 상황에 맞는 규약을 선택하면 실용적인 각도를 그대로 표현할 수 있습니다. 예를 들어, 헤딩 - 피치 - 뱅크 시스템은 강하각을 직접 나타냅니다. 따라서 방향을 수치로 표시하거나 키보드로 입력해야 할 때, 오일러 각은 사실상 유일한 선택지입니다.
•
오일러 각은 가능한 한 간결한 표현입니다. 방향을 설명하는 데 세 개의 숫자만 사용하며, 3차원 방향을 세 개 미만의 숫자로 파라미터화하는 시스템은 존재하지 않습니다. 메모리가 제한적인 경우 오일러 각은 가장 경제적인 선택입니다.
공간을 절약해야 할 때 오일러 각을 선택하는 또 다른 이유는, 저장하는 숫자를 더 쉽게 압축할 수 있기 때문입니다. 고정 정밀도 시스템으로 오일러 각을 더 적은 비트 수로 압축하는 일은 비교적 쉽습니다. 오일러 각은 각도이므로 양자화로 인한 데이터 손실이 고르게 분포됩니다. 반면 행렬과 쿼터니언은 각도의 사인과 코사인 값을 저장하므로 매우 작은 숫자를 다뤄야 합니다. 또한 두 값 사이의 절대적 차이가 지각되는 차이와 비례하지 않기 때문에, 일반적으로 고정 소수점 시스템으로 압축하기가 쉽지 않습니다.
결론적으로, 애니메이션 데이터처럼 제한된 메모리에 많은 3D 회전 데이터를 저장해야 한다면 오일러 각(또는 8.4절에서 논의될 지수 사상 형식)이 최선의 선택입니다.
•
세 개의 숫자로 이루어진 어떤 집합이든 유효합니다. 임의로 세 개의 숫자를 선택하더라도, 그것은 방향을 표현하는 것으로 해석할 수 있는 유효한 오일러 각 집합이 됩니다. 즉, 유효하지 않은 오일러 각 집합은 존재하지 않습니다. 물론 값이 정확하지 않을 수는 있지만, 적어도 유효하다는 점에서 행렬과 쿼터니언과는 다릅니다.
8.3.4 오일러 각의 단점
이 절에서는 오일러 각 방식으로 방향을 표현할 때의 단점 몇 가지를 다룹니다. 핵심은 다음 두 가지입니다.
•
주어진 방향에 대한 표현이 유일하지 않습니다.
•
두 방향 사이를 보간하는 과정에 문제가 생길 수 있습니다.
이제 이를 차례로 살펴보겠습니다.
먼저, 하나의 방향을 설명할 수 있는 오일러 각 삼중항이 여러 개 존재한다는 문제가 있습니다. 이를 별칭화(aliasing) 라고 하며, 다소 불편함을 초래할 수 있습니다. 이런 문제들은 7.3.4절에서 구면 좌표계를 다룰 때 마주친 문제와 매우 유사합니다. 별칭화 때문에 "두 오일러 각 삼중항이 동일한 각변위를 나타내는가?" 같은 기본 질문에 답하기가 어려워집니다.
우리는 극좌표계에서 이미 한 가지 단순한 별칭화를 접했습니다. 의 배수를 더하면 숫자는 달라지지만, 표현되는 방향은 변하지 않습니다.
별칭의 두 번째 유형은 더 성가신데, 세 각도가 서로 완전히 독립적이지 않기 때문에 발생합니다. 예를 들어 135° 아래로 피치하는 것은, 180° 헤딩한 뒤 45° 아래로 피치하고 이어 180° 뱅킹하는 것과 동일합니다.
구면 좌표계의 별칭 문제를 해결하기 위해 우리는 정준 집합을 정의하는 것이 유용하다는 것을 확인했습니다. 임의의 점은 극좌표로 표현할 때, 정준 집합 안에서 고유한 표현을 갖습니다. 오일러 각에도 비슷한 기법을 적용할 수 있습니다. 임의의 방향에 대해 고유한 오일러 각 표현을 보장하기 위해 각도의 범위를 제한하는 것입니다. 흔한 방법은 헤딩과 뱅크를 -180°~180°로, 피치를 -90°~90°로 제한하는 것입니다. 그러면 정준 집합 안에는 해당 방향을 나타내는 오일러 각 삼중항이 하나만 존재합니다. (다만 잠시 후 설명할 또 하나의 성가신 특이점이 남아 있습니다.) 정준 오일러 각을 사용하면 "대략 동쪽을 향하고 있는가?" 같은 기본 테스트가 훨씬 단순해집니다.
오일러 각에서 가장 유명하고 성가신 별칭 문제는 다음 예시에서 잘 드러납니다. 오른쪽으로 45° 헤딩한 뒤 아래로 90° 피치하는 것은, 먼저 아래로 90° 피치한 뒤 45° 뱅크하는 것과 같습니다. 실제로 피치 각도를 ±90°로 선택하는 순간, 수직 축을 중심으로만 회전할 수 있게 제한됩니다. 두 번째 회전이 90°일 때 첫 번째 회전과 세 번째 회전이 동일한 축을 중심으로 이루어지는 현상을 짐벌 락(Gimbal lock) 이라고 합니다. 오일러 각 삼중체의 정준 집합에서 이 별칭 문제를 제거하기 위해, 짐벌 락 상황에서는 수직 축을 중심으로 하는 모든 회전을 헤딩에 할당합니다. 즉 정준 집합에서 피치가 ±90°라면 뱅크는 0이 됩니다.
짐벌 락에 대한 이 마지막 규칙은 표준 오일러 각 집합에 대한 규칙을 완성합니다:
정준 집합에서 오일러 각이 만족하는 조건
C++ 로 오일러 각을 인수로 받는 코드를 작성할 때는 일반적으로 임의의 범위에 있는 오일러 각에서도 정상적으로 작동하도록 보장하는 것이 가장 좋습니다. 다행히도 이는 대체로 쉽습니다. 특히 각도가 삼각함수에 입력되는 경우, 별도의 추가 조치 없이도 대개 문제없이 작동합니다. 그러나 오일러 각을 계산하거나 반환하는 코드를 작성할 때는 표준화된 오일러 각 3 중값을 반환하는 것이 좋은 관행입니다. 8.7 절에 제시된 변환 메서드들이 이러한 원칙을 보여줍니다.
그림 8.9
순진한 보간은 과도한 회전을 유발할 수 있습니다.
흔히 짐벌 락 때문에 오일러 각으로 특정 방향을 표현할 수 없다는 오해가 있습니다. 실제로 방향을 기술하는 목적에서는 앨리어싱이 아무런 문제를 일으키지 않습니다. 분명히 말하자면, 3D 공간의 모든 방향은 오일러 각으로 표현할 수 있으며, 그 표현은 정준 집합 내에서 유일합니다. 또한 앞 절에서 언급했듯이"유효하지 않은"오일러 각 집합이라는 것은 존재하지 않습니다. 각도가 일반적인 범위를 벗어나더라도, 해당 오일러 각이 어떤 방향을 나타내는지에 대해 항상 합의할 수 있습니다.
따라서 단순히 방향을 설명하는 목적이라면, 특히 표준 오일러 각도를 사용할 경우 별칭 문제는 큰 문제가 되지 않습니다. 그렇다면 별칭과 김발 락이 왜 그렇게 문제일까요? 두 방향 과 사이를 보간하고자 한다고 가정해 봅시다. 즉, 주어진 매개변수 에 대해 일 때, 이 에서 로 변함에 따라 R 0 에서 R 1 으로 부드럽게 보간되는 중간 방향 R (t) 를 계산하고 싶습니다. 이는 예를 들어 캐릭터 애니메이션이나 카메라 제어에 매우 유용한 연산입니다.
그림 8.10
순진한 보간법은 긴 경로로 회전할 수 있습니다.
이 문제에 대한 순진한 접근 방식은 세 각도 각각에 표준 선형 보간 공식 ("lerp") 을 독립적으로 적용하는 것입니다:
두 각도 간의 단순 선형 보간 이는 여러 문제를 내포하고 있습니다.
첫째, 표준 오일러 각을 사용하지 않을 경우 매우 큰 각도 값이 발생할 수 있습니다. 예를 들어, R0 의 방향 (heading) 을 720°라 하고 R1 의 방향 (heading) 을 45°라고 가정해 봅시다. 이제 720°는 0°와 동일하므로, 기본적으로 R0 와 R1 는 불과 45° 차이입니다. 그러나 단순한 보간법을 적용하면 그림 8.9 에 나타난 것처럼 잘못된 방향으로 거의 두 바퀴를 회전하게 됩니다.
물론 이 문제에 대한 해결책은 정준 오일러 각을 사용하는 것입니다. 우리는 항상 두 개의 정준 오일러 각 집합 사이를 보간한다고 가정할 수 있습니다. 아니면 보간 루틴 내부에서 값을 정준 값으로 변환함으로써 이를 강제하도록 시도할 수도 있습니다. (-180°~180°범위 내에서 각도를 감싸는 것은 간단하지만, -90°~90°범위를 벗어나는 피치 값을 처리하는 것은 더 어렵습니다.)
그러나 정준 각을 사용하더라도 문제가 완전히 해결되지는 않습니다. 회전 각의 순환적 특성으로 인해 두 번째 유형의 보간 문제가 발생할 수 있습니다. 예를 들어 170°와 -170°이라고 가정해 봅시다. 이들은 모두 -180°~180°범위에 있는 방위각의 정준 값임을 주목하세요. 두 방위각 값은 불과 20°만큼 떨어져 있지만, 다시 한번 말해 단순한 보간은 올바르게 동작하지 않아 -20°인 더 짧은 반시계 방향 경로를 따르는 대신 340°인 시계 방향으로 긴 회전을 수행하게 됩니다. 이는 그림 8.10 에 나타나 있습니다.
이 두 번째 유형 문제에 대한 해결책은 보간 식에서 사용되는 각도 차이를 -180°~180°범위로 감싸서 최단 호를 찾는 것입니다. 이를 위해 우리는 다음 표기법을 도입합니다.
각도를 -π~π 사이로 감싸기
여기서 는 바닥 함수를 나타냅니다.
함수는 모든 게임 프로그래머가 도구 상자에 갖춰야 할 작고 날카로운 도구입니다. 각도의 순환적 특성을 고려해야 하는 일반적인 상황을 우아하게 처리하며, 적절한 2π 의 배수를 더하거나 빼는 방식으로 작동합니다. 목록 8.1 은 C 언어로 이를 구현한 방법을 보여줍니다.
float wrapPi(float theta) {
// Check if already in range. This is not strictly necessary,
// but it will be a very common situation. We don't want to
// incur a speed hit and perhaps floating precision loss if
// it's not necessary
if (fabs(theta) <= PI) {
// One revolution is 2 PI.
const float TWOPPI = 2.0f*PI;
// Out of range. Determine how many "revolutions"
// we need to add.
float revolutions = floor((theta + PI) * (1.0f/TWOPPI));
// Subtract it off
theta -= revolutions*TWOPPI;
}
return theta;
}
C++
복사
오일러 각으로 돌아가 보겠습니다. 예상대로 wrapPi()를 사용하면 두 각도 사이를 보간할 때 최단 호를 쉽게 취할 수 있습니다:
두 각도 사이를 보간할 때 최단 호를 취하는 방법
하지만 이러한 두 가지 임시 조치에도 불구하고 오일러 각 보간은 여전히 짐벌 잠금 (Gimbal lock) 문제를 겪으며, 많은 상황에서 덜컥거리고 부자연스러운 경로를 초래합니다. 물체가 갑자기 휙 돌아 마치 어딘가에 걸린 것처럼 보입니다. 근본적인 문제는 보간 과정에서 각속도가 일정하지 않다는 점입니다. 짐벌 잠금이 실제로 어떻게 보이는지 경험해 본 적이 없다면 왜 이렇게 문제가 되는지 의아할 수 있습니다. 불행히도 책의 삽화만으로는 이 문제를 완전히 이해하기 매우 어렵습니다. 실시간으로 직접 경험해야 합니다. 다행히도 이 문제를 시연하는 애니메이션을 찾는 것은 쉽습니다. 유튜브 (youtube.com) 에서"짐벌 잠금 (gimbal lock)"을 검색하면 됩니다.
오일러 각 보간법의 처음 두 가지 문제는 성가셨지만 분명히 극복 불가능한 것은 아니었습니다. 표준 오일러 각과 은 상대적으로 간단한 해결책을 제공합니다. 불행히도 짐벌 락은 사소한 불편을 넘어 근본적인 문제입니다. 회전을 재정의하여 이러한 문제가 발생하지 않는 시스템을 고안해 낼 수 있을까요? 불행히도 이는 불가능합니다. 3 차원 방향을 세 개의 숫자로 표현하는 데에는 본질적인 문제가 존재하기 때문입니다. 문제의 형태는 바꿀 수 있지만 완전히 제거할 수는 없습니다. 세 개의 숫자를 사용하여 3 차원 공간의 방향을 매개변수화하는 모든 시스템은 매개변수 공간에 특이점을 갖게 되며, 따라서 짐벌 락과 같은 문제에 노출될 수밖에 없습니다. 지수 사상 형태 (8.4 절 참조) 는 세 개의 숫자로 3 차원 회전을 매개변수화하는 또 다른 방식으로, 특이점을 단일 점인 대척점으로 집중시키는 데 성공했습니다. 이러한 특성은 특정 실제 상황에서 더 유리하지만 특이점을 완전히 제거하지는 못합니다. 이를 위해서는 8.5 절에서 다루는 쿼터니언을 사용해야 합니다.
8.3.5 오일러 각 요약
8.3 절에서 오일러 각에 대해 논의한 내용을 요약해 보겠습니다.
•
오일러 각은 세 개의 각도를 사용하여 방향을 저장합니다. 이 각도들은 객체 공간의 세 축을 중심으로 순서대로 회전하는 값을 나타냅니다.
•
가장 일반적인 오일러 각 시스템은 헤딩 - 피치 - 뱅크 시스템입니다. 헤딩과 피치는 물체가 향하는 방향을 나타내며, 헤딩은"나침반 판독값"을 제공하고 피치는 하강각을 측정합니다. 뱅크는"비틀림"의 양을 측정합니다.
•
고정 축 시스템에서는 회전체가 움직이는 축이 아닌 수직 축을 기준으로 회전이 발생합니다. 이 시스템은 회전 순서를 반대로 수행할 경우 오일러 각과 동일합니다.
•
많은 똑똑한 사람들이 오일러 각을 지칭하기 위해 다양한 용어를 사용하며, 서로 다른 관례를 채택할 만한 타당한 이유가 있습니다. 7 따라서 오일러 각을 다룰 때는 용어에 의존하지 않는 것이 가장 좋습니다. 항상 정확한 작업용 정의를 확인해야 하며, 그렇지 않으면 매우 혼란스러워질 수 있습니다.
•
대부분의 상황에서 오일러 각은 방향을 표현하는 다른 방법들에 비해 인간이 직관적으로 다루기 더 쉽습니다.
•
메모리가 귀할 때, 오일러 각은 3D 에서 방향을 저장하는 데 필요한 최소한의 데이터만 사용하며, 쿼터니언보다 압축하기도 더 쉽습니다.
•
유효하지 않은 오일러 각 집합이라는 것은 존재하지 않습니다. 어떤 세 숫자든 의미 있는 해석이 가능합니다.
•
오일러 각은 회전 각도의 순환적 특성과 회전들이 서로 완전히 독립적이지 않기 때문에 앨리어싱 문제를 겪습니다.
•
표준 오일러 각을 사용하면 오일러 각에 대한 많은 기본 질의를 단순화할 수 있습니다. 오일러 각 삼중주가 표준 집합에 속하려면 요 (heading) 와 뱅크 (bank) 가 -180°~180°범위 내에 있고 피치 (pitch) 가 -90°~90°범위 내에 있어야 합니다. 게다가 피치가 ±90°일 경우 뱅크는 0 이 됩니다.
•
짐벌 락은 피치가 ±90°일 때 발생합니다. 이 경우 헤딩과 뱅크가 모두 수직 축을 중심으로 회전하므로 자유도 하나가 손실됩니다.
•
흔히 알려진 오해와 달리, 3 차원의 모든 방향은 오일러 각으로 표현할 수 있으며, 정준 집합 내에서 해당 방향에 대한 고유한 표현에 합의할 수 있습니다.
•
함수는 각도의 순환적 특성을 다뤄야 하는 상황을 단순화하는 매우 유용한 도구입니다. 이러한 상황은 실무에서 자주 발생하며, 특히 오일러 각과 관련된 맥락에서 흔히 나타나지만 다른 경우에도 마찬가지입니다.
•
단순한 형태의 앨리어싱은 성가시지만 우회 방법이 있습니다. 반면 김벌 락은 쉬운 해결책이 없는 더 근본적인 문제입니다. 김벌 락이 문제가 되는 이유는 방향의 매개변수 공간에 불연속성이 있기 때문입니다. 이는 방향의 미세한 변화가 개별 각도에는 큰 변화를 초래할 수 있음을 의미합니다. 오일러 각을 사용하여 방향 간 보간을 수행하면 시스템이 불안정해지거나 흔들리는 경로를 따를 수 있습니다.
8.4 축 - 각도 및 지수 사상 표현
오일러의 이름은 회전과 관련된 여러 개념에 붙어 있습니다 (방금 8.3 절에서 오일러 각을 논의했습니다). 그의 이름은 오일러의 회전 정리에도 붙어 있는데, 이 정리는 기본적으로 임의의 3D 각변위는 신중하게 선택한 하나의 축을 중심으로 한 단일 회전으로 달성될 수 있다고 말합니다. 더 정확히는, 임의의 두 방향 과 이 주어졌을 때, 축 주위로 한 번 회전함으로써 에서 로 이동하게 하는 축 이 존재합니다. 오일러 각을 사용할 때는 기본 축 주위로만 회전할 수 있으므로 임의의 방향을 기술하려면 세 번의 회전이 필요합니다. 하지만 회전축을 자유롭게 선택할 수 있다면, 단 한 번의 회전만으로 충분한 그런 축을 찾을 수 있습니다. 게다가 이번 절에서 보겠지만, 몇 가지 사소한 세부 사항을 제외하면 이 회전축은 유일하게 결정됩니다.
오일러의 회전 정리는 방향을 기술하는 두 가지, 서로 밀접하게 관련된 방법을 이끌어냅니다. 먼저 표기법을 정하겠습니다. 회전 각도 θ 와, 원점을 지나며 단위 벡터 n̂ 에 평행한 회전축을 선택했다고 가정합니다. (이 책에서는 양의 회전을 왼손 법칙에 따라 정의합니다; 1.3.3 절 참조.)
두 값 θ 와 n̂ 을 그대로 사용하면 축 - 각 형태로 각변위를 표현한 것입니다. 또는 n̂ 의 길이가 1 이므로, 정보 손실 없이 θ 를 곱해 단일 벡터 e = θ n̂ 를 얻을 수 있습니다. 회전을 기술하는 이 방식은 다소 난해하고 생소한 이름인 '지수 사상 (exponential map)'으로 불립니다.8 회전 각도는 e 의 길이로부터 유도할 수 있습니다. 즉, θ = |e|이며, 회전축은 e 을 정규화해 얻습니다. 지수 사상은 축 - 각 표현보다 더 간결할 뿐만 아니라 (4 개 대신 3 개의 숫자), 특정 특이점을 우아하게 피하고 보간 및 미분 특성도 더 우수합니다.
축 - 각도와 지수 사상 형식은 다른 방향 표현 방식만큼 자세히 다루지는 않을 것입니다. 실제로 이들의 활용은 다소 특수하기 때문입니다. 축 - 각도 형식은 주로 개념적 도구로 사용됩니다. 이를 이해하는 것은 중요하지만, 다른 형식에 비해 직접 사용되는 빈도는 상대적으로 낮습니다. 이 형식의 주목할 만한 능력 중 하나는 변위의 임의 배수를 직접 얻을 수 있다는 점입니다. 예를 들어, 축 - 각도 형식으로 주어진 회전에 대해, 에 적절한 값을 곱하면 해당 회전의 1/3 또는 2.65 배에 해당하는 회전을 쉽게 구할 수 있습니다. 물론 지수 사상을 사용해도 동일한 연산을 똑같이 쉽게 수행할 수 있습니다. 사원수는 거듭제곱을 통해 이런 작업을 수행할 수 있지만, 수학을 살펴보면 내부적으로는 축 - 각도 형식을 사용하고 있음을 알 수 있습니다. (사원수가 내부적으로 지수 사상을 사용한다고 주장하더라도 말입니다!) 사원수는 슬립 (slerp) 을 사용해 유사한 연산을 수행할 수도 있지만, 이는 더 우회적인 방법이며 중간 결과가 180 도를 초과하는 회전을 저장할 수 없다는 제한이 있습니다. 사원수에 대해서는 8.5 절에서 살펴보겠습니다.
지수 사상은 축 - 각 표현보다 더 널리 사용됩니다. 첫째, 지수 사상의 보간 특성은 오일러 각보다 우수합니다. 비록 특이점 (다음에 논의됨) 이 있기는 하지만, 오일러 각에서 발생하는 것만큼 심각하지는 않습니다. 일반적으로 회전을 보간한다고 하면 쿼터니언을 떠올리기 쉽지만, 애니메이션 데이터 저장과 같은 일부 응용 분야에서는 과소평가된 지수 사상이 실행 가능한 대안이 될 수 있습니다 [5]. 하지만 지수 사상의 가장 중요하고 빈번한 용도는 각변위가 아니라 각속도를 저장하는 것입니다. 이는 지수 사상이 미분이 잘 되기 때문이며 (이는 다소 더 나은 보간 특성과도 관련이 있음), 여러 회전을 쉽게 표현할 수 있기 때문입니다.
오일러 각과 마찬가지로 축 - 각 및 지수 사상 형태도 앨리어싱과 특이점을 보이지만, 그 정도는 더 제한적이고 덜 심각합니다. 항등 방향, 즉 "각변위가 없음"이라는 경우에는 명백한 특이점이 존재합니다. 이때 θ = 0이며, 축의 선택은 무관합니다. 어떤 축을 사용해도 됩니다. 하지만 지수 사상은 이 특이점을 우아하게 감춥니다. 어떤 회전축 n̂ 을 선택하든 θ 를 곱하면 e 가 소멸하기 때문입니다. 축 - 각 공간에서 또 다른 사소한 형태의 앨리어싱은 θ 와 n̂ 를 모두 부호 반전해 만들 수 있습니다. 그러나 지수 사상 역시 이 문제를 피하는데, θ 와 n̂ 를 모두 부호 반전해도 e = θ n̂ 은 변하지 않기 때문입니다.
다른 별칭들은 그렇게 쉽게 처리할 수 없습니다. 오일러 각과 마찬가지로 θ 에 360°의 배수를 더하면, 동일한 최종 방향을 결과로 하는 각변위가 만들어지며 이러한 형태의 별칭 현상은 축 - 각 표현과 지수 사상 모두에 영향을 미칩니다. 하지만 이것이 항상 단점은 아닙니다. 각속도를 기술하는 경우, 이런 "추가" 회전을 표현할 수 있는 능력은 중요하고 유용한 속성입니다. 예를 들어, 정수 초 동안 적용했을 때 최종 방향이 동일하더라도, 초당 360°의 속도로 x 축 주위에서 회전하는 경우와 같은 축 주위에서 초당 1080°로 회전하는 경우를 구별할 수 있는 것은 매우 중요합니다. 쿼터니언 형식에서는 이러한 구별을 포착할 수 없습니다.
알려진 바와 같이, 회전 행렬로 기술할 수 있는 임의의 각변위는 지수 사상 표현에 의해 유일하게 결정됩니다. 비록 둘 이상의 지수 사상이 동일한 회전 행렬을 생성할 수 있더라도, 지수 사상의 부분집합 (여기서 |e| < π 인 것들) 을 취해 회전 행렬과 일대일 대응을 형성할 수 있습니다. 이것이 오일러의 회전 정리의 본질입니다.
이제 여러 회전을 연쇄적으로 적용하는 경우를 생각해 보겠습니다. e0 과 e1 이 지수 사상 (exponential map) 형식으로 표현된 두 회전이라고 합시다. 예를 들어 e0 다음에 e1 을 순서대로 수행한 결과는, 단일 회전 e2 를 수행한 것과 같지 않습니다. 이는 참일 수 없음을 우리는 알고 있는데, 그 이유는 일반적인 벡터 덧셈은 교환법칙이 성립하지만 3 차원 공간에서의 회전은 그렇지 않기 때문입니다. e0 = (0, -π/2, 0)라고 가정하고 e1 = (π/2, 0, 0)라고 합시다. 우리의 관례에 따르면 이는 아래로 90°만큼 피치 (pitch) 하는 회전과 동쪽으로 90°만큼 헤딩 (heading) 하는 회전입니다. e0 다음에 e1 을 수행하면 머리가 동쪽을 향한 채 아래를 보게 되지만, 반대 순서로 수행하면 동쪽을 바라보면서 "귀가 바닥에 닿은" 자세가 됩니다. 그런데 각도가 훨씬 작아서 90° 대신 2° 정도라면 어떨까요? 이때는 최종 회전 결과가 더 비슷해집니다. 회전 각도의 크기를 줄일수록 순서의 중요성은 감소하며, 극단적으로 "무한소 (infinitesimal)" 회전의 경우에는 순서가 전혀 중요하지 않게 됩니다. 즉, 무한소 회전에 대해서는 지수 사상을 벡터적으로 더할 수 있습니다. 무한소는 미적분학에서 중요한 주제이며, 변화율을 정의하는 핵심 개념입니다. 이 주제들은 11 장에서 다루지만, 여기서의 핵심은 지수 사상이 회전량 (각변위 또는 방향) 을 정의하는 데 사용될 때는 벡터적으로 더해지지 않는 반면, 회전율을 기술할 때는 올바르게 벡터적으로 더해진다는 점입니다. 이것이 지수 사상이 각속도를 기술하는 데 완벽하게 적합한 이유입니다.
이 주제를 떠나기 전에, 용어와 관련해 안타까운 경고를 덧붙이겠습니다. 이 두 가지 간단한 개념에는 대체 이름이 매우 많습니다. 가능한 한 가장 표준적인 이름을 선택하려 노력했지만, 강력한 합의를 찾기 어려웠습니다. 일부 저자는 "축 - 각도 (axis-angle)"라는 용어를 이 두 가지 (밀접하게 관련된) 방법을 모두 지칭하는 데 사용하며 실제로 둘을 구분하지 않습니다. 더 혼란스러운 것은 "오일러 축 (Euler axis)"이라는 용어가 오일러 각도가 아닌, 이 두 형태 중 하나를 지칭하는 데 사용된다는 점입니다. "회전 벡터 (rotation vector)"는 우리가 지수 사상 (exponential map) 이라고 부르는 것에 붙여지는 또 다른 용어일 수 있습니다. 마지막으로, 이 용어가 유래한 리 대수 (Lie algebra) 의 더 넓은 맥락에서 "지수 사상 (exponential map)"은 실제로 양 (quantity) 이 아니라 연산 (즉, "사상") 을 의미합니다. 혼란에 대해 사과드리지만, 이는 우리의 잘못이 아닙니다.

















