Home 1. 3D Transform
Post
Cancel

1. 3D Transform

3D Transform


서론


어쩌다보니 다시는 공부하지 않고 싶었던 수학을 또 다시 공부하게 되었습니다.

Untitled

다시 한 번…. 해봅시다..

3차원 공간의 설계


좌표계


일반적으로 3D 그래픽 응용 프로그램은 왼손 및 오슨론의 두가지 유형의 데카르트 좌표계를 사용합니다. 두 좌표계에서 양의 X축은 오른쪽을 가리키고 양의 Y축은 위쪽을 가르킵키다.

위의 두 시스템이 가장 일반적인 시스템이지만, 3D소프트웨어에 사용되는 다양한 다른 좌표 시스템도 존재합니다. 양의 Y축이 앞을 가리키고, Z축이 위쪽을 가리키는 좌표계를 사용하는것도 드문 일이 아닙니다.

따라서 3D소프트웨어에 사용되는 좌표시스템의 정리를 인용해 보았습니다.

https://twitter.com/FreyaHolmer/status/1325556229410861056?s=20

왜 이런 차이가 나는걸까요?


왼손 좌표계와 오른손 좌표계

엔진은 주로 왼손, 설계 작업툴은 오른손을 사용하는 것으로 보입니다.

2차원의 수학적 관례에 따라 x축을 오른쪽으로, y축을 위쪽으로 두게 된다면

큰 차이는 정면(z축)의 방향으로 볼 수 있습니다.

여기서 잠깐, 수학적 관례가 아닌 디스플레이 관점에서는 디스플레이가 브라운관(음극선관)을 사용하던 시절에는 전자빔에 의해 위에서 아래로, 왼쪽에서 오른쪽으로 표시되었는데(https://youtu.be/3BJU2drrtCM), 그래서 몇몇의 2차원 화면 평면 좌표계를 Y - Down (아래로 갈수록 값이 커짐) , X - Right(오른쪽으로 갈수록 값이 커짐)로 사용하는 것일지도 모르겠습니다.

이때 카메라를 두게 된다면, 엔진의 입장에서는 카메라를 주로 되고, 설계의 입장에서는 물체를 관찰해야하므로 물체의 정면을 카메라가 관찰하는 상황에서, 물체입장에서의 정면이 카메라의 뒤를 향하는 형태를 띄게됩니다.

다시 정리해 본다면 ‘물체의 우선순위가 높은가’ 아니면 ‘카메라의 우선순위가 높은가’에 따라 설정했다고 추측할 수 있습니다.

Y업과 Z업

현대 CAD 시스템은 대부분 오른손 좌표계를 사용합니다. 이유는 위와 같이 유추하였을 때,

시스템 설계자는 XY평면의 방향을 결정해야 했을 것입니다.

저는 여기서 XY평면이 ‘토목 및 건축’ 분야에 대해서는 일반적으로 위에서 아래를 내려다보는 설계도와 같은 평면을 설정하기 위해 Y축이 정면을 향하였다고 생각합니다.

그리고 추가된 Z축이 높이를 향하게 된 것이라고 추측해 봅니다.

3차원 공간의 트랜스폼


이동(Translate) & 크기(Scale)


사실 3차원이라고 하여도 별거 없습니다.

2차원에서 하였던 내용(이동,크기)을 한번 되새기고,

이동은 똑같이 아핀공간에서의 밀기를,

크기는 크기행렬을 짜주면 됩니다.

T=[100tx010ty001tz0001]T= \left[ \begin{matrix} 1&0&0&t_x\\ 0&1&0&t_y\\ 0&0&1&t_z\\ 0&0&0&1\\ \end{matrix} \right] S=[sx0000sy0000sz00001]S= \left[ \begin{matrix} s_x & 0 & 0 & 0\\ 0 & s_y & 0 & 0\\ 0 & 0 & s_z & 0\\ 0 & 0 & 0 & 1\\ \end{matrix} \right]

회전(Rotation)


… 하지만 회전은 답이 없습니다.

왜 답이 없는가. 그 이유를 한번 살펴보려 합니다.

표준기저벡터를 통한 회전 변환 행렬

일단 회전 역시 결국 차원만큼의 기저벡터를 통해 기저를 나타낸다면 회전량을 알 수 있습니다.

그리고 모든 방향은 벡터로 나타 낼 수 있죠. 예를들어 Y-UP 왼손 좌표계에서 정면은 (0,0,1)입니다.

이게 z기저벡터가 되는 것이죠. 그전에 잠깐, 회전행렬은 직교행렬이므로 조건이 존재합니다

Rotation matrices are square matrices, with real entries. More specifically, they can be characterized as orthogonal matrices with determinant 1; that is, a square matrix RR is a rotation matrix if and only if RTR^T = R1R^{−1} and det RR = 1.

https://en.wikipedia.org/wiki/Rotation_matrix

정리하면 다음과 같습니다.

Untitled

다음과 같은 세 기저 벡터를 가진 행렬을 작성한다면 다음과 같습니다.

M=[1000010000100001]M= \left[ \begin{matrix} 1&0&0&0\\ 0&1&0&0\\ 0&0&1&0\\ 0&0&0&1\\ \end{matrix} \right]

이렇게 생성한 세 기저 벡터의 값을 변경하여 보겠습니다. (벡터의 길이는 1이되어야하지만, 일단 소숫점 3번째 자리에서 반올림하겠습니다)

Untitled

M=[0.920.310.2500.250.930.2600.310.170.9300001]M= \left[ \begin{matrix} 0.92&0.31&-0.25&0\\ -0.25&0.93&0.26&0\\ 0.31&-0.17&0.93&0\\ 0&0&0&1\\ \end{matrix} \right]

와! 정말 보기 흉합니다. 이걸로 어느정도의 각 회전이 발생했는지 쉽게 알 수 있을까요?

저는 각 축마다 몇도씩 회전시킨걸까요?

오일러각 (Euler Angles)


오일러각의 필요성


아까보았던 세개의 표준기저벡터를 사용한 행렬은 보기만 해도 끔찍합니다.

Untitled

마치 각이 아닌 유사도를 보는 것 같아요.

2차원에서는 저희는 어떻게 회전을 표현하였었죠?

(2차원의 회전변환)

2차원에서는 값이 아니라 각 θ\theta 에 대한 식으로 나타내었었군요!

즉 회전행렬은 따지고보자면 수치 자체를 θ\theta 에 대한 식으로 나타낸 것입니다.

마찬가지로 오일러 각 또한 각 축을 제외한 평면에 대한 회전값을 식으로 나타낸 것입니다.

그렇다면 연산은 좀 하더라도 더 나은 방법으로 볼 수 있겠네요.

오일러각. 요로코롬 절차적으로 회전시킵니다.

오일러각. 요로코롬 절차적으로 회전시킵니다.

오일러 각 회전을 통해 얻는 장점


아무래도 사람이 보기에 ‘직관적’ 이라는 부분이 가장 크다고 생각합니다.

아까전에 봤던 끔찍한 3개의 단순 기저벡터의 값은 오일러각으로 본다면 다음과 같습니다

rotation:(15,15,15)rotation : (-15,-15,-15)

다시 한 번 값을 확인해볼까요?

M=[0.920.310.2500.250.930.2600.310.170.9300001]M= \left[ \begin{matrix} 0.92&0.31&-0.25&0\\ -0.25&0.93&0.26&0\\ 0.31&-0.17&0.93&0\\ 0&0&0&1\\ \end{matrix} \right]

Untitled

Untitled

Untitled

Untitled

\therefore직관성』

표현방법


이에 대해서 엔진에서 각 회전을 표현할 때, Unity는 단순 부동소숫점 3개(Vector3)로 표현을, Unreal은 rotator이라는 구조체를 사용합니다.

자 여기서 rotator을 조금 더 파고들어 봅시다.

Rotator


Aircraft principal axes

왜 Rotator라는 것이 필요하였을까?


축에 대한 회전은 좌표계가 달라지면 어떻게 회전되었는지 알 수 없습니다.

위가 아래가 되고, 위아래가 뒤집혀 오른쪽이라 생각하는게 왼쪽이 되어버리면 알 수 없습니다.

즉 로컬 수준에서 알 수 있는 좌표계가 필요한 것이죠.

마치 저희가 어떠한 회전을 하더라도 오른쪽손은 바뀌지 않듯 말입니다.

따라서 회전에 대해 Roll, Pitch, Yaw 회전을 사용합니다.

Aircraft principal Axes

Aircraft principal Axes

이것 또한 이동 회전 크기 행렬의 곱과 마찬가지로 각 축의 회전을 세번 곱할 것인데,

왜 Roll pitch Yaw 순으로 적용하는지에 대해 조금 생각해보았습니다.

해당 Roll Pitch Yaw 회전법은 항공학에서 시작되었다고 하는데, 거기서 생각해본다면 모든 날개의 Flap을 사용해서 얻을 수 있는 회전의 크기를 기준으로 설정하였다고 봅니다.

Untitled

Pitch : 승강타(Elevator) 조작, 핸들의 밀기 혹은 당기기

Pitch : 승강타(Elevator) 조작, 핸들의 밀기 혹은 당기기

Yaw : 방향타(Rudder) 조작, 좌우 페달

Yaw : 방향타(Rudder) 조작, 좌우 페달

Roll : 보조익(Aileron) 조작, 핸들의 회전

Roll : 보조익(Aileron) 조작, 핸들의 회전

Roll의 경우는 보조익(Aileron, 주익의 끝 플랩)을 통해,

Pitch의 경우 승강타(Elevator, 미익의 수평 플랩),

yaw의 경우 방향타(Rudder, 미익의 수직 플랩)를 통해 회전이 이루어 질 수 있기 때문에

플립 혹은 회전의 크기순 내림차순 정렬을 했다고 생각을 합니다.

그리고 중요한점. 이렇게 생각을 한번 하고 나면 Roll - Pitch - Yaw가 헷갈리지 않습니다.

순서는 기억했고, 이게 이제 어떤플랩으로 인하여 회전하는가를 기억한다면 단순하게 플랩 크기로 매핑하면 되기 때문이죠 하하.

오일러 각 회전을 구성하는 세개의 회전 변환


이걸 이제 세 개의 회전변환 행렬로써 표현해 보겠습니다.

기준은 다음과 같이 하겠습니다.

  1. 오른손 좌표계에서 볼때
  2. +방향에서 -방향을 보았을 때
Roll=Rotz=[cosθsinθ0sinθcosθ0001]Roll = Rot_z= \left[ \begin{matrix} cos{\theta}&-sin{\theta}&0\\ sin{\theta}&cos{\theta}&0\\ 0&0&1\\ \end{matrix} \right]

xy평면을 기준으로 x to y 회전을 표현합니다.

Pitch=Rotx=[1000cosθsinθ0sinθcosθ]Pitch = Rot_x= \left[ \begin{matrix} 1&0&0\\ 0&cos{\theta}&-sin{\theta}\\ 0&sin{\theta}&cos{\theta}\\ \end{matrix} \right]

yz평면을 기준으로 y to z 회전을 표현합니다.

Yaw=Roty=[cosθ0sinθ010sinθ0cosθ]Yaw = Rot_y= \left[ \begin{matrix} cos{\theta}&0&sin{\theta}\\ 0&1&0\\ -sin{\theta}&0&cos{\theta}\\ \end{matrix} \right]

xz평면을 기준으로 z to x 회전을 표현합니다. 즉 생각하는 평면(xz)과 실제 바라보는 평면(zx)가 달라, 여기서 뒤집히게(전치) 되어, 상식적으로 생각하는 회전행렬의 기저와 달라지게 됩니다.

최종 회전 행렬


이를 통해 최종적으로 오일러 각 정보를 받아 세 로컬축을 계산한 다음, 기저 벡터를 회전행렬로 사용함으로써 기존과 같이 TRS행렬을 만들어 적용하면 됩니다.

그러나 그 세 로컬축의 합성이 힘들죠.

한번 시작해 봅시다.

저는 3차원 게임세상에서 Roll은 거의 발생하지 않고,

좌우 회전을 많이 한다고 믿는 사람이기 때문에

(또한 팔의 좌우 움직임이 상하 움직임 보다 쉽죠.

롤에서 블루팀 바텀 라인전이 퍼플팀보다 쉽게 느껴지는 이유입니다.)

Yaw→Pitch→Roll 이라는 형태로 합성해 보겠습니다.

하하 Roll→Pitch→Yaw 로 사용하실려면 단순하게 전치하시면 됩니다.

TRS 뒤집는거 해보셨잖아요?

RotzRotxRoty=[cosθzsinθz0sinθzcosθz0001][1000cosθxsinθx0sinθxcosθx][cosθy0sinθy010sinθy0cosθy]=[cosθzcosθxsinθzsinθxsinθzsinθzcosθxcosθzsinθx(cosθz)0sinθxcosθx][cosθy0sinθy010sinθy0cosθy]=[cosθycosθzsinθxsinθysinθzcosθxsinθzsinθxcosθysinθz+sinθycosθzsinθxsinθycosθz+cosθysinθzcosθxcosθzsinθysinθzsinθxcosθycosθzcosθxsinθysinθxcosθxcosθy]Rot_z \cdot Rot_x \cdot Rot_y \\ = \left[\begin{matrix} cos{\theta_z}&-sin{\theta_z}&0\\sin{\theta_z}&cos{\theta_z}&0\\0&0&1\\ \end{matrix}\right] \cdot \left[\begin{matrix} 1&0&0\\0&cos{\theta_x}&-sin{\theta_x}\\0&sin{\theta_x}&cos{\theta_x}\\ \end{matrix}\right] \cdot \left[\begin{matrix} cos{\theta_y}&0&sin{\theta_y}\\0&1&0\\-sin{\theta_y}&0&cos{\theta_y}\\ \end{matrix}\right] \\= \left[\begin{matrix} cos\theta_z & -cos\theta_x sin\theta_z & sin\theta_x sin\theta_z \\sin\theta_z & cos\theta_x cos\theta_z & sin\theta_x (-cos\theta_z)\\0 & sin\theta_x & cos\theta_x \end{matrix}\right] \cdot \left[\begin{matrix}cos{\theta_y}&0&sin{\theta_y}\\0&1&0\\-sin{\theta_y}&0&cos{\theta_y}\\\end{matrix}\right] \\ = \left[\begin{matrix}cos\theta_y cos\theta_z - sin\theta_x sin\theta_y sin\theta_z & -cos\theta_x sin\theta_z & sin\theta_x cos\theta_y sin\theta_z + sin\theta_y cos\theta_z\\sin\theta_x sin\theta_y cos\theta_z + cos\theta_y sin\theta_z & cos\theta_x cos\theta_z & sin\theta_y sin\theta_z - sin\theta_x cos\theta_y cos\theta_z\\-cos\theta_x sin\theta_y & sin\theta_x & cos\theta_x cos\theta_y\end{matrix}\right]

오…


계산 후 수식 편집하다가 깨달은게 몇가지 있습니다.

(노션의 수식편집기는 잘못누르면 날라가서 좋아하지 않습니다.)

왼쪽 저 스크롤의 긴 줄이 보이십니까? 저거 다 수식입니다.

왼쪽 저 스크롤의 긴 줄이 보이십니까? 저거 다 수식입니다.

사랑해요 VSCode!! , 사랑해요 Markdown All in One!!

Untitled

아주 좋은 프로그램입니다. 아주 좋은 프로그램입니다. 정말 이거 없었으면 이번 게시글 작성이 아주 힘들었을 것이라고 생각합니다.


후 아무튼, 비교를 한번 해봅시다.

링크 : https://en.wikipedia.org/wiki/Euler_angles#Tait–Bryan_angles

저는 Yaw→Pitch→Roll로 곱했기 때문에 ZXY이며, 따라서 다음 값을 보면 됩니다.

Untitled

[cosθycosθzsinθxsinθysinθzcosθxsinθzsinθxcosθysinθz+sinθycosθzsinθxsinθycosθz+cosθysinθzcosθxcosθzsinθysinθzsinθxcosθycosθzcosθxsinθysinθxcosθxcosθy]\left[\begin{matrix}cos\theta_y cos\theta_z - sin\theta_x sin\theta_y sin\theta_z & -cos\theta_x sin\theta_z & sin\theta_x cos\theta_y sin\theta_z + sin\theta_y cos\theta_z\\sin\theta_x sin\theta_y cos\theta_z + cos\theta_y sin\theta_z & cos\theta_x cos\theta_z & sin\theta_y sin\theta_z - sin\theta_x cos\theta_y cos\theta_z\\-cos\theta_x sin\theta_y & sin\theta_x & cos\theta_x cos\theta_y\end{matrix}\right]

흠 교환법칙을 고려하면 맞군요.

아주 좋습니다.

자 그러면 이제 검토 :

회전변환의 성질(Rigid Transformation)의 조건을 만족하는지 검토해봅시다

검토 1. 행렬식이 1(det. \( R = 1 \) )


하… 3차원 행렬식 부터 꺼내와야하는군요.

2차원에서는 단순히 ad-bc인데

[abcd]=adbc\left[ \begin{matrix} a&b\\ c&d\\ \end{matrix} \right] = ad - bc

3차원의 행렬식은 a(ei-fh)-b(di-fg)+c(dh-eg) 입니다.

[abcdefghi]=a(eifh)b(difg)+c(dheg)\left[ \begin{matrix} a&b&c\\ d&e&f\\ g&h&i\\ \end{matrix} \right] = a(ei-fh)-b(di-fg)+c(dh-eg)

3차원 이상부터는 행렬식을 구하는 방법이 조금 어렵습니다.

제가 소개할 방법은 소행렬식을 통한 재귀적 계산법입니다.

N차 정방행렬에 대해 임의의 원소 aija_{ij} 가 존재한다면, i와 j에 해당하는 행과 열을 제거한 N-1차 행렬식( SijS_{ij} )을 원소 aija_{ij} 의 소행렬식이라 할 때,

j=1n(1)i+jaijdet(Sij)\sum_{j=1}^{n} (-1)^{i+j}\cdot a_{ij} \cdot det(S_{ij})

같은 방법으로 구할 수 있습니다.

다른방식으론 Sarrus 라는 방식이 있습니다.

Sarrus 방식의 행렬식 연산. 대각선으로 연장하여 합하고,뺍니다. 비슷한방법으론 삼각형방식이 있는데, 뭐 비슷합니다.

Sarrus 방식의 행렬식 연산. 대각선으로 연장하여 합하고,뺍니다. 비슷한방법으론 삼각형방식이 있는데, 뭐 비슷합니다.

일단 계산할 식 변형들 리마인드 하고,

sin(x+y)=sin(x)cos(y)+cos(x)sin(y)sin(xy)=sin(x)cos(y)cos(x)sin(y)cos(x+y)=cos(x)cos(y)sin(x)sin(y)cos(xy)=cos(x)cos(y)+sin(x)sin(y)sin(x)+sin(y)=2sin(x+y2)cos(xy2)sin(x)sin(y)=2cos(x+y2)sin(xy2)cos(x)+cos(y)=2cos(x+y2)cos(xy2)cos(x)cos(y)=2sin(x+y2)2sin(xy2)sin(x)cos(y)=12(sin(x+y)+sin(xy))cos(x)sin(y)=12(sin(x+y)sin(xy))cos(x)cos(y)=12(cos(x+y)+cos(xy))sin(x)sin(y)=12(cos(x+y)cos(xy))sin(x+y)sin(xy)=2cos(x)sin(y)...sin(x+y) = sin(x)cos(y)+cos(x)sin(y)\\sin(x-y) = sin(x)cos(y)-cos(x)sin(y)\\cos(x+y) = cos(x)cos(y)-sin(x)sin(y)\\cos(x-y) = cos(x)cos(y)+sin(x)sin(y)\\\\\quad\\sin(x) + sin(y) = 2sin(\frac{x+y}{2})cos(\frac{x-y}{2})\\sin(x) - sin(y) = 2cos(\frac{x+y}{2})sin(\frac{x-y}{2})\\cos(x) + cos(y) = 2cos(\frac{x+y}{2})cos(\frac{x-y}{2})\\cos(x) - cos(y) = -2sin(\frac{x+y}{2})2sin(\frac{x-y}{2})\\\\\quad\\ sin(x)cos(y) = \frac{1}{2}(sin(x+y)+sin(x-y))\\cos(x)sin(y) =\frac{1}{2}(sin(x+y)-sin(x-y))\\cos(x)cos(y) = \frac{1}{2}(cos(x+y)+cos(x-y))\\sin(x)sin(y) = -\frac{1}{2}(cos(x+y)-cos(x-y))\\ \\\quad\\ sin(x+y) - sin(x-y) = 2cos(x) sin(y)\\...

하나하나 분해하는 걸 적고 싶지만… 체력이 없어 간단하게

분해 후 계산을 시작합니다.

장장 3시간에 거친 연산작업...

장장 3시간에 거친 연산작업…

\therefore 해당 행렬 RR 에 대해 det( RR ) = 1입니다.

p.s. 계산이 잘못된건 아닐까 계산기를 연산 후에 돌려봤습니다.

Untitled

이 컴퓨터는 조금 다르게 풀었지만 1임을 증명하였습니다.

굳!

검토 2. 직교행렬이여야함( \( R^T = R^{−1} \) )


ifRT=R1thenRRT=Iif\quad R^T = R^{-1} \quad then \quad R \cdot R^{T} = I

이 식을 사용하여 계산해보겠습니다.

[cosθycosθzsinθxsinθysinθzcosθxsinθzsinθxcosθysinθz+sinθycosθzsinθxsinθycosθz+cosθysinθzcosθxcosθzsinθysinθzsinθxcosθycosθzcosθxsinθysinθxcosθxcosθy][cosθycosθzsinθxsinθysinθzsinθxsinθycosθz+cosθysinθzcosθxsinθycosθxsinθzcosθxcosθzsinθxsinθxcosθysinθz+sinθycosθzsinθysinθzsinθxcosθycosθzcosθxcosθy]\left[\begin{matrix}cos\theta_y cos\theta_z - sin\theta_x sin\theta_y sin\theta_z & -cos\theta_x sin\theta_z & sin\theta_x cos\theta_y sin\theta_z + sin\theta_y cos\theta_z\\sin\theta_x sin\theta_y cos\theta_z + cos\theta_y sin\theta_z & cos\theta_x cos\theta_z & sin\theta_y sin\theta_z - sin\theta_x cos\theta_y cos\theta_z\\-cos\theta_x sin\theta_y & sin\theta_x & cos\theta_x cos\theta_y\end{matrix}\right] \cdot \left[\begin{matrix}cos\theta_y cos\theta_z - sin\theta_x sin\theta_y sin\theta_z & sin\theta_x sin\theta_y cos\theta_z + cos\theta_y sin\theta_z & -cos\theta_xsin\theta_y \\-cos\theta_x sin\theta_z & cos\theta_x cos\theta_z & sin\theta_x\\sin\theta_x cos\theta_y sin\theta_z + sin\theta_y cos\theta_z & sin\theta_y sin\theta_z - sin\theta_x cos\theta_y cos\theta_z & cos\theta_x cos\theta_y\\\end{matrix}\right]

Untitled

Untitled

\therefore 해당 행렬 RR 에 대해 RRT=IR \cdot R^{T} = I 이므로 RR 은 직교행렬입니다.

3차원 카메라


뷰 좌표계(View Space)


뷰 좌표계란 카메라가 원점인 좌표계를 의미합니다.

즉 월드 좌표계에서 설정한 내용을 카메라 기준으로 바꿔야 합니다.

이때 카메라를 두게 된다면, 엔진의 입장에서는 카메라를 주로 되고, 설계의 입장에서는 물체를 관찰해야하므로 물체의 정면을 카메라가 관찰하는 상황에서, 물체입장에서의 정면이 카메라의 뒤를 향하는 형태를 띄게됩니다.

이때 좌표계는 물체의 정면을 카메라가 바라보기 때문에,

물체의 정면이 z+를 향하는 오른손 좌표계에서는 카메라 앞의 모든 물체의 z값이

음(negative)의 값을 갖습니다.

다시 정리하여 z+ 축은 카메라 뒤편을 향하게 됩니다.

오른손좌표계라 어쩔수 없어요.

뷰 행렬(View Matrix)


뷰 행렬은 뷰 좌표계로 변환하는 행렬을 의미합니다.

2차원 뷰 행렬

2차원과 개념자체는 바뀌지 않습니다.

따라서 V=(TR)1=R1T1V=(TR)^{-1}=R^{-1}T^{-1} 을 그대로 가져올 수 있겠네요.

R1=RT=[XxXyXz0YxYyYz0ZxZyZz00001]R^{-1}= R^{T} = \left[ \begin{matrix} X_x&X_y&X_z&0\\ Y_x&Y_y&Y_z&0\\ Z_x&Z_y&Z_z&0\\ 0&0&0&1\\ \end{matrix} \right] T1=[100tx010ty001tz0001]T^{-1}=\left[\begin{matrix}1&0&0&-t_x\\0&1&0&-t_y\\0&0&1&-t_z\\0&0&0&1\\ \end{matrix}\right] R1T1 = [XxXyXzX  t YxYyYzY  t ZxZyZzZ  t0001] =  [XxXyXzXx  tx + Xy  ty + Xz tzYxYyYzYx  tx + Yy  ty + Yz tzZxZyZzZx  tx + Zy  ty + Zz tz0001]R^{-1}T^{-1} =  \left[\begin{matrix}X_x&X_y&X_z&X \cdot -t \\Y_x&Y_y&Y_z&Y \cdot -t \\Z_x&Z_y&Z_z&Z \cdot -t\\0&0&0&1\\ \end{matrix}\right]  =  \left[\begin{matrix}X_x&X_y&X_z&X_x \cdot -t_x + X_y \cdot -t_y + X_z\cdot -t_z\\Y_x&Y_y&Y_z&Y_x \cdot -t_x + Y_y \cdot -t_y + Y_z\cdot -t_z\\Z_x&Z_y&Z_z&Z_x \cdot -t_x + Z_y \cdot -t_y + Z_z\cdot -t_z\\0&0&0&1\\ \end{matrix}\right]

이렇게 뷰 변환 행렬을 한번 만들어 보았습니다.

뷰 행렬은 왜 이동을 먼저 적용하는가?


이 질문에 대한 제 생각은 2차원일때와 동일합니다.

TRS 행렬을 하는 이유가 영향을 받지 않는 것 먼저 작업하여

유저가 생각하는 순서와 크게 다르지 않게 하기 위해서 라고 한다면,

뷰 행렬 역시 ‘역으로 연산함‘에 따라 이동을 먼저하는것이 맞다고 생각합니다.

단순하게 생각해보면 고개를 뒤로 빼면서 오른쪽으로 꺾어봐 할 때,

누가 좌측 뒤편으로 고개를 이동하면서 오른쪽으로 꺾을까요?

회전을 먼저 적용할 경우 이동은 회전에 영향을 받기 때문에,

‘관찰자의 시점’에서는 회전은 마지막에서만 적용됩니다.

Implementation


단순히 함수부분만 발췌하였습니다.

https://gist.github.com/ashuatz/86289bf82eb811485a2934649b2aa79d

3DTransform_1.gif

제가 좋아하는 것은 남의 구현 의도와 반대되는 구현을 하는것으로,

카메라 중심 회전으로 만들어진 코드를 오브젝트 중심 회전’처럼’ 바꾸어 보았습니다. 하하

끝내며


행렬은 결국 사람이 아닌 기계가 계산해주기 위해 하는 것인데,

이것의 det을 스스로 손으로 구하고 있으니 이게 뭔가 싶었습니다.

큰 골자는 어려운게 없어 보일지 몰랐으나,

무수히 많은 함정들과 자료부족이 저를 괴롭혔습니다.

왜 사람들은 과거에 ~~로 결정 지었는가 ? 에 대한 대답은 명확하게 나온 것들이 많지 않아

어디선가 글을 읽어도 의심과 불신으로 더 조사하게 되는 것 같습니다.

부족한글 읽어주셔서 감사합니다.

This post is licensed under CC BY 4.0 by the author.
Contents