DirectX로 엔진 만들기 #2

Tesselator 단계

HullShader → Tesselation → DomainShader

 

테셀레이터는 다각형을 겹치지 않고 작게 만들어 빈틈을 없애 게임 등에서 사물 등을 실제에 보다 더 가깝게 표현할 수 있게 도와주는 기술이다.

  • HullShader

Vertex Shader에서 공간 변환을 진행하지 않고 Hull Shader 정점 정보들을 전달해준다.

Hull Shader는 폴리곤을 어떻게, 얼마나 분할 할 것인가? 를 결정하는 단계이다.

 

  • Domain Shader

테셀레이터가 출력한 정점마다 한 번씩 함수(셰이딩 언어) 호출을 해주게 된다.

테셀레이션이 활성화되면 기존의 정점 쉐이더에서 수행한 것들을 도메인 셰이더에서 수행하게 된다.

예를 들면, 공간변환(World → View → 투영)이 될 수 있다.

 

하지만 자주 사용되는 기술은 아니다! 실제 게임을 제작할 때는 정점이 적은 로우폴리곤과 정점이 많은 하이폴리곤 모델 두 개를 따로 지원하는 경우가 많다.

 

Geometry Shader

기본 폴리곤에서 정점을 추가하거나 삭제하거나 하는 연산을 할 수 있다. 정점 정보를 추가하여 표현할 수 있는 모델이라면 그만큼의 정점 정보를 빼고 저장할 수 있으니 메모리적으로 용량을 적게 차지할 수도 있고, GPU 도움을 받아서 정점을 추가해주기 때문에 연산 속도가 빨라질 수 있다.

 

Rasterization

정점처리 단계를 지난 정점은 다음 단계인 레스터라이저 단계로 넘어간다. 우선 정점들은 삼각형으로 묶여있는데, 이 시점부터는 하나의 독자적인 도형으로 처리가 된다. 화면에 그려질 2차원 삼각형의 세 정점이 결정되면 다음과 같은 일이 일어난다.

 

1. 이 삼각형이 포함하는 모든 픽셀마다 Pixel Shader(Fragment Shader)가 실행된다.

2. 삼각형의 세 정점에 할당되었던 여러 데이터(pos, uv, normal, color)가 보간되어 삼각형 내부에 각 픽셀셰이더로 넘어온다.

 

DirectX에서는 이러한 과정을 통틀어서 레스터라이제이션이라 부르고, 자체 알고리즘으로 알아서 동작하는 고정 파이프라인 단계로, 프로그래머가 이러한 로직들을 임의로 바꿀 수 없는 파이프라인 단계다.

 

대표적인 레스터라이제이션의 역할!

더보기
  • 클리핑(clipping)
  • 원근 나눗셈(perspective division)
  • 뒷면 제거(back-face culling)
  • 뷰포트 변환(view-port transform)
  • 스캔 변환(scan transform)

 

클리핑

투영변환 이후의 클립공간 볼륨 바깥에 놓인 폴리곤들을 잘라내는 작업. 레스터라이저 단계에서 일어난다.

 

원근 나눗셈

현재 단계에서 투영변환을 통해 원근법이 적용된 3차원 물체들을 직육면체 클리핑 공간에서 정의되어 있다.

우리가 최종적으로 필요한 건 2차원 공간인데, 어떻게 수학적으로 3차원 공간을 2차원 공간으로 변환시킬 수 있을까?

단순히 생각하면 3차원에서 2차원으로 줄이면 된다. 바로 Z좌표로 모든 성분을 나눠버리는 것이다. 투영변환을 마친 정점데이터는 (x, y, z, w)에서 w성분에 z값이 저장된다. 원근 나눗셈이 적용된 이후에는 (x, y, z, w) → (x, y, z)의 좌표계로 변환되는데 이를 NDC(Normalize Device Coordinate) 공간이라 한다. 여기서 정규화라는 이름이 붙는 이유는, 이 좌표의 xy 범위는 [-1 ~ 1], z의 범위는 [0 ~ 1]이기 때문이다.

 

뒷면 제거

카메라가 바라보고 있는 방향에 물체로 가려진 면적은 굳이 연산을 할 필요가 없다. 외적(Cross Product) 삼각형의 바라보고 있는 면의 방향을 구해 뒷면일 경우에 연산에서 제외시킨다.

 

뷰포트 변환

컴퓨터 화면 상의 윈도우 스크린 공간을 가지는 경우, 이 스크린 공간 내에 2차원 이미지가 그려질 뷰포트가 정의되는 데에 NDC 공간의 물체들을 스크린 공간으로 이전시키는 변환을 뷰포트 변환이라고 한다.

 

스캔 변환

이전의 변환들은 자세한 사항을 몰라도 프로그래밍을 하는 데에 문제가 없었지만, 스캔 변환은 렌더링 프로그램에서 직접적인 영향을 미치기 때문에 매우 중요하다. 스캔 변환은 삼각형 하나가 내부에 차지하는 모든 픽셀(Fragment)들을 생성하는 작업이다. 이 때 정점데이터에 들어온 데이터들은 보간(선형 보간)되어서 픽셀셰이더로 넘어간다.

 

Pixel Shader

레스터라이저를 거친 도형에 원하는 색을 입혀서 출력하게 도와주는 셰이더. 텍스처매핑, 노말매핑 등 기법으로 색을 입혀서 표현도 가능하다. 조명 처리나 이미지 처리를 할 때 유용하게 사용된다. 이 때 정점 데이터가 보간된 값이 넘어온다.

 

Output Merger

깊이 - 스텐실 테스트와 블렌딩이 일어나서 최종적인 화면(텍스터)에 물체를 그려준다.

 

그리기 전

 

그리기 후

 

Compute Shader

컴퓨트 셰이더는 일반 렌더링 파이프라인과 별도로 그래픽카드를 사용할 때 실행할 수 있도록 도와주는 셰이더이다. 대량 병렬 GPGPU 알고리즘 또는 게임 렌더링의 일부를 가속시키기 위해서 사용할 수 있다. 효율적으로 사용하려면 GPU 아키텍처와 병렬 알고리즘에 대한 지식 뿐만 아니라 DirectXComput, OpenGL Compute, CUDA, OpenCL에 대한 지식도 필요하다.

 

 

 

참고) https://www.youtube.com/watch?v=ETDgyFRyT_8&list=PLWKwcHKTXy5T5v_qSsvUnjFZG85pDOZPq&index=2

'WinAPI, DirectX' 카테고리의 다른 글

WinAPI로 엔진 만들기 #1  (0) 2024.09.12
DirectX로 엔진 만들기 #1  (0) 2024.09.12