이제까지, 우리는 물리 엔진을 만들때 알아야 할 거의 모든 것을 다루었다. 우리는 파티클들을 재현할 수 있는 능력이 있는 정교한 시스템을 구성했다. 개별적이거나 또는 aggregates로 연결되거나.
우리는 두 가지 것을 놓치고 있다:
- 튼튼한 일반-목적 충돌 탐지 시스템 (현재 우리는 hard constraints의 ad hoc system을 쓰고 있다).
- 움직이는 것 뿐만 아니라 회전하는 오브젝트의 능력
이러한 문제들 중의 첫 번째 것은 꽤 해결하기에 쉽고, 이 책의 part IV의 주제이다.
그 두 번째는 좀 더 복잡하다: 그것은 완전한 rigid-body physics system과 우리가 이제까지본 mass-aggregate systems 사이의 차이이다. 회전을 추가하기 위해, 우리는 우리의 엔진의 능력에서 뒤로 갈 필요가 있다. 우리는 많은 양의 함수를 제거하고, 그것을 full rotating rigid bodies를 기반으로 재구성할 필요가 있다. 이것은 이 파트와 part V를 필요할 것이다 - 그 책의 거의 나머지.
이 챕터는 회전하는 몸체의 특성과 그것들을 나타내고 조작하는데 필요한 수학적 구조들을 본다.
9.1 Rotating Objects in Two Dimensions
우리가 3차원에서 회전들을 보기전에, 2차원에서 그것들을 이해하는 것은 가치가 있다. 나는 이 섹션에서는 어떠한 코드도 구현하지 않을 것이지만, 2차원 케이스에 대해 생각하는 것은 3차원을 이해하는 좋은 비유이다.
2차원에서, 우리는 그것의 2차원 위치와 그것이 어떻게 향하는 지를 보여주는 각도에 한 오브젝트를 나타낼 수 있다. 위치가 어떤 고정된 원점을 기준으로 명시되는 것처럼, 그 각도는 또한 미리 결정된 방향을 기준으로 주어진다. 그림 9.1은 이것을 보여준다.
나는 이 책 전체에서 방향(orientation)이라는 단어를 한 오브젝트가 향하는 방향을 언급하기 위해 사용할 것이다. 회전(rotation)이라는 단어는 다른 맥락에서 많은 의미를 갖는다. 그래서 대부분 사람들이 그것이 의미하는 것을 느끼는 동안, 미묘한 혼동을 야기할 수 있는 카멜레온이 될 수 있는 그러한 용어들 중 하나이다.
특정하게 하기 위해, 나는 회전이라는 단어를 방향의 변화 만을 의미하기 위해 사용할 것이다 (모든 사람들 그리고 그들의 개가 어떤 것을 "rotation"이라고 부를 때, 내가 새로운 이름을 만들어 내려는 유혹을 피하려는 것을 제외하고). 만약 어떤 것이 회전된다면, 그것의 방향이 변했다는 것을 의미하는 것이 당연하다.
그러나, 만약 한 오브젝트가 spinning하고 있다면, 나는 방향의 변화율을 의미하기 위해 angular velocity(각 속도)라는 용어를 사용할 것이다.
9.1.1 The Mathematics of Angles
만약 우리가 방향을 가지고 어떤 수학을 한다면, 우리는 주의할 필요가 있다: 많은 다른 방향 값들이 같은 방향을 나타낼 수 있다. 만약 radians(라디안)으로 방향을 측정한다면 (원의 360도는 2pi 라디안이다), 그러면 2pi의 방향은 0과 같다. 개발자들은 일반적으로 고정된 범위의 방향값을 설정한다, 가령 (-pi, pi]. 만약 한 방향이 이 범위 밖으로 나가게 된다면, 그것은 다시 그 범위 안으로 들어와진다. 이러한 종류의 방향 scalar를 다루는 mathematical routines는 더러워 보일 수 있다. 많은 조정할 것들과 점검들이 있어서.
대안 접근법은 방향을 나타내기 위해 벡터를 사용하는 것이다. 우리는 오브젝트가 가리키는 방향을 나타내는 2개의 요소가 있는 벡터를 취한다. 그 벡터는 다음의 방정식을 따라서 스칼라값과 관련되어 있다.
여기에서 θ는 방향의 각의 표현이고, theta는 벡터 표기이다. 나는 zero orientation이 오브젝트가 양의 X축을 바라보고 있다고 가정하고, 방향이 시계 반대 방향으로 증가한다고 가정한다. 이것은 간단히 전통의 문제이다.
방향의 벡터 형태는 많은 (그러나 모든 것은 아닌) 수학적 연산을 수행하기에 더 쉽게 만든다. 그리고 그것은 덜 special-case code와 bounds-checking을 가지고 있다.
2차원 표현으로 넘어감에 있어서, 우리는 우리의 방향을 나타내는 값의 수를 두배시킨다. 우리는 한 오브젝트가 어떤 방향을 향하는지 결정할 때 오직 1개의 자유도만을 가졌지만, 한 벡터의 표기는 두 개의 자유도를 갖는다. A degree of freedom(자유도)는 다른 것들과 독립적으로 변화할 수 있는 어떤 양이다. 예를들어, 3D position은 세 개의 자유도를 갖는다. 왜냐하면 다른 두 개에서 그것의 위치를 바꾸지 않고, 세 개의 방향 어느 것이든지 움직일 수 있기 때문이다. 자유도의 개수를 계산하는 것은 3D에서 회전을 이해하는 데 있어서 중요한 도구이다.
이 추가 자유도를 갖는 것은 우리가 한 방향을 나타내지 않는 한 벡터를 갖게될 것이라는 것을 의미한다. 사실, 대부분의 벡터들은 방정식 9.1과 부합하지 않는다. 우리의 벡터가 한 방향을 나타내는 것을 보장하기 위해서, 우리는 그것의 자유도 몇몇 을 제거할 필요가 있다. 우리는 벡터가 1의 크기를 갖도록 하여 이것을 한다. 1의 크기를 가진 어떤 벡터는 9.1의 방정식과 부합할 것ㅅ이다. 그리고 우리는 그것의 대응되는 각을 찾을 수 있다.
이 제약을 바라보는 것의 기하학적인 방식이 있다. 만약 우리가 1의 크기를 가진 모든 가능한 벡터의 끝에 한 점을 그린다면, 우리는 그림 9.2에서 보여지는 한 원을 얻는다. 우리는 한 벡터 방향이 정확히 한 방향을 나타낸 다고 말할 수 있다. 만약 그것이 이 원 위에 놓여있다면. 만약 우리가 다소 빠져나간 한 방향을 나타내기로 한 벡터를 발견한다면 (어떤 계산에서 수적인 오류 때문에), 우리는 그것을 원 안으로 가져와 고칠 수 있다. 수학적으로 우리는 그것의 크기가 1이 되도록 하여 이것을 한다. 즉, 그 벡터를 표준화하여.
만약 우리가 방향을 나타내는 벡터를 사용하여 2D 게임을 만들었다면, 우리는 그 벡터들을 표준화하여 방향이 여전히 원안에 놓여있도록 때때로 확실하게 할 필요가 있다.
이 단계들을 요약해보자 (놀랍지않게도, 우리는 그것들을 나중에 다시 볼 것이다). 우리는 영역-점검(bounds-checking)의 문제로 시작한다. 그리고 이것은 우리가 추가 제약이 필요한 한 개가 더 있는 자유도를 가진 표현을 사용하도록 우리를 이끈다; 차례로, 이것은 우리가 그 제약을 강화하는 추가 단계를 추가하도록 이끈다.
9.1.2 Angular Speed
우리가 한 오브젝트의 각속도를 볼 때 (가끔 그것의 "rotation"이라고 불려지는), 우리는 방향에 대해 우리가 보는 어떠한 문제도 가지지 않는다. 초당 4pi radians의 각 속도는 초당 2pi radians와 다르다. 단일의 스칼라값으로 표현되는 모든 각 속도는 unique하다. 각 속도에 대한 수학은 간단하다. 그래서 우리는 bounds-checking과 special-case code가 필요없다. 이것은 차례로 우리가 벡터 표기를 사용할 필요가 없고, 스칼라 값만을 가지고갈 수 있다는 것을의미한다.
9.1.3 The Origin and The Center of Mass
2차원을 떠나기전에, 우리의 위치와 방향이 무엇을 나타내는지를 고려할 필요가 있다. 우리가 파티클들을 다룰 때, position은 particle의 location을 나타냈다. 정의에 의한 파티클들은 오직 공간에서 단일점에만 존재한다. 비록 이 책에서 우리가 그 정의를 연장하고 작은 구처럼 그것들을 다루었을지라도.
The Origin of an object
만약 우리가 더 큰 오브젝트를 가진다면, 그 position은 무엇을 나타내는가? 그 오브젝트는 동시에 많은 locations들에 있다: 그것은 어느정도 연장된 지역을 덮는다.
position은 오브젝트에서 변하지 않는 몇 가지 미리 동의된 위치를 나타낸다. 그것은 가끔 오브젝트의 "origin(원점)"으로 불려진다. 한 게임에서, 우리는 한 캐릭터의 척추 뿌리를 선택하거나 차의 chassis(뼈대, 섀시)의 중심을 선택할지도 모른다. 그 위치는 그 오브젝트 안에 있을 필요가 없다. 많은 개발자들은 한 캐릭터의 위치를 땅 위에 쉬고있는 캐릭터의 발꿈치 사이의 위치로 나타낸다.
그 위치가 그 오브젝트 주위를 움직이지 않는 한, 우리는 항상 그 오브젝트의 조금이 그것의 위치와 방향으로부터 어디를 향하는 지를 결정할 수 있다. 오브젝트에서의 locations는 그 오브젝트의 원점과 상대적으로 주어진다. 만약 한 차의 원점이 그것의 chassis의 중심에 있다면, 그림 9.3에서 보여지듯이, 그러면 그것의 오른쪽 헤드라이트는 원점을 기준으로 다음의 위치에 있을지도 모른다.
[1.5 -0.75]
만약 그 차가 움직인다면, 그것의 원점이 [4 3.85]가 되도록, 그러면 그것의 헤드라이트는
[1.5 -0.75] + [4 3.85] = [5.5 3.1] 가 된다.
이 움직임은 "translation(평행이동)"이라고 불려진다: 우리는 그 차를 한 위치에서 다른 곳으로 평행이동 시키고 있는 중이다.
Rotations
만약 그 오브젝트가 다른 방향을 바라보고 있다면, 같은 것이 발생한다. 그림 9.4에서, 그 차는 그것의 위치와 방향을 바꾸었다.
그래서 우리는 어떻게 그 headlamp의 위치를 이제 계산하는가? 처음에, 우리는 그 headlamp를 그 차가 바라보는 방향을 나타내도록 돌릴 필요가 있다. 우리는 이것을 우리의 방향 값의 세 번째 버전을 사용하여 한다.
이번에, 그 방향은 행렬 형태로 표현된다. 만약 너가 행렬에 대해 확신이 없다면, 나는 Section 9.2.3에서 3D를 위한 행렬 클래스를 구성할 때 그것들의 수학으로 되돌아 갈 것이다. 너가 만약 refresher가 필요없다면, 너는 그 수학을 여기에서 건너갈 수 있다.
방향의 그 행렬 형태는 이것처럼 보인다:
여기에서 θ는 이전처럼 방향 각(orientation angle)이다. 이 행렬은 보통 "회전 행렬"로 불려진다: 그것은 한 location을 회전시키기 위해 사용될 수 있다. 우리는 headlamp의 새로운 위치를 meadlamp의 relative position(상대 위치)에 rotation matrix를 곱하여 처리할 수 있다
여기에서 q_b는 그 headlamp의 relative location이다. 우리의 경우에 θ는 3pi/8이고, 다음을 얻는다.
여기에서 모든 값은 소수점 둘 째자리까지 반올림해라.
이 방식으로 방향을 적용하여, 우리는 이전처럼 위치에서의 변화를 적용할 수 있다. 모든 과정은 이것처럼 보인다:
여기에서 p는 그 오브젝트의 position이다. 이 방정식은 2D와 3D 둘 다 에서 작동한다. 비록 ϴ의 정의가 다를지라도. 우리는 그것에 대해 챕터의 나중에 볼 것이다.
우리의 예제에 대해 우리는 다음을 얻는다.
오브젝트의 위치와 방향, 그리고 그 컴포넌트의 상대적인 위치를 기반으로, 한 오브젝트의 어떤 부분의 location에 대해 계산하는 것은 "transformation from local space(body space and object space라고도 불려진다)" to world space(local space에서 world space로의 변환)라고 불려진다. 우리는 world space와 local space에 대해 section 9.4.5로 돌아갈 것이다.
The Composition of Rotations and Translations
알아차려야 할 한 가지 중대한 결과는 평행이동과 회전의 어떤 순서는 단일의 위치와 방향으로 나타내어질 수 있다는 것이다. 다시말해서, 아무리 내가 차를 여러번 그 차를 움직이고 회전시킬지라도, 우리는 항상 그것의 현재 위치와 방향에 대해 단일의 값들의 집합을 줄 수 있다. 이것은 회전과 평행이동의 어떤 조합은 단일의 회전이 오고 단일이ㅡ 평행이동이 온다고 하는 것과 동치이다.
Rigid Bodies
한 오브젝트의 모든 컴포넌트들이 그것의 원점을 기준으로 고정되어 있다는 사실은, 우리가 물리엔진에 대해 말할 때, rigid bodies에 대해 말하는 이유이다. 만약 우리의 차가 부셔질 수 있는 고무로 된 아기의 장난감 이라면, 그러면 위치와 방향을 아는 것은 우리에게 그 headlamp가 어디에 있는지를 말해줄 만큼 충분하지 않다: 그 headlamp는 매우 다른 위치로 뻗어졌을지도 모른다.
몇 가지 물리엔진은 simple soft bodies를 다룰 수 있지만, 보통 그것들은 그 몸체가 rigid하다고 가정하고, 그것이 soft하기 보이도록 하기 위해 몇 가지 후처리를 적용하여 작동한다. 우리의 엔진에서, 뿐만 아니라 대다수의 게임 물리엔진에서, 우리는 오직 rigid bodies만을 지원할 것이다.
이론적으로 우리는 그 오브젝트의 어떤 점이든 그것의 원점이 되도록 선택할 수 있다. 물리적으로 재현되지 않는 오브젝트들에 대해, 이것은 종종 개발자들이 취하는 접근법이다: 그들은 예술가 또는 AI 프로그래머가 작업하기에 편리한 한 점을 선택한다. 임의의 원점과 작동하는 물리 코드를 만드는 것이 가능하지만, 그 코드는 극도로 복잡해진다. 모든 오브젝트에는 원점이 극적으로 수학을 간단하게 하는 한 위치가 있다: the center of mass(질량중심).
Center of Mass
질량중심(CM)(종종 무게중심이라고 불려지는)은 한 오브젝트의 균형점이다. 만약 너가 이 점을 가로질러서 어떤 수직선으로 잘라서 그 오브젝트를 두 개로 분리한다면, 너는 정확히 같은 무게를 가진 두 오브젝트를 가지게 될 것이다. 만약 그 오브젝트가 2차원 도형이라면, 너는 너의 손을 CM에 위치시켜서 너의 손가락으로 그것의 균형을 맞출 수 있다.
만약 너가 한 오브젝트가 수백만개의 아주 작은 파티클들로 구성되어있다고 생각한다면(예를들어 원자), 너는 CM을 모든 이러한 작은 파티클들의 평균 위치인 것으로 생각할 수 있다. 그리고 거기에서, 각 파티클을 그것의 질량에 의존하는 평균에 기여한다. 사실, 이것이 우리가 CM을 계산하는 방법이다. 우리는 그오브젝트를 아주 작은 파티클들로 나누고, 그러한 모든 것의 평균 위치를 취한다:
여기에서 p_cofm는 CM의 위치이고, m은 그 오브젝트의 총 질량이고, m_i와 p_i는 particle i의 질량과 위치이다.
단일한 농도를 가진 한 구의 CM은 그 구의 중심점에 위치할 것이다. 직육면체도 유사하게, 그 CM은 그것의 기하학적 중심에 있을 것이다. CM이 항상 그 오브젝트 내에 포함되지는 않는다. 한 도넛은 예를들어 그것의 CM이 구멍에 있다. Appendix A는 다양한 다른 도형들에 대해 명세를 주고, 그것들의 CM이 어디에 위치해있는지를 준다.
만약 우리가 한 rigid body의 CM을 보려한다면, 그것은 항상 한 파티클처럼 행동하기 때문에 CM은 중요하다. 다시 말해서, 우리는 CM에 대한 force calculations을 수행하고, position과 velocity를 업데이트하기 위해 이 책에서 이제까지 사용했던 것과 정확히 같은 공식을 사용할 수 있다. CM을 우리의 원점 위치로 선택하여, 우리는 그 오브젝트의 선형 운동(파티클에 대한 것이 같은)과 각 운동(회전 운동)(우리가 추가 수학이 필요한)에 대해 그 계산을 완전히 분리시킬 수 있다.
그 오브젝트의 어떤 물리적 행동은 CM의 선형 운동과 같은 점에 대한 angular motion으로 분해될 수 있다. 이것은 심오하고 중대한 결과이지만, 증명하기에 시간이 걸리는 것이다; 만약 너가 그 배경지식이 필요하다면, mechanics에 대한 어떤 좋은 학부생 교재가 세부사항을 줄 것이다.
만약 우리가 어떤 다른 점을 원점으로 선택한다면, 우리는 더 이상 움직임을 두 종류로 나눌 수 없다. 그래서 우리는 그 원점이 어디있는지를 처리하기 위해 그 오브젝트가 어떻게 회전하는지를 고려할 필요가 있다. 명백히 이것은 우리의 모든 계산을 상당히 복잡하게 만든다.
몇몇 저자들과 교육자들은 두 가지 방법을 처리한다(비록 일반적으로 몇가지 결과에 대해서만일지라도. 수학이 정말 어려워질 때, 그들은 포기한다). 개인적으로 너의 원점이 CM이 아닌 다른 곳에 가지도록 고려하는 것은 매우 나쁜 생각이라고 나는 생가한다. 나느 이것이 이 책의 나머지에 대해서도 항상 사실이라고 가정할 것이다; 만약 너가 너의 원점이 다른곳에 있길 원한다면, 너 알아서 해라!
9.2 Orientation in three dimensions
2차원에서, 우리는 방향에 대해 단일의 각으로 시작했었다. 이 값을 유지하는 것의 문제들은 우리가 다른 표기들을 보게 만든다. 많은 2차원 게임들에서, 벡터 표기는 유용하지만, 각도에 대한 수학은 너무 어렵지 않아서, 너는 그 각도를 고수할 수 없고, 처리할 주변 코드를 조정하게 된다.
놀랍지 않게, 삼차원에서 유사한 문제들이 있다. 그래서 우리는 너가 고등학교에서 배운 수학이 전혀 아닌 방향에 대한 표기를 갖게 될 것이다. 그러나 3차원에서, 그 명백한 표기는 기본적으로 너무 흠잉 ㅣㅆ어서, 그것들을 작동시키게 하는 올바른 제 2의 해결책을 제공하는 것을 상상하는 것은 거의 불가능하다.
나는 작동하지 않는 표기법의 늪에 빠지길 원치 않지만, 우리가 개선된 다양한 솔루션을 보기전에 그 문제들을 간단하게 볼 가치는 있다.
그 위치가 그 오브젝트 주위를 움직이지 않는 한, 우리는 항상 그 오브젝트의 조금이 그것의 위치와 방향으로부터 어디를 향하는 지를 결정할 수 있다. 오브젝트에서의 locations는 그 오브젝트의 원점과 상대적으로 주어진다. 만약 한 차의 원점이 그것의 chassis의 중심에 있다면, 그림 9.3에서 보여지듯이, 그러면 그것의 오른쪽 헤드라이트는 원점을 기준으로 다음의 위치에 있을지도 모른다.
[1.5 -0.75]
만약 그 차가 움직인다면, 그것의 원점이 [4 3.85]가 되도록, 그러면 그것의 헤드라이트는
[1.5 -0.75] + [4 3.85] = [5.5 3.1] 가 된다.
이 움직임은 "translation(평행이동)"이라고 불려진다: 우리는 그 차를 한 위치에서 다른 곳으로 평행이동 시키고 있는 중이다.
Rotations
만약 그 오브젝트가 다른 방향을 바라보고 있다면, 같은 것이 발생한다. 그림 9.4에서, 그 차는 그것의 위치와 방향을 바꾸었다.
그래서 우리는 어떻게 그 headlamp의 위치를 이제 계산하는가? 처음에, 우리는 그 headlamp를 그 차가 바라보는 방향을 나타내도록 돌릴 필요가 있다. 우리는 이것을 우리의 방향 값의 세 번째 버전을 사용하여 한다.
이번에, 그 방향은 행렬 형태로 표현된다. 만약 너가 행렬에 대해 확신이 없다면, 나는 Section 9.2.3에서 3D를 위한 행렬 클래스를 구성할 때 그것들의 수학으로 되돌아 갈 것이다. 너가 만약 refresher가 필요없다면, 너는 그 수학을 여기에서 건너갈 수 있다.
방향의 그 행렬 형태는 이것처럼 보인다:
여기에서 θ는 이전처럼 방향 각(orientation angle)이다. 이 행렬은 보통 "회전 행렬"로 불려진다: 그것은 한 location을 회전시키기 위해 사용될 수 있다. 우리는 headlamp의 새로운 위치를 meadlamp의 relative position(상대 위치)에 rotation matrix를 곱하여 처리할 수 있다
여기에서 q_b는 그 headlamp의 relative location이다. 우리의 경우에 θ는 3pi/8이고, 다음을 얻는다.
여기에서 모든 값은 소수점 둘 째자리까지 반올림해라.
이 방식으로 방향을 적용하여, 우리는 이전처럼 위치에서의 변화를 적용할 수 있다. 모든 과정은 이것처럼 보인다:
여기에서 p는 그 오브젝트의 position이다. 이 방정식은 2D와 3D 둘 다 에서 작동한다. 비록 ϴ의 정의가 다를지라도. 우리는 그것에 대해 챕터의 나중에 볼 것이다.
우리의 예제에 대해 우리는 다음을 얻는다.
오브젝트의 위치와 방향, 그리고 그 컴포넌트의 상대적인 위치를 기반으로, 한 오브젝트의 어떤 부분의 location에 대해 계산하는 것은 "transformation from local space(body space and object space라고도 불려진다)" to world space(local space에서 world space로의 변환)라고 불려진다. 우리는 world space와 local space에 대해 section 9.4.5로 돌아갈 것이다.
The Composition of Rotations and Translations
알아차려야 할 한 가지 중대한 결과는 평행이동과 회전의 어떤 순서는 단일의 위치와 방향으로 나타내어질 수 있다는 것이다. 다시말해서, 아무리 내가 차를 여러번 그 차를 움직이고 회전시킬지라도, 우리는 항상 그것의 현재 위치와 방향에 대해 단일의 값들의 집합을 줄 수 있다. 이것은 회전과 평행이동의 어떤 조합은 단일의 회전이 오고 단일이ㅡ 평행이동이 온다고 하는 것과 동치이다.
Rigid Bodies
한 오브젝트의 모든 컴포넌트들이 그것의 원점을 기준으로 고정되어 있다는 사실은, 우리가 물리엔진에 대해 말할 때, rigid bodies에 대해 말하는 이유이다. 만약 우리의 차가 부셔질 수 있는 고무로 된 아기의 장난감 이라면, 그러면 위치와 방향을 아는 것은 우리에게 그 headlamp가 어디에 있는지를 말해줄 만큼 충분하지 않다: 그 headlamp는 매우 다른 위치로 뻗어졌을지도 모른다.
몇 가지 물리엔진은 simple soft bodies를 다룰 수 있지만, 보통 그것들은 그 몸체가 rigid하다고 가정하고, 그것이 soft하기 보이도록 하기 위해 몇 가지 후처리를 적용하여 작동한다. 우리의 엔진에서, 뿐만 아니라 대다수의 게임 물리엔진에서, 우리는 오직 rigid bodies만을 지원할 것이다.
이론적으로 우리는 그 오브젝트의 어떤 점이든 그것의 원점이 되도록 선택할 수 있다. 물리적으로 재현되지 않는 오브젝트들에 대해, 이것은 종종 개발자들이 취하는 접근법이다: 그들은 예술가 또는 AI 프로그래머가 작업하기에 편리한 한 점을 선택한다. 임의의 원점과 작동하는 물리 코드를 만드는 것이 가능하지만, 그 코드는 극도로 복잡해진다. 모든 오브젝트에는 원점이 극적으로 수학을 간단하게 하는 한 위치가 있다: the center of mass(질량중심).
Center of Mass
질량중심(CM)(종종 무게중심이라고 불려지는)은 한 오브젝트의 균형점이다. 만약 너가 이 점을 가로질러서 어떤 수직선으로 잘라서 그 오브젝트를 두 개로 분리한다면, 너는 정확히 같은 무게를 가진 두 오브젝트를 가지게 될 것이다. 만약 그 오브젝트가 2차원 도형이라면, 너는 너의 손을 CM에 위치시켜서 너의 손가락으로 그것의 균형을 맞출 수 있다.
만약 너가 한 오브젝트가 수백만개의 아주 작은 파티클들로 구성되어있다고 생각한다면(예를들어 원자), 너는 CM을 모든 이러한 작은 파티클들의 평균 위치인 것으로 생각할 수 있다. 그리고 거기에서, 각 파티클을 그것의 질량에 의존하는 평균에 기여한다. 사실, 이것이 우리가 CM을 계산하는 방법이다. 우리는 그오브젝트를 아주 작은 파티클들로 나누고, 그러한 모든 것의 평균 위치를 취한다:
여기에서 p_cofm는 CM의 위치이고, m은 그 오브젝트의 총 질량이고, m_i와 p_i는 particle i의 질량과 위치이다.
단일한 농도를 가진 한 구의 CM은 그 구의 중심점에 위치할 것이다. 직육면체도 유사하게, 그 CM은 그것의 기하학적 중심에 있을 것이다. CM이 항상 그 오브젝트 내에 포함되지는 않는다. 한 도넛은 예를들어 그것의 CM이 구멍에 있다. Appendix A는 다양한 다른 도형들에 대해 명세를 주고, 그것들의 CM이 어디에 위치해있는지를 준다.
만약 우리가 한 rigid body의 CM을 보려한다면, 그것은 항상 한 파티클처럼 행동하기 때문에 CM은 중요하다. 다시 말해서, 우리는 CM에 대한 force calculations을 수행하고, position과 velocity를 업데이트하기 위해 이 책에서 이제까지 사용했던 것과 정확히 같은 공식을 사용할 수 있다. CM을 우리의 원점 위치로 선택하여, 우리는 그 오브젝트의 선형 운동(파티클에 대한 것이 같은)과 각 운동(회전 운동)(우리가 추가 수학이 필요한)에 대해 그 계산을 완전히 분리시킬 수 있다.
그 오브젝트의 어떤 물리적 행동은 CM의 선형 운동과 같은 점에 대한 angular motion으로 분해될 수 있다. 이것은 심오하고 중대한 결과이지만, 증명하기에 시간이 걸리는 것이다; 만약 너가 그 배경지식이 필요하다면, mechanics에 대한 어떤 좋은 학부생 교재가 세부사항을 줄 것이다.
만약 우리가 어떤 다른 점을 원점으로 선택한다면, 우리는 더 이상 움직임을 두 종류로 나눌 수 없다. 그래서 우리는 그 원점이 어디있는지를 처리하기 위해 그 오브젝트가 어떻게 회전하는지를 고려할 필요가 있다. 명백히 이것은 우리의 모든 계산을 상당히 복잡하게 만든다.
몇몇 저자들과 교육자들은 두 가지 방법을 처리한다(비록 일반적으로 몇가지 결과에 대해서만일지라도. 수학이 정말 어려워질 때, 그들은 포기한다). 개인적으로 너의 원점이 CM이 아닌 다른 곳에 가지도록 고려하는 것은 매우 나쁜 생각이라고 나는 생가한다. 나느 이것이 이 책의 나머지에 대해서도 항상 사실이라고 가정할 것이다; 만약 너가 너의 원점이 다른곳에 있길 원한다면, 너 알아서 해라!
9.2 Orientation in three dimensions
2차원에서, 우리는 방향에 대해 단일의 각으로 시작했었다. 이 값을 유지하는 것의 문제들은 우리가 다른 표기들을 보게 만든다. 많은 2차원 게임들에서, 벡터 표기는 유용하지만, 각도에 대한 수학은 너무 어렵지 않아서, 너는 그 각도를 고수할 수 없고, 처리할 주변 코드를 조정하게 된다.
놀랍지 않게, 삼차원에서 유사한 문제들이 있다. 그래서 우리는 너가 고등학교에서 배운 수학이 전혀 아닌 방향에 대한 표기를 갖게 될 것이다. 그러나 3차원에서, 그 명백한 표기는 기본적으로 너무 흠잉 ㅣㅆ어서, 그것들을 작동시키게 하는 올바른 제 2의 해결책을 제공하는 것을 상상하는 것은 거의 불가능하다.
나는 작동하지 않는 표기법의 늪에 빠지길 원치 않지만, 우리가 개선된 다양한 솔루션을 보기전에 그 문제들을 간단하게 볼 가치는 있다.
9.2.1 Euler Angles
삼차원에서, 한 오브젝트는 회전에 대해 세 개의 자유도를 갖는다. 항공기의 움직임과 유사하게, 우리는 이것을 yaw, pitch, and roll이라고 부를 수 있다. 그 항공기의 어떤 회전은 이러한 세 개의 행동의 조합으로 구성될 수 있다. 그림 9.5는 그것들을 보여준다.
한 한공기에 대해, 이러한 회전은 세 축에 대한 것이다: pitch는 X축에 대한 회전이고, yaw는 Y축에 대한 회전, 그리고 roll은 Z축에 대한 회전이다( 한 항공기아 Z축을 내려다보고 있고, Y축이 위로되어있다고 가정해서).
한 위치가 벡터로 표기된다는 것을 회상해라. 그리고 거기에서 각 컴포넌트는 원점에서 한 방향으로의 거리를 나타낸다. 우리는 회전을 나타내는 한 벡터를 사용할 수 있고, 거기에서 각 컴포넌트는 대응되는 축에 대해 회전의 양을 나타낸다. 우리는 2차원 회전과 유사한 상황을 갖지만, 여기에서 우리는 3개의 축들을 가진다. 각 축에 대해 하나씩. 이러한 세 개의 축들은 "Euler angles"라고 불려진다.
이것은 방향에 대해 가장 명백한 표기이다. 그것은 많은 그래픽스 프로그램에서 사용된다. 그 주도적인 그래픽스 모델링 패키지들 몇 가지들은 내부적으로 오일러 각을 사용하고, 사용자에게는 방향을 오일러각으로는 여전히 종종 나타내지 않는 것들이다.
불행히도, 오일러 각은 우리의 필요에 거의 쓸모가 없다. 우리는 그것들로 작동하는 것의 implications을 보아서 이것을 알 수 있다. 너는 너의 손으로 축들의 집합을 만들어서 이것을 따라할 수 있다(2.1.1에서 묘사되었뜻이), 그리고 너의 상상의 오브젝트가 너의 손바닥과 같은 방향을 보고 있다고 기억해라 - 즉 Z축을 따라서.
우리가 pitch를 30도 정도로 수행한다고 상상해보자. 그 오브젝트는 이제 그것의 코가 공중 위를 향하게 된다. 이제 같은 양으로 yaw를 수행해보자. 그 yaw axis가 더 이상 위를 가리키지 않는다는 것을 알아차리자: 그 오브젝트가 pitched했을 때, 그 yaw axis는 또한 이동했다. 그 오브젝트가 어디를 향하는지를 기억해라. 다시 시작해보자 그러나 yaw를 먼저 수행하고, 그런 다음에 pitch를 해보자. 그 오브젝트는 다소 다른 위치에 있을 것이다. 이것이 무엇을 의미하는 가? 만약 우리가 다음과 같은 벡터를 가진다면
우리는 그 회전을 무슨 순서로 수행하는가? 그 결과는 각 순서에 따라 다를지도 모른다. 더욱이, 그 순서는 중요하기 때문에, 우리는 회전을 합치기 위해서 일반적인 벡터 수학을 사용할 수 없다. 특히,
r_1 r_2는 두 개의 회전들이다.
문제가 회전 축을 움직여서 발생한다고 생각하는 경우에(즉, 그것들이 world에 고정되어있다기 보다는 그 오브젝트에 결합해 있도록 유지하는 것), 다른 방식으로 해보아라. 같은 문제가 발생할 뿐만 아니라, 이제 우리는 또 다른 문제를 갖는다 - gimbal lock.
Gimbal lock은 우리가 한 오브젝트를 시작한 한 축이 다른 축과 정렬하도록 회전시킬 때 발생한다. 예를들어, 우리가 X, Y, Z의 순서로 회전을 적용한다고 가정하자. 만약 너가 90도로 yaw를 한다면 (즉, X 회전이 아니고, 90도로 Y회전), 그 오브젝트의 앞은 음의 X 방향으 가리키고 있다. 가령 우리가 그 오브젝트가 이제 조금 roll 하기를 원한다고 해보자(그것의 point of view로부터 roll). 우리는 그것을 할 수 없다: 우리가 필요한 축(local Z axis)는 이제 X방향을 가리키고 있기 때문이다. 그래서 우리는 벌ㅆ꺼 X 회전을 적용하는 점을 넘긴다.
그래서 아마도, 우리는 Y방향으로 회전하기 전에 처음에 X 회전을 조금 적용했었어야만 했다. 시도해보아라: 너는 그것을 할 수 없다. 이 특별한 문제에 대해, 우리는 다른 순서로 회전을 수행할 수 있다 - 예를들어, ZYX. 이것은 이전의 예시를 해결할 것이지만, 이 순서가 나타낼 수 없는 새로운 방향이 있다. 약 90도의 회전이 작동하게 된다면, 우리는 오일러 각의 조합으로 모든 원하는 방향을 얻을 수 없다. 이것이 "gimbal lock"으로 불려진다.
그 문제를 완화하는 몇 가지 방법들이 있다. 그것은 축들의 조합을 사용하는데, 그 축들의 몇 몇은 오브젝트와 움직이고, 다른 몇몇은 world space에서 고정된다. 대안으로 우리는 몇 가지 축들에 대해 회전을 반복 할 수 있다. 많은 다른 전략들이 있고, 그것들 몇몇은 다른 것들 보다 유용하다. 모든 것은 매우 임의의 수학과 끔찍한 boundary conditions와 너가 생각하기에 그것들이 디버깅 된 후에 충돌할 어려운 상황을 찾는 경향으로 특징지어진다.
Gimbal lock은 너무 중요해서, 그것은 NASA의 아폴로 달 프로그램에 특별히 포함되었다. 우리가 방향에 대해 최종적으로 가지게 될 수학은 이용가능하지 않았고, 오일러 각들이 flight-monitoring 컴퓨터에서 상요되었다. 그 컴퓨터가 gimbal lock에 도달하는 것을 방지하고, 우주선의 방향을 나타내는 것이 불가능하게 되는 것을 방지하기 위해, 제약들이 우주비행사가 통제에 발휘할 수 있는 방식에 가해졌다. 만약 그 우주선이 gimbal lock에 가까워졌다면, 경고음이 들릴 것이다. 우주선이 그 방식으로 방향을 바꿀 수 없는 물리적인 이유는 없었다; 그것은 순전히 NASA의 컴퓨터가 불능이 되는 것을 피하는 예방책이였다. 개인적으로 나는 이것이 유쾌한 교훈으로 받아들인다. 만약 그 NASA의 가장 좋은 두뇌가 gimbal lock을 처리하는 소프트웨어를 쓸 수 없다면, 나는 확실히 시도해보지 않았을 것이다.
운좋게도, 방향을 나타내는 훨씬 더 좋은 방법들이 있다. 그것들은 시각화하기에 직관적이지 않을지도 모르지만, 그것들의 수학은 훨씬더 신뢰할만 하다.
삼차원에서, 한 오브젝트는 회전에 대해 세 개의 자유도를 갖는다. 항공기의 움직임과 유사하게, 우리는 이것을 yaw, pitch, and roll이라고 부를 수 있다. 그 항공기의 어떤 회전은 이러한 세 개의 행동의 조합으로 구성될 수 있다. 그림 9.5는 그것들을 보여준다.
한 한공기에 대해, 이러한 회전은 세 축에 대한 것이다: pitch는 X축에 대한 회전이고, yaw는 Y축에 대한 회전, 그리고 roll은 Z축에 대한 회전이다( 한 항공기아 Z축을 내려다보고 있고, Y축이 위로되어있다고 가정해서).
한 위치가 벡터로 표기된다는 것을 회상해라. 그리고 거기에서 각 컴포넌트는 원점에서 한 방향으로의 거리를 나타낸다. 우리는 회전을 나타내는 한 벡터를 사용할 수 있고, 거기에서 각 컴포넌트는 대응되는 축에 대해 회전의 양을 나타낸다. 우리는 2차원 회전과 유사한 상황을 갖지만, 여기에서 우리는 3개의 축들을 가진다. 각 축에 대해 하나씩. 이러한 세 개의 축들은 "Euler angles"라고 불려진다.
이것은 방향에 대해 가장 명백한 표기이다. 그것은 많은 그래픽스 프로그램에서 사용된다. 그 주도적인 그래픽스 모델링 패키지들 몇 가지들은 내부적으로 오일러 각을 사용하고, 사용자에게는 방향을 오일러각으로는 여전히 종종 나타내지 않는 것들이다.
불행히도, 오일러 각은 우리의 필요에 거의 쓸모가 없다. 우리는 그것들로 작동하는 것의 implications을 보아서 이것을 알 수 있다. 너는 너의 손으로 축들의 집합을 만들어서 이것을 따라할 수 있다(2.1.1에서 묘사되었뜻이), 그리고 너의 상상의 오브젝트가 너의 손바닥과 같은 방향을 보고 있다고 기억해라 - 즉 Z축을 따라서.
우리가 pitch를 30도 정도로 수행한다고 상상해보자. 그 오브젝트는 이제 그것의 코가 공중 위를 향하게 된다. 이제 같은 양으로 yaw를 수행해보자. 그 yaw axis가 더 이상 위를 가리키지 않는다는 것을 알아차리자: 그 오브젝트가 pitched했을 때, 그 yaw axis는 또한 이동했다. 그 오브젝트가 어디를 향하는지를 기억해라. 다시 시작해보자 그러나 yaw를 먼저 수행하고, 그런 다음에 pitch를 해보자. 그 오브젝트는 다소 다른 위치에 있을 것이다. 이것이 무엇을 의미하는 가? 만약 우리가 다음과 같은 벡터를 가진다면
우리는 그 회전을 무슨 순서로 수행하는가? 그 결과는 각 순서에 따라 다를지도 모른다. 더욱이, 그 순서는 중요하기 때문에, 우리는 회전을 합치기 위해서 일반적인 벡터 수학을 사용할 수 없다. 특히,
r_1 r_2는 두 개의 회전들이다.
문제가 회전 축을 움직여서 발생한다고 생각하는 경우에(즉, 그것들이 world에 고정되어있다기 보다는 그 오브젝트에 결합해 있도록 유지하는 것), 다른 방식으로 해보아라. 같은 문제가 발생할 뿐만 아니라, 이제 우리는 또 다른 문제를 갖는다 - gimbal lock.
Gimbal lock은 우리가 한 오브젝트를 시작한 한 축이 다른 축과 정렬하도록 회전시킬 때 발생한다. 예를들어, 우리가 X, Y, Z의 순서로 회전을 적용한다고 가정하자. 만약 너가 90도로 yaw를 한다면 (즉, X 회전이 아니고, 90도로 Y회전), 그 오브젝트의 앞은 음의 X 방향으 가리키고 있다. 가령 우리가 그 오브젝트가 이제 조금 roll 하기를 원한다고 해보자(그것의 point of view로부터 roll). 우리는 그것을 할 수 없다: 우리가 필요한 축(local Z axis)는 이제 X방향을 가리키고 있기 때문이다. 그래서 우리는 벌ㅆ꺼 X 회전을 적용하는 점을 넘긴다.
그래서 아마도, 우리는 Y방향으로 회전하기 전에 처음에 X 회전을 조금 적용했었어야만 했다. 시도해보아라: 너는 그것을 할 수 없다. 이 특별한 문제에 대해, 우리는 다른 순서로 회전을 수행할 수 있다 - 예를들어, ZYX. 이것은 이전의 예시를 해결할 것이지만, 이 순서가 나타낼 수 없는 새로운 방향이 있다. 약 90도의 회전이 작동하게 된다면, 우리는 오일러 각의 조합으로 모든 원하는 방향을 얻을 수 없다. 이것이 "gimbal lock"으로 불려진다.
그 문제를 완화하는 몇 가지 방법들이 있다. 그것은 축들의 조합을 사용하는데, 그 축들의 몇 몇은 오브젝트와 움직이고, 다른 몇몇은 world space에서 고정된다. 대안으로 우리는 몇 가지 축들에 대해 회전을 반복 할 수 있다. 많은 다른 전략들이 있고, 그것들 몇몇은 다른 것들 보다 유용하다. 모든 것은 매우 임의의 수학과 끔찍한 boundary conditions와 너가 생각하기에 그것들이 디버깅 된 후에 충돌할 어려운 상황을 찾는 경향으로 특징지어진다.
Gimbal lock은 너무 중요해서, 그것은 NASA의 아폴로 달 프로그램에 특별히 포함되었다. 우리가 방향에 대해 최종적으로 가지게 될 수학은 이용가능하지 않았고, 오일러 각들이 flight-monitoring 컴퓨터에서 상요되었다. 그 컴퓨터가 gimbal lock에 도달하는 것을 방지하고, 우주선의 방향을 나타내는 것이 불가능하게 되는 것을 방지하기 위해, 제약들이 우주비행사가 통제에 발휘할 수 있는 방식에 가해졌다. 만약 그 우주선이 gimbal lock에 가까워졌다면, 경고음이 들릴 것이다. 우주선이 그 방식으로 방향을 바꿀 수 없는 물리적인 이유는 없었다; 그것은 순전히 NASA의 컴퓨터가 불능이 되는 것을 피하는 예방책이였다. 개인적으로 나는 이것이 유쾌한 교훈으로 받아들인다. 만약 그 NASA의 가장 좋은 두뇌가 gimbal lock을 처리하는 소프트웨어를 쓸 수 없다면, 나는 확실히 시도해보지 않았을 것이다.
운좋게도, 방향을 나타내는 훨씬 더 좋은 방법들이 있다. 그것들은 시각화하기에 직관적이지 않을지도 모르지만, 그것들의 수학은 훨씬더 신뢰할만 하다.
9.2.2 Axis-Angle
삼차원에서 어떤 회전, 또는 회전의 조합은 고정된 축에 대해 단일의 회전으로 나타낼 수 있다. 다시 말해서, 어떤 조합의 회전이 발생했을지라도, 우리는 항상 한 오브젝트의 방향을 축과 각으로 명시할 수 있다.
비록 이것이 즉시 명백하지 않지만, 너는 쉽게 스스로 작은 공으로 그것을 입증할 수 있다. 너가 그 공이 어떻게 방향을 향하든 상관없이, 너는 한 축에 대해 한 번의 회전으로 어떠 ㄴ다른 방향을 하도록 할 수 있다.
우리는 이것은 방향에 대한 표기로서 사용할 수 있다(놀랍지 않게, "axis-angle representation(축-각 표기)"라고 불려진다). 그것은 대강 우리가 2차원을 위해 상요했던 각의 표기와 같고, 몇 가지 문제를 겪는다: 우리는 그 각이 항상 올바른 범위 (-pi, pi]안에 있도록 하기 위해서, 많은 영역 검사를 수행할 필요가 있다.
(축에 대해) 한 벡터와 한 각을 갖는 것은 우리에게 4개의 자유도를 준다. 그 회전은 오직 세 개의 자유도이다. 추가 자유도는 축을 나타내는 벡터가 표준화되는 것을 요구하여 제거된다. 그것은 오직 방향만을 나타낸다.
축과 각을 사용하여 또 다른 가능한 표기는 scaled axis representation이다. 만약 그 축이 표준화 된다면, 그러면 우리는 그 축과 각을 한 벡터에 합칠 수 있다. 그 벡터의 방향은 축을 주고, 그 벡터의 크기는 그 각도를 준다. 그 각도는 그러므로 [0, pi]범위 안에 있다. 우리는 음의 각을 표기할 필요가 없다. 왜냐하면 그것들을 반대 방향의 양의 회전과 같기 때문이다.
그 scaled axis representation은 우리가 가지는 가장 소형의 표기이다. 그것은 세 개의 자유도에 대해 세 개의 값을 갖고, 어떤 방향을 표시할 수 있다. 비록 그것이 angular velocity를 보는 때의 이 챕터의 나중에 우리에게 유용할지라도, 그것은 결코 방향을 나타내기 위해 사용되지 않는다.
2차원 회전의 단일 각 표기를 피했떤 같은 이유 때문이다. 방향의 scaled axis representation을 조작하는데 관련된 수학이 간단하지 않다. 2차원의 경우와 달리, 우리는 걱정해야할 영역이 더 있다: 회전을 쉽게 어떻게 합칠지도 명백하지 않다. 그 축 뿐만 아니라 각도 바뀔 필요가 있기 때문이다.
몇년 전까지, 방향을 나타내는 가장 흔한 방법은 opposite extreme으로 가는 것이였다. 세 개의 값들을 사용하기 보다는, 3x3 matrix가 사용된다.
9.2.3 Rotation Matrices
만약 우리가 회전을 합치는 것의 수학에 관심이 있다면, 그러면 우리는 3D 기하로부터 빌려와서 rotation matrix로 방향을 나타낼 수 있다. 게임에서, 우리는 보통 회전을 나타내기 위해 행렬을 사용한다. 사실, 우리가 무슨 표기를 사용하든, 우리는 그것을 회전행렬로 바꾸고 그것을 그 오브젝트를 그리기 위해 렌더링 엔진에 보내야만 하는것이 사실이다. 시작부터 노력을 아껴서 회전행렬을 사용하지 않는가?
회전 행렬을 사용하는 것은 좋은 솔루션이다; 그리고 우리는 회전 행렬로 어떤 회전이든 나타낼 수 있다. 그 행렬의 원소들은 다음과 같다
여기에서 [x y z]는 축이고; c = cosθ, s = sinθ, t = 1 - cosθ; 이고 θ는 각이다.
그 원소들이 그 각 자체 보다는 각의 sine과 cosine에 관련있기 때문에, 우리는 bounds-checking을 할 필요가 없다. 두 회전을 결합하는 것은 두 행렬을 함께 곱하는 것의 문제이다.
회전 행렬을 사용하는 것의 부작용은 그것들의 초과하는 자유도이다. 우리는 9개의 숫자를 가진 세 개의 자유도의 시스템을 나타내고 있다. 컴퓨터에서 부동소수좀 연산은 전적으로 정확하지 않다. 그래서 그 행렬이 회을 나타내도록 하기 위해 (skew 또는 mirror image와 같은 변환의 다른 종류와 반대로) 그것이 어떤 방식으로 조작되어진 후에, 우리는 그것의 값을 주기적으로 조절할 필요가 있다. 매우 많은 자유도로, 이 조절 프로세스는 우리가 원하는 것보다 더 자주 발생할 필요가 있고, 한 벡터를 표준화 하는 것처럼 사소한 프로세스가 아니다.
이상적으로, 우리는 행렬의 이점을 가지는 표기법을 원한다: 회전의 간단한 조합, 영역 확인이 없고, 더 적은 자유도를 가진 것. 그 해결책, 지금은 거의 어디에나 있는,은 "quaternion"이라는 수학적 구조를 사용하는 것이다.
9.2.4 Quaternions
방향에 대해 가장 좋고, 가장 널리 사용되는 표기법은 quaternion이다. quaternion은 4개의 값으로 방향을 나타낸다. 그리고 그것들은 다음의 방식으로 축과 각에 관련이 있다:
여기에서 [x y z] 축이고, θ는 각이다 이전처럼.
그러나 쿼터니언은 단지 4개의 원소 벡터가 아니다; 그 수학은 좀 더 낯설다. 만약 너가 수학에 알레르기가 있다면, 그러면 이 설명을 자유롭게 건너고, 다음 섹션으로 향해라
너는 고등학교 수학에서 -1의 제곱근에 대해서 배웠을지도 모른다, 소위 허수 (실수와 대조적으로), 종종 i or j로 쓰이는. 그래서 i^2 = -1. 복소수는 그러고나서 하나의 실수와 i의 곱으로 구성되어있다. a + bi의 형태로. 만약 너의 수학에 대한 기억이 좋다면, 너는 복소수를 2차원에 있는 좌표로서 그렸던 것을 상기할지도 모른다, 그리고 그것들의 특징을 기하학적으로 끌어낸 것을 봤을지도 모른다. 복소수들은 기하와 매우 강한 연결성을 가지고있다. 특히 2차원에서의 회전과 관련해서. 만약 너가 기억하지 못한다면, 걱정할 필요 없다 - 쿼터니언은 조금 더 복잡하다.
쿼터니언은 w + xi + yj + zk의 형태의 수이다. 여기에서 i, j, and k 는 모두 허수이다:
i^2 = j^2 =k^2 = -1
모든 것이 함께 곱해질 때, 우리는 또한 -1을 얻는다:
ijk = -1
이러한 것은 쿼터니언 대수의 기본적인 공식들이다. 이 결과의 두 번째 부분은 이러한 허수들의 수 중 두개가 함께가 곱해질 때 세 번째의 것을 준다는 것이다. 그러나 조심해라: 쿼터니언 수학은 교환법칙이 성립하지 않는다. 다시 말해서, ab != ba이다. 특히,
정의에 의해서, 이러한 법칙들과 함께, 우리는 쿼터니언들을 곱으로 합칠 수 있다:
그리고 만약 그 원래 두 개의 쿼터니언들이 방정식 9.4에 따라서 회전을 나타낸다면,
그러면 그 결과 쿼터니언은 합쳐진 두 개의 회전과 같다. 나는 포맷 𝚼 를 사용하여 쿼터니언을 쓸 것이고, 4개의 원소를 가진 벡터 포맷에서, 그것들의 컴포넌트를 보여주기위해서이다:
쿼터니언들은 회전의 3개의 자유도를 나타내기 위해 4개의 자유도를 갖는다. 명백히 우리가 제한할 필요가 있는 추가 자유도를 갖는다.
사실, 모든 회전들에 대해, 방정식 9.4는 쿼터니언의 크기가 정확히 1이라는 것을 암시한다. 우리는 쿼터니언의 크기를 우리가 3개의 원소를 가진 벡터에 대해 했던 것과 정확히 똑같은 방식으로 계산한다. 피타고라스 정리의 4개 컴포넌트 버전을 사용해서:
쿼터니언이 항상 회전을 나타내도록 하기 위해, 우리는 그러므로 그것이 단위 길이를 갖도록 해야만 한다:
우리는 벡터를 표준화하여 쿼터니언의 모든 4개의 컴포넌트에 작용시키는 동일한 절차를 사용하여 이것을 한다. 2차원 회전 처럼, 우리는 우리의 표현에 추가 값을 더하고, 추가 자유도를 제거하기 위해 제약을 추가하고, 우리가 오직 회전만을 얻도록 하여, 끔찍한 영역 검사의 문제를 고쳤다.
우리의 2차원 벡터 표기가 우리에게 원에서의 점을 줬던 똑같은 방식으로, 쿼터니언을 표준화하는 것은 4차원의 구의 표면에 한 점을 주는 것으로 생각되어 질 수 있다. 사실, 많은 쿼터니언 수학들은 4차원 구의 표면 기하를 기반으로 파생될 수 있다. 몇몇 개발자들은 이러한 용어에서 생각하기를 좋아라 할지라도(또는 적어도 그들이 그렇게 주장한다), 개인적으로 나는 4차원 기하가 3차원 회전보다 좀 더 시각화하기에 어렵다고 안다. 그래서 나는 내가 여기에서 주는 대수 공식을 고수하는 경향이 있따.
9.3 Angular Velocity and Acceleration
rigid bodies의 현재 방향을 나타내는 것은 문제의 오직 한 부분이다. 우리는 또한 그것들이 얼마나 빠르고 무슨 방향으로 회전하는지를 추적할 수 있을 필요가 있다.
2차원에 대해, 우리가 각 속도를 위해 bounds-checking을 수행할 필요 없이 단일 값을 쓸 수 있다는 것을 기억해라. 그 같은 것이 3차원의 angular velocity에도 해당된다. 우리는 영역의 문제 때문에 방향에 대한 스케일링 된 axis representation을 포기했었다. 다시 한 번, 우리가 한 오브젝트가 회전하는 속도를 고려할 때, 우리는 bounds가 없다: 그 오브젝트는 그것이 원하는 만큼 빠르게 회전할 수 있다는 것이다.
우리의 솔루션은 각 속도에 대해 scaled axis representation을 고수하는 것이다. 그것은 정확히 올바른 개수의 자유도를 갖고, 그것의 각을 어떤 영역에 유지하는 문제 없이, 그 수학은 효율적인 구현을 위해 충분히 간단하다.
그 각 속도는 한 축과 각 변화의 비율로 분해되어질 수 있는 3개의 요소를 가진 벡터이다:
여기에서 widehat(a) 는 그 오브젝트가 회전하는 축이고, r은 그것이 돌고있는 비율(rate)이다. 그리고 그 비율은 (전통적으로) 초당 radians로 측정된다.
벡터 수학은 angular velocity의 수학과 잘 부합한다. 특히, 만약 우리가 어떤 비율 dot(θ)로 회전하는 오브젝트를 가진다면, 그리고 우리가 그것의 회전에 새로운 방향 ⍵로 어떤 비율의 spin을 더한다면, 그러면 새로운 총 각 속도가 다음으로 주어진다
다시 말해서, 우리는 벡터 대수를 사용해서 함께 두 각 속도를 더할 수 있고, 새롭고, 올바른 각 속도를 얻을 수 있다.
그것은 모두 각 속도를 잘 합치지만, 우리는 또한 각 속도에 의한 방향을 업데이트 시킬 필요가 있다. linear updates에 대해서, 우리는 다음의 공식을 사용한다
우리는 방향과 각 속도에 대해 같은 것을 할 어떤 방법이 필요하다: 벡터와 시간으로 쿼터니언을 업데이트 하기 위해서이다. 그 대응되는 공식은 그리 복잡하지 않다:
여기에서
이것은 0의 w component로 구성된 컴포넌트이고, 그 나머지 컴포넌트들은 각 속도 벡터의 세 개의 컴포넌트로부터 직접 취해진다. 그 구성된 check(omega) 쿼터니언은 방향을 나타내지 않는다. 그래서 그것은 표준화 되어선 안된다.
나는 너가 이것이 꽤 고통이 없는 것이라는 것에 동의하기를 희망한다. 우리는 두 세계의 최상의 것으로부터 이익을 얻을 수 있다: 각 속도에 대한 벡터와 방향에 대한 쿼터니언의 수학적 특성으로 편해는 것이다.
삼차원에서 어떤 회전, 또는 회전의 조합은 고정된 축에 대해 단일의 회전으로 나타낼 수 있다. 다시 말해서, 어떤 조합의 회전이 발생했을지라도, 우리는 항상 한 오브젝트의 방향을 축과 각으로 명시할 수 있다.
비록 이것이 즉시 명백하지 않지만, 너는 쉽게 스스로 작은 공으로 그것을 입증할 수 있다. 너가 그 공이 어떻게 방향을 향하든 상관없이, 너는 한 축에 대해 한 번의 회전으로 어떠 ㄴ다른 방향을 하도록 할 수 있다.
우리는 이것은 방향에 대한 표기로서 사용할 수 있다(놀랍지 않게, "axis-angle representation(축-각 표기)"라고 불려진다). 그것은 대강 우리가 2차원을 위해 상요했던 각의 표기와 같고, 몇 가지 문제를 겪는다: 우리는 그 각이 항상 올바른 범위 (-pi, pi]안에 있도록 하기 위해서, 많은 영역 검사를 수행할 필요가 있다.
(축에 대해) 한 벡터와 한 각을 갖는 것은 우리에게 4개의 자유도를 준다. 그 회전은 오직 세 개의 자유도이다. 추가 자유도는 축을 나타내는 벡터가 표준화되는 것을 요구하여 제거된다. 그것은 오직 방향만을 나타낸다.
축과 각을 사용하여 또 다른 가능한 표기는 scaled axis representation이다. 만약 그 축이 표준화 된다면, 그러면 우리는 그 축과 각을 한 벡터에 합칠 수 있다. 그 벡터의 방향은 축을 주고, 그 벡터의 크기는 그 각도를 준다. 그 각도는 그러므로 [0, pi]범위 안에 있다. 우리는 음의 각을 표기할 필요가 없다. 왜냐하면 그것들을 반대 방향의 양의 회전과 같기 때문이다.
그 scaled axis representation은 우리가 가지는 가장 소형의 표기이다. 그것은 세 개의 자유도에 대해 세 개의 값을 갖고, 어떤 방향을 표시할 수 있다. 비록 그것이 angular velocity를 보는 때의 이 챕터의 나중에 우리에게 유용할지라도, 그것은 결코 방향을 나타내기 위해 사용되지 않는다.
2차원 회전의 단일 각 표기를 피했떤 같은 이유 때문이다. 방향의 scaled axis representation을 조작하는데 관련된 수학이 간단하지 않다. 2차원의 경우와 달리, 우리는 걱정해야할 영역이 더 있다: 회전을 쉽게 어떻게 합칠지도 명백하지 않다. 그 축 뿐만 아니라 각도 바뀔 필요가 있기 때문이다.
몇년 전까지, 방향을 나타내는 가장 흔한 방법은 opposite extreme으로 가는 것이였다. 세 개의 값들을 사용하기 보다는, 3x3 matrix가 사용된다.
9.2.3 Rotation Matrices
만약 우리가 회전을 합치는 것의 수학에 관심이 있다면, 그러면 우리는 3D 기하로부터 빌려와서 rotation matrix로 방향을 나타낼 수 있다. 게임에서, 우리는 보통 회전을 나타내기 위해 행렬을 사용한다. 사실, 우리가 무슨 표기를 사용하든, 우리는 그것을 회전행렬로 바꾸고 그것을 그 오브젝트를 그리기 위해 렌더링 엔진에 보내야만 하는것이 사실이다. 시작부터 노력을 아껴서 회전행렬을 사용하지 않는가?
회전 행렬을 사용하는 것은 좋은 솔루션이다; 그리고 우리는 회전 행렬로 어떤 회전이든 나타낼 수 있다. 그 행렬의 원소들은 다음과 같다
여기에서 [x y z]는 축이고; c = cosθ, s = sinθ, t = 1 - cosθ; 이고 θ는 각이다.
그 원소들이 그 각 자체 보다는 각의 sine과 cosine에 관련있기 때문에, 우리는 bounds-checking을 할 필요가 없다. 두 회전을 결합하는 것은 두 행렬을 함께 곱하는 것의 문제이다.
회전 행렬을 사용하는 것의 부작용은 그것들의 초과하는 자유도이다. 우리는 9개의 숫자를 가진 세 개의 자유도의 시스템을 나타내고 있다. 컴퓨터에서 부동소수좀 연산은 전적으로 정확하지 않다. 그래서 그 행렬이 회을 나타내도록 하기 위해 (skew 또는 mirror image와 같은 변환의 다른 종류와 반대로) 그것이 어떤 방식으로 조작되어진 후에, 우리는 그것의 값을 주기적으로 조절할 필요가 있다. 매우 많은 자유도로, 이 조절 프로세스는 우리가 원하는 것보다 더 자주 발생할 필요가 있고, 한 벡터를 표준화 하는 것처럼 사소한 프로세스가 아니다.
이상적으로, 우리는 행렬의 이점을 가지는 표기법을 원한다: 회전의 간단한 조합, 영역 확인이 없고, 더 적은 자유도를 가진 것. 그 해결책, 지금은 거의 어디에나 있는,은 "quaternion"이라는 수학적 구조를 사용하는 것이다.
9.2.4 Quaternions
방향에 대해 가장 좋고, 가장 널리 사용되는 표기법은 quaternion이다. quaternion은 4개의 값으로 방향을 나타낸다. 그리고 그것들은 다음의 방식으로 축과 각에 관련이 있다:
여기에서 [x y z] 축이고, θ는 각이다 이전처럼.
그러나 쿼터니언은 단지 4개의 원소 벡터가 아니다; 그 수학은 좀 더 낯설다. 만약 너가 수학에 알레르기가 있다면, 그러면 이 설명을 자유롭게 건너고, 다음 섹션으로 향해라
너는 고등학교 수학에서 -1의 제곱근에 대해서 배웠을지도 모른다, 소위 허수 (실수와 대조적으로), 종종 i or j로 쓰이는. 그래서 i^2 = -1. 복소수는 그러고나서 하나의 실수와 i의 곱으로 구성되어있다. a + bi의 형태로. 만약 너의 수학에 대한 기억이 좋다면, 너는 복소수를 2차원에 있는 좌표로서 그렸던 것을 상기할지도 모른다, 그리고 그것들의 특징을 기하학적으로 끌어낸 것을 봤을지도 모른다. 복소수들은 기하와 매우 강한 연결성을 가지고있다. 특히 2차원에서의 회전과 관련해서. 만약 너가 기억하지 못한다면, 걱정할 필요 없다 - 쿼터니언은 조금 더 복잡하다.
쿼터니언은 w + xi + yj + zk의 형태의 수이다. 여기에서 i, j, and k 는 모두 허수이다:
i^2 = j^2 =k^2 = -1
모든 것이 함께 곱해질 때, 우리는 또한 -1을 얻는다:
ijk = -1
이러한 것은 쿼터니언 대수의 기본적인 공식들이다. 이 결과의 두 번째 부분은 이러한 허수들의 수 중 두개가 함께가 곱해질 때 세 번째의 것을 준다는 것이다. 그러나 조심해라: 쿼터니언 수학은 교환법칙이 성립하지 않는다. 다시 말해서, ab != ba이다. 특히,
정의에 의해서, 이러한 법칙들과 함께, 우리는 쿼터니언들을 곱으로 합칠 수 있다:
그리고 만약 그 원래 두 개의 쿼터니언들이 방정식 9.4에 따라서 회전을 나타낸다면,
그러면 그 결과 쿼터니언은 합쳐진 두 개의 회전과 같다. 나는 포맷 𝚼 를 사용하여 쿼터니언을 쓸 것이고, 4개의 원소를 가진 벡터 포맷에서, 그것들의 컴포넌트를 보여주기위해서이다:
쿼터니언들은 회전의 3개의 자유도를 나타내기 위해 4개의 자유도를 갖는다. 명백히 우리가 제한할 필요가 있는 추가 자유도를 갖는다.
사실, 모든 회전들에 대해, 방정식 9.4는 쿼터니언의 크기가 정확히 1이라는 것을 암시한다. 우리는 쿼터니언의 크기를 우리가 3개의 원소를 가진 벡터에 대해 했던 것과 정확히 똑같은 방식으로 계산한다. 피타고라스 정리의 4개 컴포넌트 버전을 사용해서:
쿼터니언이 항상 회전을 나타내도록 하기 위해, 우리는 그러므로 그것이 단위 길이를 갖도록 해야만 한다:
우리는 벡터를 표준화하여 쿼터니언의 모든 4개의 컴포넌트에 작용시키는 동일한 절차를 사용하여 이것을 한다. 2차원 회전 처럼, 우리는 우리의 표현에 추가 값을 더하고, 추가 자유도를 제거하기 위해 제약을 추가하고, 우리가 오직 회전만을 얻도록 하여, 끔찍한 영역 검사의 문제를 고쳤다.
우리의 2차원 벡터 표기가 우리에게 원에서의 점을 줬던 똑같은 방식으로, 쿼터니언을 표준화하는 것은 4차원의 구의 표면에 한 점을 주는 것으로 생각되어 질 수 있다. 사실, 많은 쿼터니언 수학들은 4차원 구의 표면 기하를 기반으로 파생될 수 있다. 몇몇 개발자들은 이러한 용어에서 생각하기를 좋아라 할지라도(또는 적어도 그들이 그렇게 주장한다), 개인적으로 나는 4차원 기하가 3차원 회전보다 좀 더 시각화하기에 어렵다고 안다. 그래서 나는 내가 여기에서 주는 대수 공식을 고수하는 경향이 있따.
9.3 Angular Velocity and Acceleration
rigid bodies의 현재 방향을 나타내는 것은 문제의 오직 한 부분이다. 우리는 또한 그것들이 얼마나 빠르고 무슨 방향으로 회전하는지를 추적할 수 있을 필요가 있다.
2차원에 대해, 우리가 각 속도를 위해 bounds-checking을 수행할 필요 없이 단일 값을 쓸 수 있다는 것을 기억해라. 그 같은 것이 3차원의 angular velocity에도 해당된다. 우리는 영역의 문제 때문에 방향에 대한 스케일링 된 axis representation을 포기했었다. 다시 한 번, 우리가 한 오브젝트가 회전하는 속도를 고려할 때, 우리는 bounds가 없다: 그 오브젝트는 그것이 원하는 만큼 빠르게 회전할 수 있다는 것이다.
우리의 솔루션은 각 속도에 대해 scaled axis representation을 고수하는 것이다. 그것은 정확히 올바른 개수의 자유도를 갖고, 그것의 각을 어떤 영역에 유지하는 문제 없이, 그 수학은 효율적인 구현을 위해 충분히 간단하다.
그 각 속도는 한 축과 각 변화의 비율로 분해되어질 수 있는 3개의 요소를 가진 벡터이다:
여기에서 widehat(a) 는 그 오브젝트가 회전하는 축이고, r은 그것이 돌고있는 비율(rate)이다. 그리고 그 비율은 (전통적으로) 초당 radians로 측정된다.
벡터 수학은 angular velocity의 수학과 잘 부합한다. 특히, 만약 우리가 어떤 비율 dot(θ)로 회전하는 오브젝트를 가진다면, 그리고 우리가 그것의 회전에 새로운 방향 ⍵로 어떤 비율의 spin을 더한다면, 그러면 새로운 총 각 속도가 다음으로 주어진다
다시 말해서, 우리는 벡터 대수를 사용해서 함께 두 각 속도를 더할 수 있고, 새롭고, 올바른 각 속도를 얻을 수 있다.
그것은 모두 각 속도를 잘 합치지만, 우리는 또한 각 속도에 의한 방향을 업데이트 시킬 필요가 있다. linear updates에 대해서, 우리는 다음의 공식을 사용한다
우리는 방향과 각 속도에 대해 같은 것을 할 어떤 방법이 필요하다: 벡터와 시간으로 쿼터니언을 업데이트 하기 위해서이다. 그 대응되는 공식은 그리 복잡하지 않다:
여기에서
이것은 0의 w component로 구성된 컴포넌트이고, 그 나머지 컴포넌트들은 각 속도 벡터의 세 개의 컴포넌트로부터 직접 취해진다. 그 구성된 check(omega) 쿼터니언은 방향을 나타내지 않는다. 그래서 그것은 표준화 되어선 안된다.
나는 너가 이것이 꽤 고통이 없는 것이라는 것에 동의하기를 희망한다. 우리는 두 세계의 최상의 것으로부터 이익을 얻을 수 있다: 각 속도에 대한 벡터와 방향에 대한 쿼터니언의 수학적 특성으로 편해는 것이다.
9.3.1 The Velocity of a Point
섹션 9.1.3에서 우리는 한 오브젝트의 일부의 위치를 계산했었다. 심지어 그것이 움직여지거나 회전되었을 때. 오브젝트 사이의 충돌을 처리하기 위해서, 챕터 14에서, 우리는 또한 한 오브젝트의 어떤 점의 속도를 계산해야만 할 것이다.
한 오브젝트에 있는 한 점의 속도는 그것의 linear and angular velocity 둘 다에 의존한다:
여기에서 dot(q)는 그 점의 속도이고, q는 월드 좌표계에 있는 점의 위치이고, p는 그 오브젝트의 원점의 위치이고, dot(theta)는 그 오브젝트의 angular velocity이다.
만약 우리가 그 오브젝트의 알려진 점의 속도를 계산하기 원한다면 (예를들어, 차의 사이드 미러), 우리는 방정식 9.2로부터 q를 계산할 수 있다.
섹션 9.1.3에서 우리는 한 오브젝트의 일부의 위치를 계산했었다. 심지어 그것이 움직여지거나 회전되었을 때. 오브젝트 사이의 충돌을 처리하기 위해서, 챕터 14에서, 우리는 또한 한 오브젝트의 어떤 점의 속도를 계산해야만 할 것이다.
한 오브젝트에 있는 한 점의 속도는 그것의 linear and angular velocity 둘 다에 의존한다:
여기에서 dot(q)는 그 점의 속도이고, q는 월드 좌표계에 있는 점의 위치이고, p는 그 오브젝트의 원점의 위치이고, dot(theta)는 그 오브젝트의 angular velocity이다.
만약 우리가 그 오브젝트의 알려진 점의 속도를 계산하기 원한다면 (예를들어, 차의 사이드 미러), 우리는 방정식 9.2로부터 q를 계산할 수 있다.
9.3.2 Angular Acceleration
angular acceleration은 angular velocity의 1차 미분이기 때문에, 우리는 가속도와 속도 둘 다에서 같은 벡터 표기를 사용할 수 있다. 게다가, 그것들 사이의 관계는 linear velocity와 acceleration의 것과 같게 남는다. 특히, 우리는 angular velocity를 이 방정식을 사용하여 업데이트 할 수 있다
여기에서 ddot(theta)는 angular acceleration이고 dot(\theta)는 각 속도이다. 이전처럼.
여기에서 ddot(theta)는 angular acceleration이고 dot(\theta)는 각 속도이다. 이전처럼.
9.4 Implementing The Mathematics
우리는 이론을 다루었다. 이제, 올바른 수학을 수행할 수 있는 함수와 자료구조를 구현할 시간이다. 챕터 2에서, 우리는 벡터 수학을 캡슐화 한 Vector3 클래스를 만들었다; 우리는 이제 행렬과 쿼터니언에 대해 같은 것을 할 것이다. 이 과정의 일부로서, 나는 각 유형에 대한 많은 연산의 수학을 소개할 것이다.
만약 너가 존재하는 렌더링 라이브러리로 작업한다면, 너는 이미 행렬, 벡터, 쿼터니언 클래스가 구현되어 있을지도 모른다. 내가 여기에서 주는 구현들에서 physics-specific한 것은 없다. 너는 변경하지 않고 너 자신의 구현을 사용할 수 있어야 한다. 나는 개인적으로 DirectX utility library 구현으로 작업한다 많은 프로젝트에서. 물리 코드의 나머지를 바꿔야 하는 것 없이.
9.4.1 The Matrix Classes
행렬은 스칼라 값의 사각형 배열이다. 그것들은 벡터들이 하는 것과 같은 명백하 기하적 해석을 갖지 않는다. 우리는 그것들을 몇 가지 다른 맥락에서 사용할 것이지만, 각각의 경우에, 그것들을 벡터를 바꾸는데(또는 transform) 사용될 것이다.
비록 행렬이 어떤 크기든 될지라도, 행과 열이 어떤 수가 되어서, 우리는 우선적으로 두 종류에 관심이 있다: 3x3, 3x4 행렬. 행렬을 구현하기 위해, 우리는 어떤 행과 열의 수를 지원할 수 있는 일반 행렬 자료구조를 만들 수 있따. 우리는 가장 일반적인 방식으로 행렬 수학을 구현할 수 있고, 우리의 행렬 타입들 둘 다에 대해 같은 코드를 사용할 수 있다 (그리고 우리가 나중에 필요한 행렬 타입들). 이것이 받아들일만한 전략일지라도, 추가 유연성얼 갖는 것은 최적화하기에 어렵다. 우리가 필요한 행렬의 유형에 대해 특정 자료구조를 만드는 것이 더 낫다. 이것은 우리의 접근법이 될 것이다.
우리는 3x3 행렬에 대해 Matrix3라고 불리는 자료구조를 만들고, 3x4 행렬에 대해 Matrix4라고 불려지는 것을 만들 것이다.
그 기본 Matrix3의 자료구조는 이것처럼 보인다:
그리고 Matrix4에 대한 것은 이것처럼 보인다:
명백히 지금까지 아주 힘든 것은 없다; 우리는 두 개의 숫자 배열을 갖는다.
우리가 chapter 2에서 Vector3 class에 대해 했던 것처럼, 우리는 그것들의 수학을 구현하기 위해 이러한 클래스들에 methods들을 추가한다.
만약 너가 존재하는 렌더링 라이브러리로 작업한다면, 너는 이미 행렬, 벡터, 쿼터니언 클래스가 구현되어 있을지도 모른다. 내가 여기에서 주는 구현들에서 physics-specific한 것은 없다. 너는 변경하지 않고 너 자신의 구현을 사용할 수 있어야 한다. 나는 개인적으로 DirectX utility library 구현으로 작업한다 많은 프로젝트에서. 물리 코드의 나머지를 바꿔야 하는 것 없이.
9.4.1 The Matrix Classes
행렬은 스칼라 값의 사각형 배열이다. 그것들은 벡터들이 하는 것과 같은 명백하 기하적 해석을 갖지 않는다. 우리는 그것들을 몇 가지 다른 맥락에서 사용할 것이지만, 각각의 경우에, 그것들을 벡터를 바꾸는데(또는 transform) 사용될 것이다.
비록 행렬이 어떤 크기든 될지라도, 행과 열이 어떤 수가 되어서, 우리는 우선적으로 두 종류에 관심이 있다: 3x3, 3x4 행렬. 행렬을 구현하기 위해, 우리는 어떤 행과 열의 수를 지원할 수 있는 일반 행렬 자료구조를 만들 수 있따. 우리는 가장 일반적인 방식으로 행렬 수학을 구현할 수 있고, 우리의 행렬 타입들 둘 다에 대해 같은 코드를 사용할 수 있다 (그리고 우리가 나중에 필요한 행렬 타입들). 이것이 받아들일만한 전략일지라도, 추가 유연성얼 갖는 것은 최적화하기에 어렵다. 우리가 필요한 행렬의 유형에 대해 특정 자료구조를 만드는 것이 더 낫다. 이것은 우리의 접근법이 될 것이다.
우리는 3x3 행렬에 대해 Matrix3라고 불리는 자료구조를 만들고, 3x4 행렬에 대해 Matrix4라고 불려지는 것을 만들 것이다.
그 기본 Matrix3의 자료구조는 이것처럼 보인다:
그리고 Matrix4에 대한 것은 이것처럼 보인다:
명백히 지금까지 아주 힘든 것은 없다; 우리는 두 개의 숫자 배열을 갖는다.
우리가 chapter 2에서 Vector3 class에 대해 했던 것처럼, 우리는 그것들의 수학을 구현하기 위해 이러한 클래스들에 methods들을 추가한다.
9.4.2 Matrix Multiplication
내가 벡터를 변환하기 위해 주로 행렬들이 존재한다고 말했으니, 이것을 우선 봐보자. 우리는 한 벡터를 그것에 행렬을 곱하여 변환한다
v' = Mv
그리고 이것은 종종 "post-multiplication"이라고 불려진다. 왜냐하면 그 벡터가 행렬 곱 이후에 발생하기 때문이다.
행렬 곱은 우리가 두 개의 행렬을 곱하든 한 행렬과 벡터를 곱하든 같은 방식으로 작동한다. 사실, 우리는 한 벡터를 간단히 단일의 열을 갖는 행렬로 생각할 수 있다 - 3x1 행렬.
모든 종류의 행렬 곱이 교환 법칙이 성립하지 않는 다는 것을 아는 것은 중요하다. 일반적은 ab != ba이다. 특히, 두 행렬을 곱하기 위해, 첫 번째 행렬의 열의 개수는 두 번째 행렬에서의 행의 개수와 같을 필요가 있다.
.......
일반 행렬곱 설명 생략..
.......
Matrices as Transformations
이 챕터 이전에, 나는 방향을 나타내기 위해 행렬을 사용하는 것에 대해 말했었다. 사실, 행렬은 회전, 스케일링, sheering, 그리고 어떤 다른 변환의 개수든 나타낼 수 있다.
행렬의 원소들은 수행되는 transformation을 통제한다. 그리고 그것들이 어떻게 그것을 하는지 알 가치가 있다. 우리는 행렬을 다음과 같이 생각할 수 있다.
그리고 그것들은 세 개의 벡터로 구성되어 있다.
[a d g] [b e h] [c f i]
이 세 백터들은 세 개의 주된 축인 X, Y, Z 각각이 변환후에 어디를 가리키는지를 나타낸다. 예를들어, 만약 우리가 양의 X축을 따라 가르키는 벡터를 가진다면
그것은 다음의 벡터로 변환될 것이다
그리고 우리는 행렬 곱으로 다음을 입증할 수 있다.
그리고 다른 두 개의 축들에 대해서도 마찬가지이다. 내가 벡터를 소개할 때, 나는 그것들의 세 개의 컴포넌트들이 세 개의 축에 대한 한 위치로 생각되어질 수 있다고 언급했었다. 그 x component는 X축을 따라가는 거리이고 등등이다. 우리는 그 벡터를 이렇게 쓸 수 있다.
다시 말해서, 한 벡터는 각 basic axis의 어떤 비율로 구성된 것이다.
만약 그 세 개의 축이 변환으로 움직인다면, 그러면 그 벡터의 새 위치는 이전과 같은 방식으로 결정될 것이다. 그 축들이 이동했지만, 그 새로운 벡터는 그것들을 같은 비율로 합칠 것이다:
행렬 변환을 축의 한 변화로 생각하는 것은 중요한 시각화 도구이다.
축들의 집합은 "basis(기저)"라고 불려진다. 우리는 chapter 2에서 orthonormal bases를 보았다. 거기에서 그 축들은 모두 1의 길이를 가지고, 서로에게 직각이다. 3x3 matrix는 벡터를 한 기저에서 다른 기저로 변환할 것이다. 이것은 가끔씩 "change of basis(기저 변환)"으로 불려진다.
section 9.1.3의 회전 행렬로 다시 생각해보면, 우리는 headlamp의 position이 어떻게 game level의 위치로 변환되었는지를 봤었따. 이것은 기저 변환이다. 우리는 차의 원점을 기준으로 headlamp의 local coordinates로 시작하고, 게임에서의 headlamp의 world coordinates로 끝난다.
headlamp의 예제에서, 우리는 두 단계를 갖는다: 처음에 우리는 그 오브젝트를 회전시켰다 (행렬 곱을 사용하여 - 기저 변환), 그러고나서 우리는 그것을 평행이동 시킨다 (한 offset vector를 더해서). 만약 우리가 우리의 행렬을 조금 확장시킨다면, 우리는 한 번에 두 단계들을 수행할 수 있다. 이것이 3x4 matrix의 목적이다.
만약 너가 미리 생각했다면, 너는 행렬 곱 법칙들에 의해 우리가 3x4 matrix를 3x1벡터와 곱할 수 없다라는 것을 눈치챘을 지도 모른다. 사실, 이것을 할 것이지만, 3x4 행렬이 무엇을 위해 사용되는지에 대해 좀 더 자세히 볼 필요가 있느 이유를 이해할 필요가 있다.
이전 섹션에서 우리는 transformation matrices를 보았다. 3x3 행렬로서 나타내어질 수 있는 변환은 모두 원점을 같은 장소에 유지한다. 우리의 게임에서 움직임과 회전의 일바넞ㄱ인 조합을 다루기 위해서, 우리는 원점을 움직일 필요가 있다: 차가 그것의 게임 level의 origin에 막혀있다면 차를 모델링 할 필요가 없다. 우리는 이것은 두 단계 프로세스로 할 수 있다: 회전 행렬 곱을 수행하고, 거기에 offset vector를 더해라. 더 좋은 대안은 우리의 행렬을 확장하고 그것을 한 단계로 하는 것이다.
처음에, 우리는 우리의 벡터를 한 원소 더 연장시킨다. 그래서 우리는 4개의 원소를 갖고, 거기에서 마지막 원소는 항상 1이다:
[x y z 1]
벡터에서 4개의 값들은 "homogeneous(동차)" 좌표라고 불려진다. 그리고 그것들은 몇몇 그래픽스 패키지에서 사용된다. 너가 원한다면 너는 그것들을 4차원 좌표로 생각할 수 있다. 비록 4차원으로 생각하는 것은 너에게 우리가 하고 있는 것들을 시가고하하는데 도움이 되지 않을 것이지만.
만약 우리가 3x4 행렬을 취한다면 그리고 일반적인 방식으로 그것을 우리의 4개의 element vector를 곱한다면 다음을 얻게된다.
우리는 두 효과의 조합을 얻는다. 그것은 마치 우리가 3x3 matrix로 처음에 곱한 것과 같다. 그리고나서 베겉를 더한다.
그리고 이것은 정확히 두 단계이고, 우리가 이전에 가졌던 transform-then-move process이다. 그러나 그것은 모두 한 단계로 되었다. 만약 그 처음 세 개의 열이 새로운 기저에 있는 세 개의 축들의 방향을 준다면, 그 네 번째 열은 우리에게 원점의 새로운 위치를 준다.
우리는 또한 이것을 4x4 행렬과 1x4 벡터의 곱으로 볼 수 있다:
다시말해서, 우리는 동차 좌표로 시작하여 끝난다. 우리는 4차원 좌표에 관심이 없기 때문에, 행렬의 마지막 행은 항상 [0 0 0 1]이고, 그 벡터의 마지막 값은 항상 1이다. 우리는 그러므로 방정식 9.6에서 주어진 방정식 버전을 사용할 수 있고, 곱해진 벡터에서 4번 째 값(1)이 필요할 때 마법처럼 나타나게 한다. 우리는 Vector3 class에 네 번째 값을 저장하지 않는다.
...............
행렬 구현에 관한 내용 생략
..............
내가 벡터를 변환하기 위해 주로 행렬들이 존재한다고 말했으니, 이것을 우선 봐보자. 우리는 한 벡터를 그것에 행렬을 곱하여 변환한다
v' = Mv
그리고 이것은 종종 "post-multiplication"이라고 불려진다. 왜냐하면 그 벡터가 행렬 곱 이후에 발생하기 때문이다.
행렬 곱은 우리가 두 개의 행렬을 곱하든 한 행렬과 벡터를 곱하든 같은 방식으로 작동한다. 사실, 우리는 한 벡터를 간단히 단일의 열을 갖는 행렬로 생각할 수 있다 - 3x1 행렬.
모든 종류의 행렬 곱이 교환 법칙이 성립하지 않는 다는 것을 아는 것은 중요하다. 일반적은 ab != ba이다. 특히, 두 행렬을 곱하기 위해, 첫 번째 행렬의 열의 개수는 두 번째 행렬에서의 행의 개수와 같을 필요가 있다.
.......
일반 행렬곱 설명 생략..
.......
Matrices as Transformations
이 챕터 이전에, 나는 방향을 나타내기 위해 행렬을 사용하는 것에 대해 말했었다. 사실, 행렬은 회전, 스케일링, sheering, 그리고 어떤 다른 변환의 개수든 나타낼 수 있다.
행렬의 원소들은 수행되는 transformation을 통제한다. 그리고 그것들이 어떻게 그것을 하는지 알 가치가 있다. 우리는 행렬을 다음과 같이 생각할 수 있다.
그리고 그것들은 세 개의 벡터로 구성되어 있다.
[a d g] [b e h] [c f i]
이 세 백터들은 세 개의 주된 축인 X, Y, Z 각각이 변환후에 어디를 가리키는지를 나타낸다. 예를들어, 만약 우리가 양의 X축을 따라 가르키는 벡터를 가진다면
그것은 다음의 벡터로 변환될 것이다
그리고 우리는 행렬 곱으로 다음을 입증할 수 있다.
그리고 다른 두 개의 축들에 대해서도 마찬가지이다. 내가 벡터를 소개할 때, 나는 그것들의 세 개의 컴포넌트들이 세 개의 축에 대한 한 위치로 생각되어질 수 있다고 언급했었다. 그 x component는 X축을 따라가는 거리이고 등등이다. 우리는 그 벡터를 이렇게 쓸 수 있다.
다시 말해서, 한 벡터는 각 basic axis의 어떤 비율로 구성된 것이다.
만약 그 세 개의 축이 변환으로 움직인다면, 그러면 그 벡터의 새 위치는 이전과 같은 방식으로 결정될 것이다. 그 축들이 이동했지만, 그 새로운 벡터는 그것들을 같은 비율로 합칠 것이다:
행렬 변환을 축의 한 변화로 생각하는 것은 중요한 시각화 도구이다.
축들의 집합은 "basis(기저)"라고 불려진다. 우리는 chapter 2에서 orthonormal bases를 보았다. 거기에서 그 축들은 모두 1의 길이를 가지고, 서로에게 직각이다. 3x3 matrix는 벡터를 한 기저에서 다른 기저로 변환할 것이다. 이것은 가끔씩 "change of basis(기저 변환)"으로 불려진다.
section 9.1.3의 회전 행렬로 다시 생각해보면, 우리는 headlamp의 position이 어떻게 game level의 위치로 변환되었는지를 봤었따. 이것은 기저 변환이다. 우리는 차의 원점을 기준으로 headlamp의 local coordinates로 시작하고, 게임에서의 headlamp의 world coordinates로 끝난다.
headlamp의 예제에서, 우리는 두 단계를 갖는다: 처음에 우리는 그 오브젝트를 회전시켰다 (행렬 곱을 사용하여 - 기저 변환), 그러고나서 우리는 그것을 평행이동 시킨다 (한 offset vector를 더해서). 만약 우리가 우리의 행렬을 조금 확장시킨다면, 우리는 한 번에 두 단계들을 수행할 수 있다. 이것이 3x4 matrix의 목적이다.
만약 너가 미리 생각했다면, 너는 행렬 곱 법칙들에 의해 우리가 3x4 matrix를 3x1벡터와 곱할 수 없다라는 것을 눈치챘을 지도 모른다. 사실, 이것을 할 것이지만, 3x4 행렬이 무엇을 위해 사용되는지에 대해 좀 더 자세히 볼 필요가 있느 이유를 이해할 필요가 있다.
이전 섹션에서 우리는 transformation matrices를 보았다. 3x3 행렬로서 나타내어질 수 있는 변환은 모두 원점을 같은 장소에 유지한다. 우리의 게임에서 움직임과 회전의 일바넞ㄱ인 조합을 다루기 위해서, 우리는 원점을 움직일 필요가 있다: 차가 그것의 게임 level의 origin에 막혀있다면 차를 모델링 할 필요가 없다. 우리는 이것은 두 단계 프로세스로 할 수 있다: 회전 행렬 곱을 수행하고, 거기에 offset vector를 더해라. 더 좋은 대안은 우리의 행렬을 확장하고 그것을 한 단계로 하는 것이다.
처음에, 우리는 우리의 벡터를 한 원소 더 연장시킨다. 그래서 우리는 4개의 원소를 갖고, 거기에서 마지막 원소는 항상 1이다:
[x y z 1]
벡터에서 4개의 값들은 "homogeneous(동차)" 좌표라고 불려진다. 그리고 그것들은 몇몇 그래픽스 패키지에서 사용된다. 너가 원한다면 너는 그것들을 4차원 좌표로 생각할 수 있다. 비록 4차원으로 생각하는 것은 너에게 우리가 하고 있는 것들을 시가고하하는데 도움이 되지 않을 것이지만.
만약 우리가 3x4 행렬을 취한다면 그리고 일반적인 방식으로 그것을 우리의 4개의 element vector를 곱한다면 다음을 얻게된다.
우리는 두 효과의 조합을 얻는다. 그것은 마치 우리가 3x3 matrix로 처음에 곱한 것과 같다. 그리고나서 베겉를 더한다.
그리고 이것은 정확히 두 단계이고, 우리가 이전에 가졌던 transform-then-move process이다. 그러나 그것은 모두 한 단계로 되었다. 만약 그 처음 세 개의 열이 새로운 기저에 있는 세 개의 축들의 방향을 준다면, 그 네 번째 열은 우리에게 원점의 새로운 위치를 준다.
우리는 또한 이것을 4x4 행렬과 1x4 벡터의 곱으로 볼 수 있다:
다시말해서, 우리는 동차 좌표로 시작하여 끝난다. 우리는 4차원 좌표에 관심이 없기 때문에, 행렬의 마지막 행은 항상 [0 0 0 1]이고, 그 벡터의 마지막 값은 항상 1이다. 우리는 그러므로 방정식 9.6에서 주어진 방정식 버전을 사용할 수 있고, 곱해진 벡터에서 4번 째 값(1)이 필요할 때 마법처럼 나타나게 한다. 우리는 Vector3 class에 네 번째 값을 저장하지 않는다.
...............
행렬 구현에 관한 내용 생략
..............
9.4.3 The Matrix Inverse and Transpose
...............
역행렬 및 전치행렬의 내용 및 구현에 관한 생략
..............
...............
역행렬 및 전치행렬의 내용 및 구현에 관한 생략
..............
9.4.4 Converting a Quaternion to a Matrix
행렬 곱 외에도, 우리는 쿼터니언을 행렬로 바꾸는 연산이 필요할 것이다. 너의 그래픽스 엔진은 행렬로 표현되는 변환을 필요할 가능성이 높다. 한 오브젝트를 그리기 위해서, 우리는 그것의 위치벡터와 방향 쿼터니언을 렌더링을 위한 transform matrix로 변환할 필요가 있을 것이다.
가끔씩, 우리는 그 회전 행렬이 그것의 3x3 form에 있기를 원할 것이고, 다른 경우에, 우리는 full transformation matrix(4x4)를 원할 것이다. 각 경우에, 쿼터니언에서 행렬로의 변환은 우리가 9.2.3와 9.2.4에서 본 결과를 사용한다. 거기에서 두 쿼터니언과 회전 행렬은 한 축과 각도의 관점으로 표현된다.
우리는 그 축과 각을 쿼터니언으로부터 재구성하고, 그것에게 방정식 9.3을 줄 수 있다. 만약 우리가 이것을 한다면, 우리는 축과 각들을 간단하게 하고, 쿼터니언의 계수의 관점에서 행렬식을 알 수 있다
{
이거 책에 부호가 잘못나와있다.
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
여기에서 나왔듯이 부호가 다르다. glm::toMat4 함수로 quat ->mat4로 바꾸는 함수도 이 링크에 나와있는대로이다. 책의 부호와 다르다.
데모 코드의 body.cpp에서는 링크의 부호대로 계산이 되어있다.
}
여기에서 w,x,y,z는 쿼터니언의 원소들이다. 구현되어질 때, 3x3 버전으로, 회전을 포함한 것은 이것처럼 보인다.
... 생략 ...
행렬 곱 외에도, 우리는 쿼터니언을 행렬로 바꾸는 연산이 필요할 것이다. 너의 그래픽스 엔진은 행렬로 표현되는 변환을 필요할 가능성이 높다. 한 오브젝트를 그리기 위해서, 우리는 그것의 위치벡터와 방향 쿼터니언을 렌더링을 위한 transform matrix로 변환할 필요가 있을 것이다.
가끔씩, 우리는 그 회전 행렬이 그것의 3x3 form에 있기를 원할 것이고, 다른 경우에, 우리는 full transformation matrix(4x4)를 원할 것이다. 각 경우에, 쿼터니언에서 행렬로의 변환은 우리가 9.2.3와 9.2.4에서 본 결과를 사용한다. 거기에서 두 쿼터니언과 회전 행렬은 한 축과 각도의 관점으로 표현된다.
우리는 그 축과 각을 쿼터니언으로부터 재구성하고, 그것에게 방정식 9.3을 줄 수 있다. 만약 우리가 이것을 한다면, 우리는 축과 각들을 간단하게 하고, 쿼터니언의 계수의 관점에서 행렬식을 알 수 있다
{
이거 책에 부호가 잘못나와있다.
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
여기에서 나왔듯이 부호가 다르다. glm::toMat4 함수로 quat ->mat4로 바꾸는 함수도 이 링크에 나와있는대로이다. 책의 부호와 다르다.
데모 코드의 body.cpp에서는 링크의 부호대로 계산이 되어있다.
}
여기에서 w,x,y,z는 쿼터니언의 원소들이다. 구현되어질 때, 3x3 버전으로, 회전을 포함한 것은 이것처럼 보인다.
... 생략 ...
9.4.5 Transforming Vectors
... 생략 ...
... 생략 ...
9.4.6 Changing The Basis of A Matrix
아직 다뤄지지 않은 행렬로 할 필요가 있는 한 가지 마지막 것이 있다. 우리가 transformation matrix를 한 기저에서 다른 기저로 바꾸는 것으로 생각할 수 있다는 것을 회상해라. 즉, 한 축들의 집합에서 다른 집합으로. 만약 그 transformations이 3x4 matrix라면, 그러면 그 변화는 또한 원점에서의 변화를 포함한다. 우리는 이 transformation을 한 기저에서 다른 기저로 한 벡터를 변경하기 위해 사용했었다.
우리는 또한 한 기저에서 다른 기저로 전체 행렬을 변환시킬 필요가 있는 상황을 만날 것이다. 이것은 시각화 하기에 좀 더 어려울 수 있다.
행렬 M_t을 가지고 있다고 가정하자. 그것은 그림 9.6의 첫 번째 부분에 보여지듯이, 몇 가지 transformation을 수행한다 (그림은 편의를 위해 2D에 있지만, 그 같은 원리가 3D에 적용된다). 그것은 원점에 대해 작은 회전을 수행한다; 그 그림의 part A는 회전되는 한 오브젝트를 보여준다.
이제 우리가 다른기저를 가진다고 가정하자, 하지만 우리는 정확히 같은 transformation을 원한다. 우리의 새로운 기저에서, 우리는 같은 효과를 갖는 transformation을 찾고 싶다 (즉, 그것은 그 오브젝트가 같은 최종 위치로 남겨둔다), 그러나 새로운 좌표계로 작동하길 원한다. 이것은 그림 9.6의 part B에서 보여진다; 이제 원점은 이동했고(우리는 다른 기저에 있다), 그러나 우리는 그 변환의 효과가 같아지길 원한다. 명백히, 만약 우리가 새로운 기저에서 M_t를 적용했다면, 그것은 다른 최종 결과를 줄 것이다.
우리가 우리의 원래 기저 B_1과 새로운 기저 B_2사이에 transformation M_b를 가진다고 해보자. M_t가 B_1에서주는 행동을 새로운 B_2에서 복사하는 M_t와 M_b로부터 새로운 transformation을 만들 수 있는 방법이 있는가?
그 솔루션은 세 단계 프로세스에 있는 M_b와 (M_b)^-1 이다:
아직 다뤄지지 않은 행렬로 할 필요가 있는 한 가지 마지막 것이 있다. 우리가 transformation matrix를 한 기저에서 다른 기저로 바꾸는 것으로 생각할 수 있다는 것을 회상해라. 즉, 한 축들의 집합에서 다른 집합으로. 만약 그 transformations이 3x4 matrix라면, 그러면 그 변화는 또한 원점에서의 변화를 포함한다. 우리는 이 transformation을 한 기저에서 다른 기저로 한 벡터를 변경하기 위해 사용했었다.
우리는 또한 한 기저에서 다른 기저로 전체 행렬을 변환시킬 필요가 있는 상황을 만날 것이다. 이것은 시각화 하기에 좀 더 어려울 수 있다.
행렬 M_t을 가지고 있다고 가정하자. 그것은 그림 9.6의 첫 번째 부분에 보여지듯이, 몇 가지 transformation을 수행한다 (그림은 편의를 위해 2D에 있지만, 그 같은 원리가 3D에 적용된다). 그것은 원점에 대해 작은 회전을 수행한다; 그 그림의 part A는 회전되는 한 오브젝트를 보여준다.
이제 우리가 다른기저를 가진다고 가정하자, 하지만 우리는 정확히 같은 transformation을 원한다. 우리의 새로운 기저에서, 우리는 같은 효과를 갖는 transformation을 찾고 싶다 (즉, 그것은 그 오브젝트가 같은 최종 위치로 남겨둔다), 그러나 새로운 좌표계로 작동하길 원한다. 이것은 그림 9.6의 part B에서 보여진다; 이제 원점은 이동했고(우리는 다른 기저에 있다), 그러나 우리는 그 변환의 효과가 같아지길 원한다. 명백히, 만약 우리가 새로운 기저에서 M_t를 적용했다면, 그것은 다른 최종 결과를 줄 것이다.
우리가 우리의 원래 기저 B_1과 새로운 기저 B_2사이에 transformation M_b를 가진다고 해보자. M_t가 B_1에서주는 행동을 새로운 B_2에서 복사하는 M_t와 M_b로부터 새로운 transformation을 만들 수 있는 방법이 있는가?
그 솔루션은 세 단계 프로세스에 있는 M_b와 (M_b)^-1 이다:
- 우리는 transformation (M_b)^-1을 수행하고, 이것은 우리가 B_2에서 B_1으로 돌아가게 해준다.
- 우리는 그러고나서 원래 transform M_t를 수행한다. 왜냐하면 우리가 지금 basis B_1에 있기 때문이다. 그리고 거기에서 그것은 원래 옳다.
- 그러고나서 우리는 basis B_2로 돌아간다. 그래서 우리는 M_b transformation을 적용한다.
그래서 우리는 다음으로 끝나게 된다:
{
즉, M_t' 가 transformation matrix라는 것을 주의하자. 즉 선형대수에서 배웠듯이,
transformation을 할 때 기본형식은 Ax인데, 여기에서 A는 M_t'가 되고, x는 변환할 좌표 벡터가 되는 것이다.
그래서 (M_b)^-1을 그 벡터에 적용시켜 x벡터를 b_1기저로 변경시킨다. 여기에서 그러면 x벡터 또한 b_2기저에 있다는 것이 implicitly하게 정의되어있다. 그리고 b_1 기저에서 M_t 행렬로 변환하고, 다시 M_b로 바꾼다.
}
곱해진 행렬들이 역순으로 실행되는 transformations과 같다는 것을 염두에 두어라.
우리는 우리가 한 기저에서 표현되는 행렬을 가지고 다른 기저에서 그것을 필요할 때 마다 이 함수를 사용할 필요가 있다. 우리는 우리가 이미 구현한 곱과 역행렬 함수를 사용하여 이것을 할 수 있다: 특수화된 함수는 필요없다. 특히, 그 기법이 다음 챕터에서 우리가 rigid body의 inertia tensor로 작업할 때 반드시 필수적일 것이다. 그 단계에서, 나는 수학을 간단하게 하는 inertia tensor의 어떤 다른 특징을 이용하는, 세부적인 구현을 제공할 것이다.
9.4.7 The Quaternion Class
우리는 행렬에 대해 기본 수학 연산을 다루었고, 튼튼한 Matrix와 Vector class를 구현시켰다. 우리가 넘어가기 전에, 우리는 quaternions를 조작하는 자료구조를 만들 필요가 있다.
이 섹션에서, 우리는 Quaternion class를 만들 것이다. 그 기본 자료구조는 이것처럼 보인다:
우리는 행렬에 대해 기본 수학 연산을 다루었고, 튼튼한 Matrix와 Vector class를 구현시켰다. 우리가 넘어가기 전에, 우리는 quaternions를 조작하는 자료구조를 만들 필요가 있다.
이 섹션에서, 우리는 Quaternion class를 만들 것이다. 그 기본 자료구조는 이것처럼 보인다:
9.4.8 Normalizing Quaternions
우리가 이전에 말 했듯이, 쿼터니언들은 그것들이 1의 크기를 갖는다면 한 회전만을 나타낸다. 우리가 수행할 모든 연산들은 1의 크기를 유지하지만, numerical inaccuracies and rounding errors는 이 제약이 시간에 따라 위반되도록 일으킬 수 있다. 가끔, 쿼터니언을 다시 표준화하는 것은 (renormalize) 좋은 아이디어이다. 우리는 다음의 방식으로 이것을 수행할 수 있다.
우리가 이전에 말 했듯이, 쿼터니언들은 그것들이 1의 크기를 갖는다면 한 회전만을 나타낸다. 우리가 수행할 모든 연산들은 1의 크기를 유지하지만, numerical inaccuracies and rounding errors는 이 제약이 시간에 따라 위반되도록 일으킬 수 있다. 가끔, 쿼터니언을 다시 표준화하는 것은 (renormalize) 좋은 아이디어이다. 우리는 다음의 방식으로 이것을 수행할 수 있다.
9.4.9 Combining Quaternions
우리는 두 개의 쿼터니언들을 곱하여, 두 개의 쿼터니언들을 결합한다. 이것은 정확히 회전(또는 다른 transformation) matrix와 정확히 같다: check(qp)의 결과는 p의 회전을 처음에 수행하고, 그러고나서 q는 와 동일하다.
우리는 section 9.2.4에서 보았듯이, 두 쿼터이너의 곱은 다음의 형태를 갖는다
우리는 두 개의 쿼터니언들을 곱하여, 두 개의 쿼터니언들을 결합한다. 이것은 정확히 회전(또는 다른 transformation) matrix와 정확히 같다: check(qp)의 결과는 p의 회전을 처음에 수행하고, 그러고나서 q는 와 동일하다.
우리는 section 9.2.4에서 보았듯이, 두 쿼터이너의 곱은 다음의 형태를 갖는다
9.4.10 Rotating
때때로, 우리는어떤 주어진 양만큼 쿼터니언을 회전시킬 필요가 있다. 만약 한 쿼터니언이 한 오브젝트의 방향을 나타낸다면, 그리고 우리가 그것을 회전시켜서 방향을 바꿀 필요가 있다면, 우리는 그 방향을 변환시켜서, 그 요구되는 회전을 행렬로 바꿀 수 있고, 그것들을 곱할 수 있다. 그러나 이것을하는 좀 더 직접적인 방법이 있다.
회전의 양은 가장 간단히 벡터로 표현된다(회전의 양은 제한이 없기 때문에, 우리가 angular velocity에 대해 보았듯이). 우리는 그러고나서 이 방정식을 사용하여 쿼터니언을 바꿀 수 있다
그리고 이것은 우리가 section 9.3에서 본 방정식과 같다, 그러나 velocity * time을 단일의 절대 angular change (θ)로 바꾼다.
여기에서, anuglar velocity의 경우에서 처럼, 그 회전은 표준화되지 않은 쿼터니언으로 변경된 한 벡터로서 제공된다:
[Δθ_x, Δθ_y, Δθ_z] -> [0, Δθ_x, Δθ_y, Δθ_z]
이것은 다음으로 구현되어질 수 있다.
때때로, 우리는어떤 주어진 양만큼 쿼터니언을 회전시킬 필요가 있다. 만약 한 쿼터니언이 한 오브젝트의 방향을 나타낸다면, 그리고 우리가 그것을 회전시켜서 방향을 바꿀 필요가 있다면, 우리는 그 방향을 변환시켜서, 그 요구되는 회전을 행렬로 바꿀 수 있고, 그것들을 곱할 수 있다. 그러나 이것을하는 좀 더 직접적인 방법이 있다.
회전의 양은 가장 간단히 벡터로 표현된다(회전의 양은 제한이 없기 때문에, 우리가 angular velocity에 대해 보았듯이). 우리는 그러고나서 이 방정식을 사용하여 쿼터니언을 바꿀 수 있다
그리고 이것은 우리가 section 9.3에서 본 방정식과 같다, 그러나 velocity * time을 단일의 절대 angular change (θ)로 바꾼다.
여기에서, anuglar velocity의 경우에서 처럼, 그 회전은 표준화되지 않은 쿼터니언으로 변경된 한 벡터로서 제공된다:
[Δθ_x, Δθ_y, Δθ_z] -> [0, Δθ_x, Δθ_y, Δθ_z]
이것은 다음으로 구현되어질 수 있다.
class Quaternion { void rotateByVector(constVector& vector) { Quaternion q(0, vector.x * scale, vector.y * scale, vector.z* scale); (*this) *= q; } }
9.4.11 Updating by the angular velocity
우리가 할 필요가 있는 최종 연산은 특정 time duration 동안 angular velocity를 적용하여 방향 쿼터니언을 업데이트 하는 것이다. 섹션 9.3에서, 우리는 이것이 그 방정식으로 다뤄지는 것을 보았었다
여기에서 check(omega)는 angular velocity의 쿼터니언 형태이고, t는 업데이트 할 duration이다. 이것은 다음으로 구현되어질 수 있다.
우리는 이제 엔진의 나머지를 위해 필요한 모든 기능을 포함하는 Quaternion class를 가지고 있다. 벡터와 행렬로, 우리가 더할 수 있는 많은 다른 연사들이 있다 - 좀 더 많은 변환, 다른 수학적 연산자들. 만약 너가 존재하는 quaternion library를 사용한다면, 그것은 정의된 다른 함수들이 있을 것이지만, 우리는 그것들이 필요하지 않을 것이기 때문에, 나는 우리가 사용하지 않을 구현을 주는 것을 피할 것이다.
여기에서 check(omega)는 angular velocity의 쿼터니언 형태이고, t는 업데이트 할 duration이다. 이것은 다음으로 구현되어질 수 있다.
class Quaternion { void addScaledVector(const Vector3& vector, real scale) { Quaternion q(0, vector.x * scale, vector.y * scale, vector.z * scale); q *= *this; r += q.r * ((real)0.5); i += q.i * ((real)0.5); j += q.j * ((real)0.5); k += q.k * ((real)0.5); } }
우리는 이제 엔진의 나머지를 위해 필요한 모든 기능을 포함하는 Quaternion class를 가지고 있다. 벡터와 행렬로, 우리가 더할 수 있는 많은 다른 연사들이 있다 - 좀 더 많은 변환, 다른 수학적 연산자들. 만약 너가 존재하는 quaternion library를 사용한다면, 그것은 정의된 다른 함수들이 있을 것이지만, 우리는 그것들이 필요하지 않을 것이기 때문에, 나는 우리가 사용하지 않을 구현을 주는 것을 피할 것이다.
9.5 Summary
우리는 이 챕터에서 긴 길을 걸어왔고, 만약 너가 행렬과 쿼터니언에 이전에 익숙하지 않았다면, 그러면 이것은 큰 걸음이였다. 우리는 이제 우리의 최종 물리 엔진 동안 우리가 봐야할 모든 수학을 만났다.
이 챕터에서, 나는 이 수학의 몇몇이 엔진에서 사용되는 방식으로 알려주었다. Chapter 10은 linear motion뿐만 아니라 angular motion이 있는 full 3D rigid bodies를 지원하기 위해 우리의 엔진을 재구성하기 시작한다.
이 챕터에서, 나는 이 수학의 몇몇이 엔진에서 사용되는 방식으로 알려주었다. Chapter 10은 linear motion뿐만 아니라 angular motion이 있는 full 3D rigid bodies를 지원하기 위해 우리의 엔진을 재구성하기 시작한다.
댓글 없음:
댓글 쓰기