Direct3D : 월드행렬 (World Matrix) 3 - 크기변환행렬 Direct 3D


월드행렬을 설정할때의 마지막 행렬인, 크기변환행렬입니다.
영어를 그대로 써서 스케일 행렬(Scale Matrix) 이라고도 많이 부릅니다.



스케일 행렬은 기본적으로 이런 식으로 구성되어 있습니다. 전체 행렬 곱 연산에
섞어넣어 전체 연산 결과의 비율을 조절하는 역할을 하게 되는데요,

이는 _11,_22,_33,_44 인자를 1로 구성했을때의 항등행렬을 곱할때
원본 비율이 유지된다는 것에서 출발하여, 인자의 수를 변동하여 일부 비율을
변경하겠다는 식으로 발전된 개념입니다.

말하자면 스케일 행렬은 원본을 유지하는 항등행렬의 원리를 응용한 것이죠.




행렬을 실제 코드에서 사용하는 예시는 이런 식입니다.
이전에 행렬을 적용했던것과 비슷하죠.

스케일 행렬로 사용할 행렬을 선언하고..
항등행렬로 초기화하고...
스케일 행렬을 설정하고..

이렇게 만들어진 정보를 월드행렬 정보로 설정하는 과정까지인 것이죠.
현재는 비율을 (1,1,1) 로 설정하였으므로, 출력결과에는 변동이 없을 겁니다.
원본 비율을 유지하기 때문이지요.


D3DXMatrixScaling


이 함수는 X,Y,Z 에 대한 비율값을 받고, 이 비율을 스케일 행렬의 값으로 설정하는
기능을 합니다. 받은 수를 _11,_22,_33 인자에 대입하는 기능 말이죠.


_11,_22,_33 인자에 값을 직접 대입하는 것으로 동일한 결과를 볼 수 있습니다.
이 비율은 숫자를 다르게 넣어주면 그 비율에 맞도록 크기가 변하게 됩니다.
2를 넣었다면 2배의 크기로, 5를 넣었다면 5배의 크기가 되며,
0.5 를 넣으면 그 비율만큼 작아진 상태가 됩니다.






0.5 를 값으로 넣은 결과입니다.
해당 비율만큼 줄어든 상태가 되었습니다.
스케일 행렬은 이동행렬과 마찬가지로, 상당히 직관적이며, 단순히 넣은 숫자를 비율로
생각하면 되므로, 쉽게 생각할 수 있습니다.
사실상, 기본적인 소개와 사용법에 대해서는 이정도로 끝난 셈이 됩니다.


하지만 여기서 한가지 의문점을 제기해 보겠습니다.


지금은 스케일 행렬을 곧바로 월드행렬로 설정하여 값을 디바이스에 전달하고 있지요?
그런데 _11,_22,_33 인자는 이전에 소개하였던 회전행렬이 관장하는 영역의 일부입니다.
결국 전달받으면, 행렬의 값으로 식을 세우고, 변화된 X,Y,Z 값을 새로 구하게 되지요.

단지 _11,_22,_33 만 설정하고 값을 넘겼다고 해서 디바이스에서
"음 이 행렬은 크기변환 행렬이군!" 하고 크기를 변화시키는 것일까요?
물론 아닐 것입니다.

_11 ~ _33 까지의 모든 인자는 행렬의 값을 통해 식을 세우고,
이 식으로 변동된 새로운 좌표를 만드는 역할에 사용됩니다.
스케일 행렬은 이렇게 회전행렬의 영역을 함께 사용하고 있는 셈이지요.
그렇다면 여기서 식을 세우는 방향으로 접근해 봅시다.



자 이처럼 _11,_22,_33 인자가 각각 3으로 설정된 스케일 행렬이 있습니다.
이 상태로 디바이스에 행렬을 넘겨준다면, 내부적으로 어떻게 연산을 수행할까요?

일단 새로운 좌표를 산출하기 위한 식을 만들 것입니다. 행렬의
인자를 사용해서 말이죠. 이 행렬을 구성으로 식을 만든다고 생각하면...

3X + 0Y + 0Z = X'  //새로운 X좌표
0X + 3Y + 0Z = Y'  //새로운 Y좌표
0X + 0Y + 3Z = Z'  //새로운 Z좌표

이런식으로 식을 세우게 되겠지요. 여기서 0 인 항들을 제외한다고 생각하면...

3X  = X'   //X의 3배가 새로운 X 좌표
3Y  = Y'   //Y의 3배가 새로운 Y 좌표
3Z = Z'   //Z의 3배가 새로운 Z 좌표

이렇게 정리됩니다. 각각의 좌표들은 기존 좌표의 3배씩 늘어난 수치를 값으로 가지게 
됩니다. 결론적으로 이 식은 모든 버텍스 정점에 적용되고, 이 비율에 따라서 버텍스 정점들의
값이 조금씩 거리를 변경하면, 전체적으로 크기가 커진 듯한 효과를 볼 수 있게 됩니다.
이것이 스케일 행렬만 선언하여 월드행렬값으로 설정되도, 별다른 문제 없이 잘 적용되는
이유입니다. 

어디까지나 행렬을 받으면 내부에서는 받은 행렬로 각 버텍스들의 새로운 좌표를 
산출하기 위한 식을 세웁니다. 스케일 행렬이라고 해서 이 방식을 벗어나는 것이 
아니라는 것을 강조하고 싶었던 겁니다.

또한, 회전행렬과 곱 연산을 거치게 되면, 항등행렬의 원리에 따라서, 회전행렬의 연산값의
비율을 조절하는 역할을 하게 됩니다. 이렇게 변경된 비율은, 식을 세울때도 그대로 반영되므로,
회전행렬과 스케일행렬을 함께 사용했을 경우에도 크기 변환이 문제없이 이루어지게 됩니다.

(회전을 하는데 비율만큼 좀 더 떨어진 꼴로 회전하는 결과가 나오는 것이죠)



다음으로, 여태까지 소개한 행렬들을 곱하여, 각각의 결과를 합산해 보겠습니다.


각 행렬들을 멤버변수로 정의하고, 필요한 자료형을 벡터 자료형을 통해서 준비했습니다.



이후 준비된 멤버변수들을 통해 행렬들을 설정하고, 이들의 곱으로 연산결과를
결합하는 과정을 작성했습니다.

행렬을 곱하는 것은 하나의 행렬에 모든 행렬의 결과를 반영하기 위한 과정입니다.

행렬을 곱할때는 보통 다음 순서를 지켜서 연산해야 합니다.
행렬은 기본적으로 결합법칙이 성립하지 않으므로, 순서를 바꾸게 되면 연산 결과가
많이 달라지게 됩니다.



일단 기본적인 연산 순서는 이런 식입니다.

스케일행렬 * 자전행렬 * 이동행렬 * 공전행렬 * 부모행렬


스케일 행렬은 어디까지나 비율을 조절해 주는 것으로,
자전행렬(회전행렬)과의 곱 연산을 거쳐도, 큰 맥락을 변경시키지 않습니다.
그 후에 이동행렬을 곱하게 되는데요 이 연산을 통해서 오브젝트의 중심 좌표에 대한
설정까지 이루어지게 됩니다.

공전행렬과 부모행렬은, 공전을 위한 행렬입니다. 공전이라는 것은, 전체 버텍스가
부모의 위치를 중심으로 함께 회전을 하는 것을 의미하며, 때문에 공전 시에 사용할
회전행렬을 설정하고, 기준이 되는 부모행렬을 지정해 주는 것입니다.
자세한 사항은 아직은 언급하지 않겠습니다.

이들 중에서 연산을 수행하지 않을 행렬은 곱 연산에 작성하지 않으면 됩니다.
어차피 행렬이 있었더라도, 값의 변동이 없다면, 항등행렬인 상태로 곱 연산이 수행될
것이며, 이 연산은 행렬의 값을 변동시키지 않는다는 것을 상기해 본다면,
행렬 자체를 빼 버리는 것 역시 동일하다는 것을 알 수 있을 것입니다.

월드행렬 연산은 매우 자주 사용되는 내용이므로,
이들 순서는 암기를 하는 편이 좋습니다. 스-자-이-공-부 라고 줄임말로 암기해 보세요^^



여기까지, 3D 그래픽스에서 사용되는 기본적인 행렬들인 
이동행렬, 회전행렬, 크기변환행렬에 대한 내용을 소개해 보았습니다.
월드 스페이스를 구성하는 중요한 내용이므로, 잘 숙지해야 하는 부분이기도 합니다.

아직 공전에 대해서는 구체적으로 언급하지 않았습니다. 
이 부분에 대해서는 뷰 행렬과 투영 행렬을 설정하고 카메라에 대한 개념을 적용된 
후에 언급해 보도록 하겠습니다. 왜냐하면 카메라 개념이 도입되지 않은 상태에서 
공전을 언급하는 것은 반쪽짜리 설명밖에 되지 않기 때문입니다.


덧글

댓글 입력 영역


라운드 시계