Game Programming/Rendering

DX 9 :: 3차원의 대해서 알아보기

VallistA2016. 2. 24. 18:27


지금까지의 글들은 준비를 하기위한 단계였고 비로소 3D 프로그래밍을 할 준비가 된 것이다.

하지만 3D 프로그래밍은 단순히 점토를 주물럭거린다고 뚝딱 만들어지는 것이 아니다.

3D 프로그래밍의 과정은 간단하지 않으며 이러한 것에 뒷받침되는 기본적 지식이 있어야 한다.


3D 프로그래밍은 수학과 함께 프로그래밍 할 수 있어야 한다. 하지만 수학적 지식이 없더라도 지금은 프로그래밍을 할 수 있는데,

엔진의 보급화와 내부에서 다 지원해주기 때문에 아주 조금의 수학적 지식만 있어도 아니 아에 없어도 구현을 할 수 있게 되었다.

하지만 이건 엔진의 경우이며 우리는 네이티브까진 아니지만 GL (Graphics Library)를 사용하기 때문에 수학적인 생각을 할 줄 아는게 좋을 것이다.

제일 필요한 기술은 수학적인 것들을 C++로 구현을 하는 것이고, 이러한 과정이 어떻게 진행되는지에 대해서 알아볼 것이다.


이번 글은 이론적인 부분에 대해서 서술을 하기 때문에 예제가 없다.

그러므로 다음 글부터 시작되는 좌표계 등등이 어떻게 3D 장면을 만들어내는지에 대해서 설명을 하기에 지루할 수 있지만 잘 봐주길 바란다.



3D 좌표계


기본 수학의 이해 없이 3D 프로그래밍은 불가능하다. 그리고 대학교에서 대수학을 이해하지않으면 이해 하기도 힘들다.

하지만 3D 좌표계 개념을 이해하지않아도, 어떻게 그들이 일을하는지에 대해서는 이해를 할 수 있다.


그렇다면, 3차원 좌표계를 이해하기 전에 직교 좌표라는 것을 이해해보도록 하자.


직교/데카르트 좌표계 (The Cartesian Coordinate System)


직교 좌표계는 2차원 좌표 시스템을 호출하는 경우 시스템이 인식을 더 잘하도록 평면 상에 정확한 포인트를 위치시키는 방법론이라고 할 수도 있고 좌표라고 할 수도 있다.


포인트 축을 따라 정확한 위치로 정의되며 얼마나 멀리에 있는가에 대해 알고 싶어하는 경우 일반적으로 정확한 숫자를 제공하게 된다.

물론 그것의 단위가 12m 이라던가 미터단위는 아니겠지만. 예를들자면 "수지는 12 미터를 걸었다" 라는 구문이 있다고 하자.

12 미터라는 것은 축을 기준으로 한 거리이며, 우리는 0이 출발점이라는 것을 알며, 밥이 진행됨에 따라서 축을따라서 더 멀리 이동을 한 것이다.

지금 설명 한 것이 1차원 좌표계이다.



1차원 좌표계


수지는 0의 지점에서 우측으로 12미터 지점까지 걸어갈 때 12 미터를 걸어갔다고 12의 값을 더했다.

하지만 이와 같은 그림에서. 반대로 갔다면 12의 값을 더하는게 아니라 뺄셈이 되었을 것이다.


자 여기서 수지가 90도를 회전하고 다른 방향으로 움직인다면? 

수지는 제 2축을 따라서 움직일 것이다. 그림으로 표현하면 아래와 같다.




직교/데카르트 좌표계



이제 좌표계는 하나 이상의 축을 가지고 있으며, 어디의 위치에 있는지 식별이 가능할 것이다.

수지는 가로축을 기준으로 12m를 이동했으며 (x 좌표) 그리고 다시 90도를 이동하여 4m를 이동했다. (y 좌표)

X 축이 0이라는 원점이 있는 것과 같이 y축도 0이라는 원점이 있고 이것이 바로 시작 지점이다.


이제 두개의 기준 축을 가지고 있으며 이 것이 직교(데카르트) 좌표계를 형성하는 것이다.

위의 그림이 보이는 것과 같이 어느 지점에 있는지 표면에서 찾을 수 있게 되었다.

간단하게 나타내자면 아래와 같다.


"12만큼 x축을 오른쪽으로 이동 했으며, 다시 위의 방향으로 4만큼 이동했다를 표현하면 (12,4) 정도가 될 것이다."

보통 x와 y를 순서대로 작성을 한다.


이 두 숫자는 일반적으로 좌표라고 불리며 정확한 포지션이 원점에서 얼마나 떨어져 있는지를 표시하는데 사용된다.

3차원 시스템


사실 3차원 시스템은 우리가 위에서 봤던 x,y좌표에 한가지가 확장이 된 좌표인데,

간단하게 세번째 축이(z축이라고 명명한다) 직교좌표에 추가되었다고 보면된다. 



3차원 좌표계 시스템



직교 좌표계와 같이 3D 좌표는 점이 있는 방향에 따라서 증가나 감소가 되게 된다. 

보통 나타내는 방법은 직교 좌표처럼 2개의 인자에서 한개를 추가해서 표현한다. (X, Y, Z) 또는 (12, 4, 15) 처럼 말이다.


수지가 15미터 정도를 하늘로 떳다고 하자. 그러면 (12, 4, -15)가 될 것인가?

기준 위치는 음수인지 양수인지 설정을 할 수 있지만 일반적으로 하늘로 뜨게되면 음수보다는 양수를 사용 할 것이다.

-15는 땅쪽으로 가지 않겠는가?

삼각형 기하학


게임 프로그래밍에 적용되는 3D 좌표 방식을 알아볼 필요가 있다.

3차원 좌표계의 공간에서 위치를 나타내는 경우 정확한 위치의 배열을 형성하여 3D 모델을 나타낼 것이다.

물론 3D 모델을 뿌리는데 많은 설정 및 많은 메모리 공간을 차지하기 때문에 쉽고 빠른 방법으로 나타낼 것이다.

이 방법은 삼각형을 사용하여 설정한다.


삼각형은 모든 수학분야에서 매우 유용한 모양이다.

이것은 삼각형을 측정하기 위해 형성 될 수도 있고, 빌딩을 보강하는데 사용될 수도 있으며, 3D 이미지를 생성하기 위해 사용될 수도 있기 때문이다.

삼각형은 모든 이미지를 형성할 수 있게 배치를 할 수 있으며, 아래와 같은 이미지를 만들때 삼각형을 사용한다.



삼각형으로 만든 모델들


3D 모델을 만드는 삼각형의 유용한 특성 때문에 Direct3D에서 삼각형 모양을 만드는 알고리즘이 단독으로 설계가 되어 있다.

그래서, 삼각형을 구축하기 위해 vertices (정점들) 이라는 것을 사용한다.


Vertices (정점들)은 vertex(정점)이 여러개 있는 것이다. (정점은 꼭지점 이라고 보면 된다, 아니 똑같다)

정점은 3D 공간에서 정확한 지점으로, 세 개의 값 X, Y, Z에 의해 정의된다.

Direct3D에서 그 작은 정점들을 추가할 수 있다. 또 정점들의 다양한 속성을 포함한다. 그래서 "3D 공간에서의 정확한 지점의 대한 속성과 위치"에 의미하는 정의를 확장하게 된다. 쉽게 말하자면 배열에 다양한 속성을 넣는다 생각하면 된다.


삼각형은 각각 시계 방향의 순서대로 프로그램에서 정의되게 되며, 3 개의 꼭지점으로 구성되어 있다.

부호화 할 때, 이 3개의 꼭지점은 회전, 질감, 비치등과 필요에 따라 수정될 수 있는 평평한 표면을 형성한다.




정점들에서의 내장 삼각형


위의 이미지에 표시된 삼각형은 세 가지 점에 의해 생성된다. 좌표는 아래와 같다.


x = 0, y = 5, z = 1

x = 5, y = -5, z = 1

x = -5, y = -5, z = 1


위의 모든 z 값이 1을 가지고 있음을 알 수 있다. 왜냐하면 위의 삼각형은 3D 오브젝트가 아니기 때문이다.

2D 삼각형에서는 저 z 값을 바꾸어 봐야 본질적인 차이가 없을 것이다.


실제 3D 개체를 만드려면 우리는 삼각형을 결합해야 한다. 

위의 그림에서 보다시피 (정점들에서의 내장 삼각형 말고. 삼각형으로 만든 모델들..) 자세히보면 수많은 삼각형들이 결합된 것을 볼 것이다.

간단한 예제를 보면 큐브의 한 면은 두 개의 삼각형이 합쳐진 모습이다. 6개의 면이 동일한 방식으로 삼각형의 조합으로 구성된다.


하지만 저렇게 삼각형을 일일히 조합하는 것은 매우 노가다 적인 일이며, 실로 그 과정은 복잡하기 까지 하다.

그러므로 우리는 그렇게 할 필요가 없고, 다른 도구를 써서 만들게 될 것이다. (다음 글에서 언급하게 될 것이다.)


모델을 만드는 일은 다른 툴이 대신해 주겠지만 우리가 해주어야 할 일은 따로 존재한다.

첫번째로 게임에 들어가는 모든 삼각형의 정점을 정의를 해야하며, 어떤 순서로 등록을 하게 될 것인지, 좌표와 각 정점에 대한 정보를 어디에 포함할 것인지에 대한 정점의 목록을 만들어 주어야 한다.


프리미티브 (Promitives)


프리미티브 (Primitive)는 3D 환경에서 하나의 요소를 가리키며, 삼각형, 선, 점 또는 무엇이든을 가리킨다. 

다음의 프리미티브는 3D 객체를 생성하기 위해 결합 될 수 있는 방법에 대한 목록이다.


1. 점 목록 (Point Lists)

2. 선 목록 (Line Lists)

3. 선 스트립 (Line Strips)

4. 삼각형 목록 (Triangle Lists)

5. 삼각형 조각 (Triangle Strips) 

6. 삼각형 팬 (Triangle Fans) 


1. 점 목록 (Point Lists)


 점 목록은 화면에 점으로 표시된 각각의 정점(Vertices)의 리스트이다.

 3D starfields 렌더링 점선을 만들어 미니 맵에 위치를 표시를 하는 등 유용하게 사용 할 수 있다.

 아래의 그림은 점 목록이 화면에 표시되는 방법을 보여준다. (물론 여기서 좌표는 표시되지 않는다..)


 


점 목록 (6 프리미티브)


2. 선 목록 (Line Lists)


 선 목록은 각 홀수 정점과 다음 정점 사이에 별도의 선 세그먼트를 만들 선에 대한 정점의 목록이다. 

 이러한 선 목록은 자연 효과, 3D 그리드, 굵은 비, 웨이포인트 라인들 등등에 사용할 수가 있다.

 아래의 그림은 선 리스트가 화면에 표시되는 방법에 대해 보여준다.




선 목록 (3 프리미티브)


3. 선 스트립 (Line Strips)


 선 스트립은 선 목록과 비슷하지만, 리스트에 있는 모든 정점이 선분으로 연결되어 있다는 점에서 다르다.

 이 것은 어디에 사용되냐 하면 와이어 프레임 지형, 잔디의 잎 그리고 non-model-based 오브젝트들을 만드는 것에 사용되는데 유용하며,

 디버깅 프로그램에 매우 유용하다.


 


선 스트립 (5 프리미티브)

 

4. 삼각형 목록 (Triangle Lists)


 삼각형 목록은 3개의 정점 리스트를 하나의 삼각형으로 분리를 하는데 사용되는 정점들의 리스트이다.

 이 것이 사용되는 곳은 이펙트의 조성, 포스 필드, 폭팔, 오브젝트의 조각들, 등등에 대해서 쓰인다.


 


삼각형 목록 (2 프리미티브)


5. 삼각형 스트랩 (Triangle Strips)


 삼각형 스트랩은 삼각형 시리즈들을 연결해주는 또 다른 삼각형을 생성하는 정점 리스트이다.

 주로 게임을 위한 3D 모델을 만드는 데 사용되며 3D 그래픽을 처리할 때 가장 많이 사용된다.


 처음 세 개의 정점이 하나의 삼각형을 만들고 각 정점 이후 기존 오브젝트에 따라서 추가 삼각형을 만들어 낼 수 있다.


 


삼각형 스트립 (4 프리미티브)


6. 삼각형 팬 (Triangle Fans)


모든 삼각형이 하나의 정점을 공유한다는것을 제외하고는삼각형 펜은 삼각형 스트립과 비슷하다.




삼각형 펜 (4 프리미티브)


Primitive Quirk (프리미티브 쿼크)


 프리미티브는 렌더링 걸때 대부분 한면에 대해서 보여주는데, 그 이유는 안보이는 면을 렌더링을 걸 필요가 없기 때문이다.

 아주 간단한 예를 들어보자면 아래 그림을 보자.


 


프리미티브를 시계 방향으로만 렌더링 했을때



그렇다. 한 면만 보이기 위해 렌더링을 하게되면 반댓면은 저렇게 바뀌기 때문에 렌더링이 되지 않아 보이지 않게된다.

이러한 문제를 해결하기위해 그냥 간단히 반대로 렌더링을 한번 더 해준다 (...)



프리미티브를 반대로 렌더링 한번더 거쳤을 때




 

색상 (Color)



 색은 3D 프로그래밍에서 비교적 간단한 부분이다. 하지만 컬러 스펙트럼, 물리학, 빛에 대해서 잘 알고있는 경우에도 

 Direct3D가 우주 물리학이나 법칙에 대해서 똑같을꺼라 생각을 하면 안된다. 

 현실과 똑같은 물리나 빛을 구현을 하는 경우 GPU등의 그래픽 프로세서들은 연산중에 터져버릴것이다. 

 그래서 DirectX와 같은 그래픽 라이브러리들은 비슷하게 구현을 할 수 있게 연산하는 방법을 구현해 놓았다.


 빛(Light)는 물론 현실과 같이 주위의 다양한 개체들을 구별 할 수 있도록 하는 입자의 파장이다.

 Direct3D에서 그래픽 하드웨어에 의해 수행되는 다양한 수학적 알고리즘을 담고있는 것중 하나이기도 하며,

 빛(Light)이 Direct3D에서 구현되어 있는 비슷하게 구현 시키는 메커니즘에 대해서 다룰 것이다.


색상 감산(Subtractive Color) vs 색상 첨가(Additive Color)


 보통 초등학생때나 중학생 미술시간 때 색상의 기본 3색을 공부를 했을 것이다.

 빨간색, 초록색, 파란색 으로 말이다. 사실은 이 세개는 다른 색으로 분류된다.

 Magenta, Cyan 그리고 Yellow로. 왜 이렇게 쓸때없는 기술 세부 사항을 알려주는지는 이해하려면 감산 및 첨가의 개념을 이해해야 하기 때문이다.

 

 색상의 차이는 두가지 종류가 있다.

 하나는 빛의 색, 또 하나는 객체의 색 이 두가지 여부로 갈린다.

 감산은 객체의 색상에 대해서이며, 원색의 Magenta, Cyan 및 Yellow를 갖는다.

 첨가는 빛의 색상에 대해서 이며, 적색, 녹색 및 청색 원색을 갖는다.


 빛의 광선에서, 많은 색상들이 합쳐질 수록 흰색을 갖는다. 흰색을 만들기 위해 추가를 하며, 그것을 색상 첨가 (Additive Colors) 이라고 한다.



색상 첨가는 합쳐질 수록 흰색이 되는 것을 말한다.


색상 감산 (Subtractive Color)은 반대라고 보면 된다. 

색상 감산은 대상의 표면에서 반사되지 않는 빛으로 이루어져 있다. 예를들자면 흰색 빛으로 저명을 비췃을대 빨간색 객체는 붉은 빛을 반사하며, 녹색 및 청색 빛을 흡수하게 된다. 위의 이미지를 보면 녹색 및 청색이 결합되는 색상을 볼 것이다. 하지만 색상 감산은 반대이며, 빨간색과 노란색이 결합되는 것이 보일 것이다.




색상 감산은 합쳐질 수록 검정색이 되는 것을 말한다.


그래픽 프로그래밍에서, 모니터는 빛으로 구성되어 있기 때문에 항상 색상 첨가 (Additive Colors)를 사용하게 된다. 

하지만 3D 엔진을 구축할 때, 객체가 색상을 직관적으로 이해할 수 있도록 보이게 하는 것이 좋다.


하지만 출력에서는 Magenta, Cyan, Yellow 색상이 적색, 청색, 녹색으로 화면에서 보인다.


DX 10이후의 게임을 생각하고 있다면 색깔에 대해서나 빛의 물리학에 대해서 철저한 공부가 필요한데, 그렇다면 아래의 링크에 대해서 공부하길 권한다.


링크 (정말 어렵다)


알파 컬러링 (Alpha Coloring)


알파 컬러링은 빛의 적-녹-청 색상에 한가지 요소가 추가된 것이다.

색상에 약간의 알파를 포함하는 경우. 그래픽은 그 수치에 비례하여 반투명으로 나타난다.

게임에서 알파라는 값은 상당히 많은 역할을 차지하며, 수많은 이펙트나 기능에 추가가 될 수 있다.


32 비트를 사용하여 색상 설정


Direct3D의 컬러는 컬러에 대한 모든 정보를 저장하는 32 비트 변수의 형태로 제공한다.

이 컬러는 (적색, 녹색, 청색 RGB 채널을 칭함) 알파 값을 포함한다. 이것들은 각각 채널이라고 칭하며, 여기서 각각 8비트씩 용량을 차지하게 된다.




색상의 비트 레이아웃 (여기서 0~255 니까 32비트가 되겠다.)


코드는 아래와 같아진다.



이 값에 변수를 연결해야 하는 경우 이러한 색상을 구축하는데 사용할 수 있는 DX 함수도 존재한다.



D3DCOLOR_ARGB() 함수는 내가 원하는 색상에 대한 적절한 DWORD형의 값으로 반환한다.

알파값에 대해서도 반환을 받길 원하면 D3DCOLOR_ARGB()를 사용할 수 있으나, 사용하지 않을 경우에는 알파 채널은 자동으로 255값이 들어간다.




빛 (Light)


이 챕터에서는 빛에 대한 모든 것을 다루려고 하지 않는다. 나중에 진행하면서 계속 글을 올릴 것이며, 이 글에서는 기본적인 빛이 뭔지에 대해서만 공부를 할 것이다. 


자연속에서의 빛은 수학적으로 말하기 매우 복잡한 주제이다.

태양이 빛날 때, 거의 모든 것을 볼 수 있도록 태양이 많이 빛나지 않더라도 그것에 의해 볼 수 있게 된다.

태양이 있나 없나의 여부에서 모든 것에 대해 영향을 끼칠 수 있다. 

또한 햇빛이 공간에서 이동함에 따라서 그 중 일부는 완전히 알 수 없는 패턴으로 빛을 산란하여 먼지 입자를 반사하고, 그것들을 수학적 연산을 하게 된다.

컴퓨터가 모든 수를 계산하더라도 연산이 매우 느리기 때문에 실시간으로 실행되지 않을 수 있다.


Direct3D는 실제 환경에서 빛을 사용하는 시스템을 사용한다. 

이러한 시스템을 위해서 이것은 3가지 빛의 타입인 확산광(Diffuse Light), 주변광(Ambient Light), 반사광(Specular Light)을 사용한다.


확산광 (Diffuse Light)


 확산광은 간접적으로 객체에 빛나는 빛이다.

 이 영역은 단독으로 조명 확산에 의해서 보여진다.


 


확산광 (Diffuse Light)


나중에 빛의 근원에 대해 배우게 된다. 이 영역은 어디 왼쪽에서 비춰지고 있으며, 하나의 소스에 의해서 조명이 보여진다.

빛이 멀리에서 비춰질 때 적은 부분은 소스에 의해서 조명이 더 적게 비춰진다.


주변광 (Ambient Light)


주변광은 사방에서 비추는 빛이다. 확산 광과 달리 소스가 없으며, 그리고 단독으로 사용되면 원으로 보일 것이다.

(모든 부분이 조명 아래에서 동일하게 비추기 때문에 그렇게 보일 것이다.)

이 분야는 지난번과 같은 영역이지만, 이번에는 주변 조명이 어두운 부분을 채우기 위해 포함되어 있다.



확산광과 주변광이 합쳐진 모습 (Diffuse and Ambient Lighting)


반사광 (Specular Light)


반사광은 개체를 강조하기 때문에 하이라이트 라고 하기도 한다. 확산 및 주변 광으로 조명 후, 하이라이트가 반사되도록 더 잘 보이게 하기 위해 추가했다.



확산, 주변, 반사광 (Diffuse, Ambient and Specular Lighting)



'Game Programming > Rendering' 카테고리의 다른 글

Rendering :: anti-aliasing  (0) 2016.08.18
DX 9 :: 전체화면  (0) 2016.02.19
DX 9 :: Direct3D 시작  (0) 2016.02.17
DX 9 :: 리얼타임 메시지 루프  (0) 2016.02.16
DX 9 :: 윈도우 생성  (1) 2016.02.16

댓글

VallistA

병특이 끝나서 게임에서 웹으로 스위칭한 프로그래머.
프로그래밍 정보등을 공유합니다.
현재는 이 블로그를 운영하지 않습니다.
vallista.kr 로 와주시면 감사하겠습니다!

자고 싶습니다. ㅠㅠ

Github      :: 링크

궁금한점 문의 주시면 답변드리도록 하겠습니다

VISITED

Today :

Total :

SNS

  • 페이스북아이콘
  • 카카오톡아이콘
  • 트위터아이콘

Lately Post

Lately Comment