유니티 매트릭스 #1 월드공간으로 변환하는 모델행렬 만들어보기
그래픽 공부하고 영상 내용을 정리한 글이 무려 10개가 넘엇는데
정리가 지저분하고, 또 잘못 해석하여 이상하게 적은 부분이 많아서 비공개로 그냥 내렸다
정리해서 다시 올릴까 싶었지만, 어차피 블로그의 용도가 공부한걸 메모하여 다시 보는용도로 사용하려해서
의미가 변색되는거같기도(사실 귀찮아서도 있다)해서 그냥 글을 비공개로 넘겨버렸다
아무튼 그동안 이론을 배웠던 OpenGL es 내용들을 토대로 유니티에 그대로 접목시켜볼까한다
오늘은 첫째로 그동안 쉐이더 지원함수로 편히 손쉽게 적용해엇던 월드공간등의 좌표변환중
월드공간으로의 변환을 해볼것이다
이거.. 직접 구현해보려니 엄청 귀찮다.. 얼마나 유니티가 개발자들에게 유용하고 편리한 기능을 지원하는지
다시 한번더 깨닫고 간다 ㅠㅜ
유니티의 좌표변환 매트릭스, 로컬공간(오브젝트공간)에서 월드공간으로 변환하는 행렬.
모델매트릭스라고 부른다(오브젝트공간을 월드공간으로 변환하는 행렬)
먼저 유니티는 openGL과 같이 TRS순으로 행렬연산을 한다 (DX 는 SRT )
T 는 Translation, R 은 Rotation S는 Scale이다
이 TRS 연산 행렬을 현재 오브젝트 공간의 OBJ의 열벡터(오브젝트공간상의 좌표)을 연산하여
원점을 0,0,0으로 하는 월드공간상에 배치하는것이다
(주의할점, 행렬은 결합법칙이 가능하지만 교환법칙은 안된다)
URP로 셰이더를 작성하였다
어떠한 음영이나 효과를 만들려고 한것이 아니다보니 전체 코드까지 캡처할필욘 없을테니
직접만들어본 함수들만 캡처하였다
1. TranslationMatrix
인자로 이동할 벡터를 받아 행렬에 대입한다,
이 행렬과 현재좌표를 의미하는 열벡터를(오른쪽) 연산시 실제 이동이 가능하다
유니티내 곱셈함수 mul(행렬, 열벡터)을 이용하면 된다
예로 mul(T, columnVector), 그리고 벡터도 a행 1열 구조의 행렬이기에
행렬의 곱셈법칙 ( MxN ) (NxR)
즉 왼쪽행렬의 열과
오른쪽 행렬의 행이 같아야 곱셈이 성립된다
아무튼 trs행렬의 구조의 경우
3D transformations (c-jump.com) 이사이트를 참고해도 좋다
2. RotationMatrix
캡처사진의 경우 x y z순이다 그렇다 행렬이 약간의 구조차이가있다
단 주의할점이 있다면, 인자로 받는 angle의경우 유니티 매스함수 radians()을 이용하여 인자로 보내주어야한다
끝으로 위의 각축(xyz)의 회전을 다루는 개별함수를 이제 rot란 이름의 함수로 합쳐 계산한다
여기서 재밌는게 3가지가 있는데
유니티의 경우 회전에 있어서는!
1) z x y 축 순으로 연산을 처리한단것이다
즉 (Ym)(Xm)(Zm) X (현재좌표)이 되는것이다 m은 매트릭스 약자.
유니티의 mul함수는 인자를 두개받는데 A B두인자라 가정시, mul(A,B)로 작성시
(A)(B) 형태로 연산한다
행렬은 교환법칙이 안된다 즉 AB != BA란 소리이다
그래서 mul함수를 쓸때 순서를 보면, 위에서 결국 y x z 순서로 mul로 연산을 한걸 볼수있다
주석부분 아랫부분을 보면
mul(Y, (mul(X,Z)))이니까 Z X Y순으로 연산이 된단것이다
2) 결합법칙이 성립되는 행렬의 특징
위 주석과 주석아래부분의 결과는 똑같다
(AB)C == A(BC) 행렬연산이 가능하단것이다
3) radians함수를 사용하였는데 인자가 각도라 가정시, 각도인자를 계산하여 라디안을 반환한다
라디안 반환없이 회전행렬에 각도벡터를 곱할시, 에디터상에서의 회전과 다른 회전을 볼수있기에
라디안회전값을 적용해주자;;
1 rad = degree * 180f / PI 이다
3.ScaleMatrix
구조가 너무 단순해서 아마 가장 먼저 외워졌던? 행렬구조였던거같다 대각선 한줄 끝..
너무 단순하고 깔끔하고 그래서 고마운??ㅋㅋㅋ 구조의 행렬이다
사실 이런 행렬의 구조는 외울필요는 없지만(필요할때마다 찾아봐도 되지않는가싶다 그만큼 자료가 널려있다)
계속 보다보니 구조가 자연스럽게 외워지는게 있었다
4. 모두 통합하여 계산하는 월드변환매트릭스!(유니티에선 ModelMatrix라고 부르더라)
인자가 4개나 된다
사실 위의 행렬반환함수도 그렇고 인자는 내가 아무렇게나 집어넣은것이다보니 더 깔끔하게 표현도 가능할것이다
float3 posOS는 오브젝트공간상의 정점좌표이다
스케일 앵글 무브 float들은 이름에서 알다싶이 입력 인자들이다
그후 ToWorld라는 변수에 위에서 만들어두었던 모든 행렬들을 곱한다
TRS라 말했던 이유가 여기 그림에서 나오는데
사실상 (TRS)X(오브젝트공간 좌표)이 되는것이다
아까 말한 결합법칙으로 TRS를 먼저 다 결합해서 ToWorld란 변수의 4x4행렬로 만든다
그후 최종 결과물, 월드공간상의 좌표를 의미하는 변수 WorldCoordinate로
mul(ToWorld , float4(posOS,1))즉 월드변환행렬 곱 오브젝트공간좌표를 하여
최종결과를 만든다
버텍스함수에서보면
TransformWorldToHClip에 내가 만든 월드좌표변환후의 좌표를 넣어서
유니티 기본 오브젝트와 비교를 해보았다
그전에 오브젝트내 추가 스크립트를 붙여서 편집하기 쉽게 만들어도 보았다
이런 간단한 실험이나 공부를 할땐 업데이트보단 OnValidate함수가 더 적합한거같다
스크립트내 변화가 일어날떄마다 OnValidate함수가 실행된다
이 스크립트내의 변수들을 쉐이더 프로퍼티들에 전달하여 에디터상에서
실시간으로 값이 변화하는차이를 볼수가 있게된다
왼쪽이 쉐이더스크립트가 적용, 오른쪽은 기본큐브
위의 트랜스폼컴포넌트는 무시하고
아래 매트릭스 스크립트가 실제 변환을 시킨다
먼저 위사진에서 두 큐브의 방향이 같은데
유니티 기본 큐브를 x축으로 15 z축으로 45 변형시키고
왼쪽 셰이더가 적용된 큐브를 위 인스펙터창에서 똑같이 변화시키어도 똑같은 모양이 나온다
어떠한 변형을 주어도 동일하게 적용시 똑같다
아무튼 월드변환매트릭스를 성공시킨거같아 기쁘다
추가로
월드공간으로 변환하는 모델 변환행렬의 3x3부분중 회전행렬의 1~3열은
모델 좌표계에서 월드좌표계의 기저벡터
월드 좌표계에서 모델 좌표계의 기저벡터
서로 전치관계이다
또한 월드공간으로 변환하는 모델행렬의 TRS행렬연산을 다 한 결과값에서
스케일, 로테이션, 이동등을 어떻게 추출할지에 대해서
재밌는 글을 보았다
Given this transformation matrix, how do I decompose it into translation, rotation and scale matrices? - Mathematics Stack Exchange
Given this transformation matrix, how do I decompose it into translation, rotation and scale matrices?
I have this problem from my Graphics course. Given this transformation matrix: $$\begin{pmatrix} -2 &-1& 2\\ -2 &1& -1\\ 0 &0& 1\\ \end{pmatrix}$$ I need to extract
math.stackexchange.com
4x4행렬기준으로 설명시
먼저 4X4행렬에서 4행은 동차좌표 통일을 위해서 언제나 0 0 0 1이기에 4행은 제외하고 보면
T행렬의 경우 4열의 3개를 추출시 그것이 이동변화량
S행렬의 경우 1열의 요소합의길이가 X스케일요소가 ,2열이 Y스케일 3열이 Z스케일요소가 된다
R의경우 S행렬요소를 구한것들을 이용해
각 열마다 X Y Z을 나눠주면 된다