DX9을 이용한 3D Game 프로그래밍 입문 - Part.2 Direct3D 기초 2장

제 2장 렌더링 파이프라인

렌더링 파이프라인 : 3D 세계에 대한 기하하적 표현과 이 세계를 바라보는 관점을 정의하는 가상 카메라를 이용해 2D 이밎를 만들어내는 역할을 담당한다.

2.1 모델 표현

장면 : 물체나 모델의 모음

물체 : 삼각형 메쉬의 묘사로 이루어짐. 삼각형은 우리가 모델링하는 물체의 기본적인 구성 성분이 되며, 우리는 메쉬 삼각형을 참조하는 용어로 다각형 기본형 그리고 메쉬 기하물체를 상호 교환적으로 이용한다.

버텍스 : 다각형에서 두 개읜 변이 만나는 지점(꼭지점)
하나의 삼각형을 만들기 위해서는 삼각형의 세 버텍스에 해당하는 세 개의 포인트 위치를 지정해야하고, 이 삼각형을 지정하여 물체를 묘사한다.

2.1.1. 버텍스 포맷

앞서 정의한 버텍스는 수학적으로는 문제가 없지만 D3D에서 이용할 개념으로는 불완전함 그 이유는 D3D 내의 버텍스가 공간적 위치 이외의 부가적인 특성으로 이루어져 있기 때문
D3D는 우리 자신의 버텍스 포맷을 구성할 수 있는 유연성을 제공하는데, 다른 말로 하면 버텍스의 속성을 정의할 수 있도록 해준다.

커스텀 버텍스 포맷을 만들기 위해서는 먼저 우리가 선택한 버텍스 데이터를 포함할 구조체를 만들어야 한다.
버텍스 구조체를 완성한 다음에는 FVF 플래그 조합을 이용해 버텍스가 포맷팅되는 방법을 지정해야 한다.
여기서 한 가지 기억해야 할 점은. 버텍스 구조체에 정의된 데이터의 순서와 FVF의 정의된 순서는 반드시 일치해야 한다는 것이다.

2.1.2 삼각형

삼각형은 3D 물체의 기본 구성 요소로서, 물체를 구성하기 위해서는 물체의 모양과 외형을 묘사하는 삼각형 리스트를 만들어야 한다. 삼각형 리스트는 우리가 그리고자 하는 각각의 삼각형에 대한 데이터를 포함.

-NOTE-
삼각형의 버텍스를 지정하는 순서는 매우 중요하며 이를 두르기 순서라고 부른다.

2.1.3 인덱스

3D 물체를 구성하는 삼각형들은 동일한 버텍스들을 공유하는 경우가 많다.
이 문제를 해결하기 위해 우리는 인덱스의 개념을 이용한다. 기본적인 아이디어는 다음과 같다. 먼저 버텍스 리스트와 인덱스 리스트를 구성한다.
버텍스 리스트 : 모든 독특한 버텍스들을 포함
인덱스 리스트 : 삼각형을 구성하기 위한 버텍스 리스트로의 인덱스 값을 포함


이 사각형을 예제로 들면
버텍스 리스트는 Vertex vertexList[4] {vO , v1 , v2 , v3) ; 이렇게 등록되고
인덱스리스튼 버텍스리스트의 요소로
WORD indexList[6] {O , 1, 2, // 삼각형 O
0, 2, 3); // 삼각형 1
구 삼각형을 표현한다.

2.2 가상 카메라

카메라 : 관찰자가 볼 수 있느 세계의 부분을 지정하는 것으로,2D 이미지를 생성하기 위해 세계의 어떤 부분이 필요한지를 결정하며, 세계 내에 위치하며 보여질 공간의 부피를 정의한다.

공간의 부피는 절두체이며, 시야각과 가까운 평면,먼 평면에 의해 정의된다.
사각 원뿔을 이요하는 이유는 모니터 스크린이 사각형이기 때문이다.

이 공간에 포함되지 않은 물체들은 보여지지 않으며 이후의 처리에서 제외된다. 이와 같은 데이터의 제외 처리를 클리핑이라 부른다.

투영윈도우 : 3D 장면의 2D 표현을 만드는 데 이용될 절두체 내부에 있는 3D 기하의 2D 영역이다. MIN=(-1,-1)과 MAX=(1,1)로 정의하여 만든다.

D3D는 투영 평면이 평면 Z=1이 되도록 정의한다.

2.3 렌더링 파이프라인

기하하적으로 3D 장면을 구성하고 가상 카메라를 설정한 뒤에는 모니터에 2D 표현을 만들어 내는 과정을 수행해야 한다. 이 과정을 렌더링 파이프 라인이라 한다.

로컬스페이스-> 월드스페이스 -> 뷰 스페이스 -> 후면 추려내기 -> 조명 -> 클리핑 -> 투영 -> 뷰포트 -> 래스터 라이즈

파이프라인 내에서는 몇가지 단계에 의해 하나의 좌표시스템에서 다른 시스템으로 기하물체를 변환하는 과정이 이루어짐.
이 변환에는 행렬이 이용되며, 변환 과정은 D3D의 책임 하에 이루어짐. 이 때, 하드웨어 변환 기능을 가진 하드웨어를 보유하고 있다면 그래픽 하드웨어 내에서 변환을 처리할 수 있다. D3D 변환을 이용하기 위해서는 우리가 원하는 변환 행렬을 지정해야하며, IDirect3DDevice->SetRransform 메서드를 이용해 행렬을 전달할 수 있다.
이 메서드는 변환 타입을 설명하는 인자와 변환을 표현하는 행렬을 인자로 받는다.

2.3.1 로컬 스페이스

로컬 스페이스 : 우리가 물체의 삼각형 리스틀 정의하는 데 이용하는 좌표 시스템. 모델링 과정을 쉽고 단순하게 만들어주며, 자체의 로컬 좌표 시스템을 이용하는 것이 월드에서 직접 모델을 구성하는 것보다 훨씬 쉽다. 예를 들어 로컬 스페이스를 이용하면 위치나 크기, 월드 내의 다른 물체와의 관계 등을 고려하지 않고도 모델을 구성할 수있다.

2.3.2 월드 스페이스

자체의 로컬 좌표 시스템 내에 다수의 모델을 구성한 다음에는 이를 전역좌표 시스템으로 옮겨 하나의 장면을 구성해야함. 로컬 스페이스의 물체들은 이동,회전,크기 변형 등을 포함하는 월드 변환이라는 작업을 거쳐 월드 스페이스로 옮겨짐.
월드 변환은 위치와 크기, 방위를 포함하는 각 물체 간의 관계를 정의함 으로써 이루어짐.
월드 변환은 하나의 행렬로 표현되며, 변환 타입에 D3DTS_WORLD를 지정하고 SetTransform 메서드를 호출하여 수행할 수 있다.

ex) m_pGraphic_Device->SetTransform(D3DTS_WORLD, &WorldMatrix);

2.3.3 뷰 스페이스

월드 스페이스 내에서 기하물체와 카메라는 워드 좌표 시스템과 연계되어 정의됨. 한편 카메라가 월드 내 임의의 위치나 방위를 가진다면 투영이나 그 밖의 작업이 어려버나 덜 효율적이 됨. 따라서 작업의 수월함을 위해 카메라를 월드 시스템의 원점으로 변환하고, 카메라가 양의 z-축을 내려다 보도록 회전시켜야함

뷰스페이스 변환 : 월드에 대한 관점이 바뀌지 않도록 하기위해서 카메라에 맞추어 월드 내의 모든 기하물체를 변환하는 작업. 이 변환을 거친 뒤의 기하 물체는 뷰 스페이스 내에 위치한다고 말할 수 있다.


위 그림은 월드 스페이스에서 뷰 스페이스로의 변환을 보여준다, 이 변환은 카메라를 시스템의 원점으로 변환하고 양의 z-축을 내려보도록 한다. 스페이스 내의 모든 물체들을 카메라와 함께 변환되므로 카메라가 월드를바라보는 관점에는 변화가 없다.

뷰 스페이스 변환 행렬은 다음의 D3DX 함수를 통해 계산할 수 있다.

D3DXMATRIX DEDMatrixLookAtLH(
D3DMATRIX
pOut; //결과 행렬을 받을 포인터
CONST D3DXVECTOR3 pEye //월드 내의 카메라 위치
CONST D3DXVECTOR3
pAt //월드 내의 카메라가 보는 지점
CONST D3DXVECTOR3* pUp //월드의 업 벡터 - (0,1,0)
);

아이 인자에는 월드 내의 원하는 카메라 위치를 지정한다. 앳 인자는 월드 내의 카메라가 조준하기를 원하는 지점을 지정한다. 업 인자는 3D 월드 내의 위쪽 방향을 가리키는 벡터를 지정한다. 보통 이 값은 항상 Y축과 일치하는 벡터이다.

뷰 스페이스 변환을 수행하려면 D3DTS_VIEW에 변환 타입을 지정하고 IDirect3DDevice9::SetTransform 메서드를 호출하면 된다.

ex) m_pGraphic_Device->SetTransform(D3DTS_VIEW, &ViewMatrix);

2.3.4 후면 추려내기

폴리곤은 두 개의 면을 가지고 있으며 하나의 면을 전면,다른 면을 후면이라 부른다. 일반적으로 폴리곤의 후면은 절대 보여지지 않는데, 이는 장면 내의 물체들이 대부분 박스나 원기둥,탱크, 캐릭터 등과 같은 채워진 볼륨이며, 채워진 물체의 내부로 카메라를 넣는 것이 허용되지 않기 때문이다.즉, 카메라는 절대로 폴리곤의 후면을 보지 못한다. 이와 같은 사실은 매우 중요한데,왜냐하면 폴리곤의 후면을 볼 수 있는 경우에는 후면 추려내기가 작동하지 않기 때문이다.

후면 추려내기(backface culling) : 전면을 향하고 있는 폴리곤들이 뒤쪽의 후면 폴리곤을 가릴것이고 D3D는 이들을 추려냄으로써 상당한 이득을 취한다.

물론, 이와 같은 처리를 위해서는 어떤 폴리곤이 전면 폴리곤이고 , 후면 폴리곤인지를 D3D 입장에서 확인할 수 있어야 한다. 디폴트로 D3D는 두르기 순서의 시계 방향에 지정된 버텍슬르 가진 폴리곤을 전면 폴리곤으로 취급하며(뷰 스페이스에서),시계 반대방향에 지정된 버텍스를 후면 폴리고느로 취급한다.

-NOTE-
뷰 스페이스로 시점을 정의했다는 데 주의하자. 이것은 삼각형이 180도 회전할 경우 두르기 순서가 뒤집히기 때문이다. 즉 로컬 스페이스에서 시계 방향의 두르기 순서를 가지고 있던 삼각형이라도 뷰스페이스로 변환하면 회전에 의해 시계 방향의 두르기 순서가 아니게 될 수 있다.

만약 표준적인 추려내기 동작이 마음에 들지 않는다면 D3DRS_CULLMODE 렌더 상태를 수정하여 동작을 변경하는 것도 가능하다.

m_pGraphic_Device->SetRenderState(D3DRS_CULLMODE, Value);

Value에는 다음의 세 가지 중 하나를 선택적으로 사용할 수 있다.

D3DCULL_NONE - 후면 추려내기를 완전히 끈다.
D3DCULL_CW - 시계 방향 두르기를 가진 삼각형을 추려낸다.
*D3DCULL_CCW - 시계 반대 방향 두르기를 가진 삼각형을 추려낸다. 디폴트 상태이다.

2.3.5 조명

광원 : 물체에 명암을 추가하여 장면에 사실감을 더해준다. 월드 스페이스 내에 정의되지만 뷰 스페이스 변환에 의해 뷰 스페이스로 변환된다.

2.3.6 클리핑

클리핑 : 시야 볼륨 외부의 기하물체를 추려내는것

시야 절두체에서의 삼각형의 위치는 다음 세가지로 분류 가능

*완전한 내부 - 삼각형이 완전히 절두체 내부에 위치하면 그대로 보존되어 다음 단계로 진행된다.

*완전한 외부 - 삼각형이 완전히 절두체 외부에 위치하면 추려내어진다.

*부분적 내부 - 삼각형이 부분적으로 절두체 내부에 위치하면 삼각형을 두 개의 부분으로 분리한다. 절두체 내부의 부분은 보존되며, 나머지는 추려내어진다.

2.3.7 투영

투영 : N차원에서 N -1 차원을 얻는 과정
원근 투영 : 원근법을 이용하여 기하물체를 투사함. 즉, 카메라에서 멀리 떨어진 물체는 가까운 물체에 비해 작게 나타난다.

투영 변환은 우리의 시야 볼륨(절두체)을 정의하고 절두체 내의 기하물체를 투영 윈도우에 투영하는 과정을 담당한다.
다음과 같은 D3DX 함수를 이용하여 절두체 선언에 따른 투영 행렬을 만들어낼수 있다.

D3DMATRIX D3DXMatrixPerspectiveFovLH(
D3DMATRIX
pOut // 투영 행렬을 리턴
FLOAT fovy // 시야각의 수직 영역(라디안)
FLOAT Aspect // 중횡비 = 윈도우 너비 / 윈도우 높이
FLOAT zn // 가까운 평면까지의 거리
FLOAT zf // 먼 평면까지의 거리
);

종횡비 : 화면 너비와 높이의 비율, 투영윈도우(정사각형) 에서 스크린(직사각형)으로의 매핑에 의해 발생하는 왜곡을 보정하는 역할을 한다.

다음 코드는 90도의 시야각과 거리 1의 가까운 평면,거리의 1000의 먼 평면을 가지는 절두체에 맞는 투영 행렬을 만들어낸다.

D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,PI * 0.5F, (float)width/height , 1.0,1000.F);
Device->SetTransform(D3DTS_PROJECTION,&proj);

2.3.8 뷰포트 변환

뷰포트 변환 : 프로젝트 윈도우의 좌표를 뷰포트라 불리는 화면의 직사각형으로 변환하는 과정. 게임에서의 뷰포트는 보통 직사각형의 전체 화면이 되지만, 윈도우 모드에서 실행하는 경우에는 클라이언트 영역이나 화면의 일부가 될 수도 있다. 뷰포트 사각형은 이를 포함하고 있는 윈도우와 상대적이며, 윈도우 좌표를 이용해 지정된다.

D3D에서는 D3DVIEWPORT9 구조체를 이요아여 부포틀 표현하며, 이 구조체는 다음과 같이 정의된다.

typedef struct _D3DVIEWPORT9 {
DWORD X;
DWORD Y;
DWORD Width;
DWORD Height;
DWORD MinZ;
DWORD MaxZ;
} D3DVIEWPORT9;

앞 부분의 네 데이터 멤버는 뷰포를 포함하는 윈도우와의 상대적인 뷰포트 사각형을 정의한다. MinZ 멤번 최소 깊이 버퍼값 MaxZ는 최대 깊이 버퍼값을 정의한다. Direct3D는 0부터 1까지의 깊이 버퍼를 이용하므로, 특수한 효과를 원하는 것이 아니라면 MinZ와 MaxZ에도 이에 맞는 값으로 지정해야 한다.

D3DVIEWPORT9 구조체를 채운 다음에는 다음과 같은 코드를 이용해 뷰포트를 구성한다.

D3D는 자동으로 뷰포트 변환을 수행해주지만 뷰포트 변환을 수행하는 행렬이 어떻게 구성되었는지를 확인해보는 것도 나쁘지는 않을 것이다. 식의 변수들은 D3DVIEWPORT9 구조체에서 설명한 것과 동일하다.

2.3.9 래스터 라이즈

스크린 좌표로 버텍스들을 변환한 다음에는 2D 삼각형들의 리스트를 가지게 된다.
래스터라이즈 단계는 각각의 삼각형을 그리는 데 필요한 픽셀 컬러들을 계산하는 과정이다.

래스터라이즈 과정은 엄청난 작업 양을 필요로 하므로 반드시 전용 그래픽 하드웨어에서 처리되어야 한다. 래스터라이즈의 결과물은 모니터에 바로 디스플레이할 수 있는 2D 이미지가 된다.

2.4 요약

  • 3D 물체들은 물체의 모양과 외각을 묘사하는 삼각형들의 리스트인 삼각형 메쉬들로 표현된다.

  • 가상 카메라는 절두체로 모델링되며 절두체 내의 공간이 카메라가 "보는"것이 된다.

*3D 물체들은 로컬 스페이스 내의 정의되며 모두 하나의 월드 스페이스 시스템으로 옮겨진다. 투영을 위해 서는 추려내기와 같은 다른 작업이 필요하며, 이어 뷰 스페이스로 물체를 변환하고, 카메라를 원점으로 옮기고 양의 Z-축을 내려다보도록 하는 과정이 진행된다 뷰 스페이스 내에 놓여진 물체들은 투영 윈도우로 투영되며, 뷰 포트 변환을 통해 투영 윈도우의 기하물체가 뷰포트로 변환된다. 이제 최종적으로 래스터라이즈를 거쳐 최종 2D 이미지를 구성하는 각각의 픽셀 컬러가 계산된다.

좋은 웹페이지 즐겨찾기