이 포스팅에서는 “그래픽스 파이프라인”이 3D 모델의 삼각형과 텍스처를 받아서 최종 화면 이미지를 만드는 과정을 단계별로 설명합니다.
“그래픽스 파이프라인”
그래픽스 파이프라인은 3D 장면을 표현하는 삼각형 메쉬와 텍스처를 입력으로 받아, 모니터에 보여지는 2D 이미지(렌더 타깃)를 만들어 내는 일련의 단계입니다. 이 영상에서는 그중 Direct3D·OpenGL 계열에서 공통적으로 등장하는 “입력 조립 → 정점/테셀레이션/지오메트리 셰이더 → 래스터라이저 → 픽셀 셰이더 → 출력 머저” 흐름을, 수학 대신 개념 위주로 직관적으로 설명합니다. 파란 블록은 라이브러리가 내부에서 처리하는 고정 기능 단계이고, 초록 블록은 우리가 직접 코드를 작성하는 셰이더 단계라는 색 구분도 함께 소개합니다.
입력 조립(Input Assembler)
파이프라인의 시작은 입력 조립(Input Assembler)입니다. 여기서는 메모리에 길게 붙어 있는 버텍스 버퍼에서 “정점 하나가 어떤 속성들(position, UV, normal, color 등)로 이루어져 있는지”를 포맷, 컴포넌트 수, 자료형(예: float32, uint16) 정보를 통해 정의합니다. 이 과정을 통해 각 행이 하나의 정점이 되며, 필요하면 정점 ID 같은 추가 속성도 붙일 수 있습니다.
버텍스 셰이더
이렇게 구성된 정점은 버텍스 셰이더로 넘어가는데, 버텍스 셰이더는 각 정점의 위치를 월드·뷰·투영 행렬 등 외부 데이터를 이용해 변환하여 클립 공간으로 보내고, 최종적으로[−1,1] 범위의 정규화된 장치 좌표(NDC) 큐브 안에 오도록 만듭니다. 이때 UV·노멀 같은 속성은 그대로 전달하거나, 새 색 속성을 계산해 추가할 수도 있어 이후 픽셀 단계에서 사용할 정보를 준비하는 역할을 합니다.
버텍스 셰이더는 행렬을 이용해 정점들을 카메라·클립 공간으로 변환해 [−1,1] 범위의 큐브 안에 들어오게 만들며, 필요하다면 색 같은 새 속성을 추가하거나 기존 속성을 그대로 전달합니다.
테셀레이션
그 다음 테셀레이션 단계는 입력 프리미티브(예: 사각형, 삼각형)를 더 잘게 나누어 삼각형 개수를 늘려 “로우폴리 → 하이폴리”처럼 디테일을 올릴 수 있게 하고, 지오메트리 셰이더는 삼각형·선·점 단위로 새로운 정점을 추가해 머리카락(선 → 두 개의 삼각형), 파티클(점 → 쿼드) 같은 형상을 만들어 냅니다. 이후 래스터라이저는 삼각형들을 화면의 픽셀 그리드로 옮겨 어떤 픽셀들이 삼각형 안에 있는지 결정하고, 그 픽셀마다 보간된 UV·노멀 등의 속성을 픽셀 셰이더로 넘깁니다.
지오메트리 셰이더
테셀레이션과 지오메트리 셰이더는 선택적인 기하 단계입니다. 테셀레이션 단계는 낮은 해상도의 사각형이나 삼각형 패치를 입력으로 받아, 패턴을 정의하는 Hull Shader와 패턴에 따라 실제 위치를 정하는 Domain Shader를 통해 더 세분화된 삼각형들로 쪼개어 하이폴리 모델처럼 보이게 할 수 있습니다. 지오메트리 셰이더는 삼각형, 선, 점 같은 프리미티브 단위로 입력을 받아, 인접 정점 정보를 활용해 새로운 정점을 추가하거나 프리미티브의 형태를 바꾸는 데 사용되며, 머리카락을 선에서 두 개의 삼각형 스트립으로 확장하거나, 점을 화면에 보이는 쿼드로 바꾸는 파티클 렌더링 등에 활용됩니다. 이 단계들까지 지나면 모든 정점·프리미티브는 최종 화면에서의 위치가 결정된 상태가 됩니다.
래스터라이저: 삼각형 표면이 카메라에 가까울수록 색상은 더 어두워집니다.
이제 래스터라이저 단계가 3D 프리미티브를 2D 픽셀 그리드로 변환합니다. 래스터라이저는 각 삼각형이 화면의 어떤 픽셀들을 덮는지 계산하고, 그 픽셀 위치에서의 보간된 속성(예: 위치, 깊이 Z, UV, 노멀)을 생성해 픽셀 셰이더로 넘겨 줍니다. 이 과정에서 프러스텀 밖으로 나간 부분은 클리핑되고, 뒤를 보는 면(back face)은 컬링될 수 있어 불필요한 픽셀 처리를 줄입니다. 픽셀 셰이더는 이렇게 전달된 한 픽셀 단위 속성을 입력으로 받아, 텍스처와 샘플러, 조명 계산 등을 이용해 최종 색을 계산하며, 동시에 해당 픽셀의 깊이 값도 함께 출력합니다.
픽셀 셰이더
픽셀 셰이더는 각 픽셀에 대해 텍스처와 샘플러를 이용해 색을 계산하고, 동시에 Z 값(깊이)도 함께 넘겨 줍니다. 출력 머저(Output Merger)는 이 색·깊이와 기존 렌더 타깃의 색, 깊이 버퍼를 비교해 더 카메라에 가까운 픽셀만 렌더 타깃에 쓰고 깊이 버퍼를 갱신하며, 필요하면 두 색을 섞는 블렌딩을 수행해 반투명 효과를 만듭니다. 이렇게 해서 파란 삼각형 앞/뒤에 있는 빨간 삼각형처럼, 카메라에 가까운 물체가 멀리 있는 물체를 가리는 올바른 장면이 실시간으로 그려집니다.
출력 머저(Output Merger)
마지막 출력 머저(Output Merger)는 픽셀 셰이더가 내놓은 색·깊이와 기존 렌더 타깃, 깊이 버퍼를 이용해 어떤 픽셀을 실제 화면에 쓸지 결정합니다. 깊이 버퍼(또는 Z 버퍼)는 각 픽셀 위치에서 지금까지 가장 카메라에 가까웠던 깊이 값을 저장하고 있으며, 새 픽셀이 들어오면 그 깊이와 비교해 더 가까우면 색과 깊이를 갱신하고, 더 멀면 버립니다. 이 덕분에 빨간 삼각형이 파란 삼각형 뒤에 있을 때 자동으로 가려지며, 필요하면 기존 색과 새 색을 섞는 블렌딩을 사용해 반투명 물체나 파티클을 자연스럽게 표현할 수 있습니다. 이런 모든 단계가 초당 수십 번 반복되면서, 게임이나 응용 프로그램에서 보는 부드러운 실시간 3D 그래픽이 만들어집니다.