게임 엔진을 처음 공부하기 시작하면 언젠가 반드시 만나게 되는 단어가 있습니다.
바로 렌더링 파이프라인(Rendering Pipeline) 입니다.
특히 DirectX나 OpenGL, Vulkan 같은 그래픽 API를 공부하기 시작하면 렌더링 파이프라인 각 단계와 마주하게 됩니다.
- Input Assembly
- Vertex Shader
- Rasterizer
- Pixel Shader
- Output Merger
지금 나열한 목록은 최근 그래픽스 API에서 제공하는 렌더링 파이프라인의 일부입니다.
필수적으로 필요한 목록만 나열해봤습니다.
그럼에도 처음에는 이런 이름들이 굉장히 어렵게 느껴집니다.
이러한 렌더링 파이프라인은 단순 그래픽 API 구조가 아니라, GPU가 화면 이미지를 만들어내기 위해 발전해온 과정입니다.
그리고 게임 엔진 역시 화면에 이미지를 그려야하는 프로그램이기 때문에 렌더링 파이프라인을 떼 놓고 이해할 수 없습니다.
아래의 다양한 렌더링 관련 개념들도 결국 렌더링 파이프라인과 연관되어 있습니다.
- Draw Call
- Material
- Mesh
- Shader
- GPU Instancing
- Deferred Rendering
이번 시리즈에서는 렌더링 파이프라인의 각 단계가 왜 존재하는지,
GPU는 실제로 어떤 작업을 수행하는지,
그리고 CPU는 GPU를 위해 어떤 준비를 하는지를 단계별로 자세하게 정리해보려고 합니다.
게임 엔진은 단순히 “그림”을 보여주는 프로그램이 아니다
처음 게임을 보면 굉장히 자연스럽게 화면이 출력되는 것처럼 느껴질 수 있습니다.
캐릭터가 움직이고, 빛이 반사되며, 수많은 오브젝트들이 화면에 등장합니다.
너무 자연스럽기 때문에:
“원래 게임은 화면에 그려지는 것 아닌가?”
처럼 느껴질 수도 있습니다.
하지만 실제 게임 엔진 내부에서는 생각보다 굉장히 많은 계산 과정이 계속 이루어지고 있습니다.
- 어떤 오브젝트를 그릴지 결정하고
- 객체 위치를 계산하며
- 카메라 기준으로 공간을 변환하고
- GPU에게 렌더링 명령을 전달합니다.
이렇게 GPU에 렌더링 명령이 전달되면 GPU는 아래의 작업들을 처리합니다.
- 정점(Vertex)을 변환하고
- 삼각형을 조립하며
- 픽셀 후보를 생성하고
- 최종 색상을 계산합니다.
즉, 게임 화면은 단순한 어떤 이미지를 출력한 결과가 아니라, 수많은 공간 계산과 변환 과정을 거쳐서 만들어지는 결과물입니다.
게임 안의 객체는 처음부터 화면 위에 존재하지 않는다
게임 안의 객체들은 처음부터 화면 좌표 형태로 존재하는 것이 아닙니다.
GPU가 화면을 그리는 과정인 렌더링 파이프라인을 이해할 때 이 점을 이해하는 것이 중요합니다.
예를 들어 게임 안의 캐릭터는 아래와 같은 위치 데이터를 갖습니다.
Position = { 100, 20, -50 }
즉, 가상 공간에 배치된 게임 객체는 3D 공간 안에 존재합니다.
하지만 우리가 실제로 보는 모니터는 결국 2D 화면입니다.
따라서 게임 엔진은 3D 공간 정보를 2D 화면 이미지로 변환해야 합니다.
그리고 이 과정이 바로 렌더링의 핵심입니다.
렌더링 파이프라인을 이해하기 전에 이 과정이 무엇을 처리하기 위한 과정인지를 이해하면 각 단계를 더 깊이 이해하는데 도움이 됩니다.
렌더링 파이프라인이 등장한 이유
3D 공간 정보를 2D 화면 이미지로 바꾸는 과정이 왜 이렇게 복잡할까요?
처음에는 “그냥 GPU가 화면을 바로 그리면 되는 것 아닌가?”하는 생각이 들 수도 있습니다.
하지만 실제 그래픽 계산은 생각보다 훨씬 복잡합니다.
단순히 픽셀 색상만 계산하는 것이 아니라,
먼저 객체의 위치를 월드 공간 기준으로 변환해야 하고,
카메라 기준 공간으로 다시 계산하는 뷰 변환(View Transform)과 투영 변환(Projection Transform)도 필요합니다.
그리고 이렇게 변환된 삼각형(Polygon)은 다시 화면 위 픽셀 형태로 변환되는 래스터화(Rasterization) 과정을 거치게 됩니다.
이후에야 비로소 최종 픽셀 색상을 계산할 수 있게 됩니다.
그리고 이런 작업들은 모두 성격이 서로 다릅니다.
- 어떤 작업은 정점 단위 계산에 가깝고
- 어떤 작업은 픽셀 단위 계산에 가깝습니다.
즉, GPU 입장에서도 3D 공간 정보를 2D 화면 이미지로 변환하는 과정에서 처리해야 하는
여러 계산의 흐름을 체계적으로 분리할 필요가 있습니다.
그리고 이런 이유 때문에 렌더링 작업은 여러 단계로 분리되어 처리됩니다.
즉, 렌더링 파이프라인은 단순 API 구조가 아니라,
그래픽 계산을 효율적으로 처리하기 위해 발전한 구조라고 할 수 있습니다.
초기의 GPU는 지금과 구조가 많이 달랐다
흥미로운 점은 초기의 GPU는 지금처럼 자유롭게 프로그래밍 가능한 구조가 아니었다는 점입니다.
초기 그래픽 파이프라인은 고정 파이프라인(Fixed Pipeline) 구조에 가까웠습니다.
즉, GPU 내부 계산 흐름이 어느 정도 고정되어 있었습니다.
- 조명 계산 방식
- Texture 계산 방식
- Vertex 처리 방식
하지만 게임 그래픽 기술이 발전하기 시작하면서 문제가 생기기 시작했습니다.
개발자들은 다양한 작업을 게임에 적용하기를 원했습니다.
- 더 다양한 조명
- 더 사실적인 재질
- 특수 효과
- 후처리 효과
기존에 GPU에서 고정적으로 처리하는 계산들을 개발자가 직접 제어할 수 있어야 가능한 것들이었습니다.
그리고 이를 위해 셰이더(Shader)가 등장하게 됩니다.
현대 GPU는 “프로그래밍 가능한 파이프라인”으로 발전했다
최근의 GPU는 프로그래밍 가능한 파이프라인(Programmable Pipeline) 구조를 사용합니다.
즉, GPU가 내부적으로 계산하는 작업의 일부를 개발자가 직접 작성할 수 있습니다.
대표적인 것이 정점 셰이더와 픽셀 셰이더입니다.
- Vertex Shader
- Pixel Shader
GPU는 이미지 출력을 위한 단순 계산 장치를 넘어서, 프로그래밍 가능한 병렬 계산 장치로 발전하기 시작했습니다.
그리고 이렇게 발전한 GPU를 가장 잘 활용한 프로그램 중 하나가 게임과 게임 엔진입니다.
게임의 그래픽이 굉장히 복잡한 처리를 필요로하기 때문입니다.
- Material
- Lighting
- Post Processing
- Rendering Technique
렌더링 파이프라인은 결국 “변환의 흐름”이다
처음 렌더링 파이프라인을 배우면 굉장히 복잡하게 느껴집니다.
- Vertex 데이터를 읽고
- World 공간으로 변환하며
- Camera 기준 공간으로 변환하고
- 화면 좌표로 변환한 뒤
- 픽셀 이미지로 변환합니다.
하지만, 각 단계를 하나씩 살펴보면 결국 3D 공간을 2D 화면 이미지로 변환하기 위한 단계라는 것을 알게됩니다.
Vertex Data ↓ Input Assembly ↓ Vertex Shader ↓ Rasterizer ↓ Pixel Shader ↓ Output Merger ↓ Frame Buffer
그리고 이 과정에서 변환을 더 효율적으로 그리고 우리가 원하는 대로 처리하기 위한 다양한 개념들이 추가로 등장합니다.
- Matrix
- Camera
- Shader
- Rasterization
CPU와 GPU는 서로 역할이 다르다
렌더링 파이프라인을 이해할 때 굉장히 중요한 부분 중 하나가 바로 CPU와 GPU 역할 차이를 이해하는 것입니다.
CPU는 일반적으로 최종 화면 렌더링 위한 준비 과정을 처리합니다.
- 게임 로직 처리
- 물리 계산
- 애니메이션 계산
- 렌더링 준비
그리고 GPU는 실제 렌더링 계산을 수행합니다.
- 정점 변환
- 삼각형 처리
- 래스터화(Rasterization)
- 픽셀 계산
즉, 게임 그래픽은 결국 CPU와 GPU가 협력하면서 이미지를 생성하는 과정이라고 할 수 있습니다.
그리고 렌더링 파이프라인은 이 CPU와 GPU 협력 구조를 이해하는 데 굉장히 중요한 개념입니다.
이번 시리즈에서는 무엇을 다룰까?
이번 시리즈에서는 렌더링 파이프라인 각 단계가 왜 존재하는지,
그리고 실제 GPU 내부에서는 어떤 계산이 이루어지는지를 단계별로 정리해보려고 합니다.
예를 들어
– Input Assembly 단계는 왜 필요한가
– Vertex Shader는 왜 등장했는가
– Rasterizer는 무엇을 하는가
– Pixel Shader는 실제로 무엇을 계산하는가
같은 내용들을 다루고자 합니다.
그리고 단순 기능 설명보다는 “왜 이런 구조가 필요해졌는가”를 중심으로 흐름을 정리해보려고 합니다.
마무리
게임 엔진을 공부하다 보면 렌더링 파이프라인이라는 단어가 자주 등장합니다.
이 단어가 나올 때마다 굉장히 어렵고 복잡하게 느껴질 수도 있습니다.
하지만 렌더링 파이프라인 각 단계를 하나씩 익히고, 이 개념의 목적을 이해하다 보면
GPU가 화면 이미지를 만들어내기 위해 발전해온 구조라는 것을 알게됩니다.
그리고 이런 흐름을 이해하기 시작하면 아래 나열한 다양한 개념들이 등장한 이유도 이해할 수 있습니다.
- Shader
- Draw Call
- Rasterizer
- Deferred Rendering
다음 글에서는 렌더링 파이프라인의 첫 단계인 Input Assembly 단계가 왜 필요한지,
그리고 GPU는 왜 Vertex 데이터를 “조립”하기 시작했는지를 이어서 정리해보려고 합니다.