태그 : D3D

3D 세상과 2D의 모니터 변환 사이에서 일어나는 작업들

오랜만에 글을 쓰게 되네요.
시간도 없고 써야할 주제가 딱히 생각나지 않아 업뎃이 없었네요.

오늘은 간단하게 3D 세상과 2D모니터로 출력될때의 작업들에 대해서 좀 다루어 보도록 하겠습니다.
(렌더링 파이프라인이라고 할수도 있지만 우선 쉐이더는 건너뛰고 로컬좌표, 월드좌표, 카메라에
대한 설명을 중점적으로 해서 렌더링 파이프라인이라는 표현은 안하도록 하겠습니다.)

우선 3D 세상은 3D오브젝트들로 구성이 되게 됩니다.
이때 항상 생각되어야 하는것이 월드행렬과 로컬행렬입니다.
월드행렬은 모든 오브젝트의 기준이 되어야 하는 좌표로서 단위행렬을 넣어주며
문법으로는
D3DXMATRIXA16 matWorld;
D3DXMatrixIdentity(&matWorld); //단위 행렬로 채워주는 함수
디바이스->SetTransform(D3DTS_WORLD, &matWorld);
로 넣어줍니다.
만일 월드가 돌아간다면 그에 속해있는 물체들도 같이 돌게 될것입니다.
즉 월드를 이용하면 그 세상에 있는 모든것에 대한 동일한 변환을 시켜줄수 있는 것이지요.
(같은 예로 "지구가 돈다면 그 위에 서있는 사람도 돌고 있다."가 될수 있겠네요.)

그렇다면 로컬행렬을 생각해 보겠습니다.
2D처럼 절대적인 좌표로 처리가 되지 않는 3D는 (정확히는 2D도 절대적인 좌표는
아니지만 2D는 대체적으로 모니터의 픽셀과 매칭시키는 작업을 많이 하기 때문에 이런 표현을
사용하였습니다. 그렇지 않은 예가 RTS게임들이겠네요.) 상대적이기 때문에 로컬행렬의 값이 매우 중요합니다.

로컬좌표는 월드좌표(절대좌표)에서 상대적으로 얼마나 떨어져있고 얼마나 혼자 회전해 있으며
얼마나 크기가 틀린지를 결정짓는 좌표가 되겠습니다. 로컬좌표는 대체적으로 오브젝트당
하나씩 가지고 있으며 로컬좌표가 다른 오브젝트의 또다른 월드좌표가 될수도 있습니다.
계층구조로 이루어진 오브젝트(사람등의 계층적으로 오브젝트가 구성되어 있는 경우,
지구에 달이 종속되어 있는 경우)등이 그러한 예가 되겠습니다.

여기까지의 설명의 결론은 "World는 상대적인 월드 좌표고 로컬좌표도 상대적인 좌표이다"라는게
특징이 될것입니다. 이것을 강조하는 이유는 D3DX문법이 조금 이상해 보일수 있기 때문입니다.

D3D에서 오브젝트를 특정좌표에 찍을시에는
D3DXMATRIXA16 matLocal;
matLocal위치이동, 회전, 확대축소를 결정한다.;
디바이스->SetTransform(D3DTS_WORLD, &matLocal);
후에 오브젝트를 그리면 되겠습니다.

자 여기서 매우 이상한게 D3DTS_WORLD에다가 로컬좌표를 먹인다는 문제인데
이게 매우 이상해 보입니다. 방금 D3DTS_WORLD는 월드좌표를 바꿀때 쓴다고
하였는데 왜 여기에 로컬좌표를 넣는건지 이상해 보입니다.
(이상해 보이지 않으실지 모르겠지만 저는 공부할때 매우 이상했습니다.)

이건 렌더링작업에 대한 이해가 필요한데 정확히 3D세상과 모니터의 2D세상은 전혀 틀린
세상입니다. 화면의 모습은 카메라에서 특정좌표를 바라보고 그것을 투사시키는 방식이지요.
저 문법의 의미는 "오브젝트를 그릴때 위의 세계환경으로 오브젝트를 그려다오"라는
의미입니다. 즉 로컬좌표를 알려주는 방법중에 하나이며 저렇게 했을시 월드좌표가
되는것이 아니라 순간적인 로컬좌표가 되어 3D세상의 어떤부분에 일치하게 되는것입니다.
즉 그려지는게 아니라 위치시킨다는 것입니다.

우리가 사는 세상의 예로 설명을 하면 남산타워는 지구중심을 기준으로 x,y,z로 몇 이동한 위치에(이동),
1기압으로(확대축소), 0.2도 만큼 기울어져 있는 남산위에(회전) 있다.
라는 작업을 남산타워를 그리기 전에 설명해 주는 방식이 되겠습니다.

그리고 이렇게 동작하는 2번째 이유는 그래픽 카드의 T&L기능의 사용을 위해서입니다.
이 함수를 이용하여 동작할시 변환되는 작업은 그래픽 카드의 T&L로 넘어가서 처리되기
때문입니다. (기존 DX7에서는 이걸 다 cpu로 계산했어야 했죠. DX8은 공부한적이 없어서 모르겠네요)

자 그렇다면 월드행렬과 로컬행렬은 어떻게 관리되어야 할까요?
네 정확히는
D3DXMatrixA16 matWorld;
D3DXMatrixA16 matLocal1;
이런식으로 따로따로 저장되고 자신이 그려지기 전에 그려져야 합니다.
(이 부분에서 matWorld는 정확히는 게임내에서 정의하는 월드와 환경을 같이 하는 오브젝트의 로컬좌표이기도 합니다.)

그렇다면 만일 태양을 중심으로 지구가 돌고 지구를 중심으로 달이 돈다면 어떻게 표현해야 할까요?
D3DXMatrixA16 matSun;
D3DXMatrixA16 matEarth;
D3DXMatrixA16 matMoon;

D3DXMatrixA16 matWorld = matSun;
디바이스->SetTransform(D3DTS_WORLD, &matWorld);
해그리기();

D3DXMatrixA16 matWorld = matSun*matEarth;
디바이스->SetTransform(D3DTS_WORLD, &matWorld);
지구그리기();

D3DXMatrixA16 matWorld = matSun*matEarth*matMoon;
디바이스->SetTransform(D3DTS_WORLD, &matWorld);
달그리기();

이런식으로 작업하게 됩니다.
다시 한번 강조드리지만
디바이스->SetTransform(D3DTS_WORLD, &matWorld);
이 문법은 현재의 환경(World)을 matWorld의 값으로 한다는 뜻입니다.

길이 길었네요.
다음글에 이어서 카메라행렬의 이야기를 이어서 하도록 하겠습니다.

by JetLi | 2008/08/27 00:59 | DirectX 3d | 트랙백 | 덧글(0)

◀ 이전 페이지 다음 페이지 ▶