렌더링 파이프라인 완벽 이해 – Output Merger 단계는 왜 필요할까?

이전 글에서는 Pixel Shader 단계가 왜 필요한지를 정리했습니다.

Pixel Shader 단계에서는 Fragment마다 최종 색상을 계산하게 되며,
Texture Sampling, 조명 계산, Material 표현 같은 다양한 그래픽 처리들이 이 단계에서 수행된다는 점도 함께 살펴봤습니다.

그리고 이 과정을 이해하면 최근의 그래픽스 기법들이 왜 점점 Shader 중심으로 발전하게 되었는지도 이해할 수 있습니다.

이번 글에서는 렌더링 파이프라인의 마지막 단계 중 하나인 Output Merger 단계에 대해 정리해보려고 합니다.

지금까지의 단계에서는 삼각형을 구성하고,
공간 변환을 수행하며,
픽셀 색상을 계산하는 과정들을 살펴봤습니다.

하지만 Pixel Shader 단계에서 색상 계산이 끝났다고 해서 곧바로 화면 출력이 완료되는 것은 아닙니다.

GPU는 여전히 최종 픽셀을 실제 화면 버퍼에 어떻게 기록할 것인지 결정해야 합니다.

그리고 이 과정에서 Depth Test, Blending, Frame Buffer 같은 개념들이 등장하게 됩니다.

Output Merger 단계는 최종 화면 이미지를 완성하는 단계입니다.


Pixel Shader가 끝났다고 화면 출력이 완료되는 것은 아니다

Pixel Shader 단계가 끝나면 GPU는 Fragment마다 최종 색상 값을 계산하게 됩니다.

이 시점까지 오면 화면 출력이 모두 끝난 것처럼 느껴질 수도 있습니다.

하지만 실제로는 아직 중요한 과정이 하나 더 남아 있습니다.

GPU는 여전히 어떤 픽셀이 실제 화면에 기록되어야 하는지를 판단해야 하기 때문입니다.

예를 들어 화면 위에 여러 삼각형이 서로 겹쳐 있는 상황을 생각해보겠습니다.

이 경우 단순히 마지막으로 계산된 픽셀을 그대로 출력해버리면 올바른 화면 결과가 만들어지지 않을 수 있습니다.

카메라에 더 가까운 객체가 앞에 보여야 하고, 뒤쪽 객체는 가려져야 합니다.

예를 들어 캐릭터 앞에 벽이 존재한다면, 벽 뒤에 있는 캐릭터 픽셀은 실제 화면에 보이면 안 됩니다.

따라서 GPU는 Pixel Shader 단계에서 계산된 색상을 곧바로 화면에 기록하지 않습니다.

대신 현재 픽셀이 기존 픽셀보다 더 앞에 있는지,
실제로 최종 화면에 남아야 하는 픽셀인지를 한 번 더 판단하게 됩니다.

그리고 바로 이런 작업들이 Output Merger 단계에서 수행됩니다.

즉, Output Merger 단계는 단순 출력 단계가 아니라,
최종 화면 결과를 결정하기 위한 마지막 판단 과정에 가깝다고 볼 수 있습니다.


왜 이름이 “Output Merger”일까?

Output Merger라는 이름은 여러 출력 결과를 하나로 병합(Merge)한다는 의미입니다.

하지만 Pixel Shader 단계에서 계산된 색상 결과만 사용해 병합하지 않습니다.

GPU는 현재 Fragment의 색상 결과와 Depth Buffer 정보,
그리고 기존 Frame Buffer 안에 저장되어 있는 값들도 함께 비교하고 조합합니다.

예를 들어 현재 Fragment가 기존 픽셀보다 카메라에 더 가까운 위치에 있는지를 판단할 수도 있습니다.

만약 기존 픽셀보다 더 뒤에 있는 Fragment라면 실제 화면에는 보이지 않아야 하기 때문에 최종 출력 대상에서 제외될 수 있습니다.

반대로 투명 객체처럼 색상을 섞어야 하는 상황도 존재합니다.

유리창이나 반투명 파티클 같은 경우에는
기존 화면 색상과 현재 Fragment 색상을 함께 조합해야 자연스러운 결과를 만들 수 있습니다.

따라서 Output Merger 단계에서는 단순히 Pixel Shader에서 계산된 새로운 픽셀을 기록하는 것이 아니라,
기존 화면 데이터와 새로운 계산 결과를 함께 비교하고 조합하는 과정이 진행됩니다.

그리고 이런 이유 때문에 “Output Merger”라는 이름이 붙었다고 할 수 있습니다.

즉, 이 단계는 단순한 렌더링 파이프라인의 마지막 출력 단계가 아니라,
최종 화면 이미지를 완성하기 위한 조합 단계라고 할 수 있습니다.


Depth Buffer는 왜 필요할까?

렌더링 파이프라인을 공부하다 보면 Depth Buffer라는 개념이 등장합니다.

Depth Buffer는 화면 위에서 어떤 객체가 더 앞에 있는지를 판단하기 위해 사용됩니다.

예를 들어 같은 화면 위치에 캐릭터와 벽이 함께 존재한다고 가정해보겠습니다.

이 경우 GPU는 두 객체 중 어떤 픽셀을 실제 화면에 보여줘야 하는지를 결정해야 합니다.

만약 단순히 나중에 계산된 픽셀만 화면에 출력한다면 올바른 결과를 만들 수 없습니다.

벽 뒤에 있는 캐릭터가 화면 위로 튀어나와 보이는 문제가 발생할 수도 있기 때문입니다.

따라서 GPU는 각 픽셀이 카메라로부터 얼마나 떨어져 있는지에 관한 정보도 함께 저장해 관리합니다.

이를 위해 사용되는 것이 바로 Depth Buffer입니다.

Depth Buffer에는 픽셀마다 깊이값(Z값)이 저장됩니다.

GPU는 새로운 Fragment가 들어올 때 기존에 저장되어 있는 Depth 값과 현재 Fragment의 Depth 값을 비교합니다. 그리고 카메라에 더 가까운 픽셀만 실제 화면에 남깁니다.

이 과정을 보통 Depth Test라고 부릅니다.

즉, GPU는 단순히 색상만 계산하는 것이 아니라,
각 픽셀이 실제로 화면에 보여야 하는지도 함께 판단하고 있는 것입니다.

따라서 Output Merger 단계는 단순 색상 출력 단계가 아니라,
실제 화면에서 어떤 픽셀이 최종적으로 남아야 하는지를 결정하는 단계라고 볼 수 있습니다.

그리고 이 Depth Buffer 덕분에 최신 GPU는 복잡한 3D 공간에서도 올바른 가림(Visibility) 처리를 할 수 있게 되었습니다.


왜 투명 객체 처리가 어려울까?

Output Merger 단계를 이해하면 왜 투명 객체 처리가 어려운지도 함께 보이기 시작합니다.

불투명 객체는 비교적 단순한 편입니다.

Depth Test를 수행해서 카메라에 더 가까운 픽셀만 화면에 남기면 대부분 올바른 결과를 만들 수 있기 때문입니다.

예를 들어 벽 뒤에 있는 객체는 Depth Test 과정에서 자연스럽게 가려지게 됩니다.

하지만 투명 객체는 상황이 훨씬 복잡해집니다.

예를 들어 유리창을 생각해보겠습니다. 유리는 단순히 자신의 색상만 출력되는 것이 아닙니다.

뒤쪽에 있는 객체가 일부 보이면서도,
유리 자체의 색상과 반사 느낌 역시 함께 표현되어야 합니다.

따라서 단순히 더 가까운 픽셀만 남기는 방식으로는 올바른 결과를 만들 수 없습니다.

이 경우 GPU는 기존 화면 색상과 현재 Fragment 색상을 서로 섞는 작업을 수행하게 됩니다.

그리고 이 과정을 Blending이라고 부릅니다.

예를 들어 반투명 파티클 효과나 유리 재질 표현 같은 경우에는 현재 픽셀 색상만 사용하는 것이 아니라,
이미 Frame Buffer 안에 존재하는 기존 색상 결과도 함께 고려해야 합니다.

따라서 투명 객체는 렌더링 순서(Render Order) 역시 굉장히 중요해집니다.

잘못된 순서로 렌더링하면 뒤쪽 객체가 비정상적으로 보이거나,
투명 효과가 깨져 보이는 문제가 발생할 수도 있기 때문입니다.

결국 Output Merger 단계에서는 단순히 픽셀을 기록하는 작업만 수행되는 것이 아니라,
최종 화면 이미지를 자연스럽게 만들기 위한 다양한 조합 작업들도 함께 수행된다고 볼 수 있습니다.

그리고 이런 이유 때문에 투명 객체 렌더링은 지금도 그래픽스 프로그래밍에서 비교적 까다로운 주제 중 하나입니다.


Frame Buffer는 무엇일까?

Output Merger 단계를 이해하기 위해서는 Frame Buffer 개념도 함께 알아둘 필요가 있습니다.

Frame Buffer는 GPU가 최종 화면 이미지를 저장하는 메모리 공간입니다.

Pixel Shader 단계에서 계산된 색상 결과는 곧바로 모니터로 출력되는 것이 아닙니다.

먼저 GPU 내부의 Frame Buffer 안에 기록된 다음, 이 결과가 실제 화면으로 전달됩니다.

즉, GPU는 매 프레임 새로운 화면 이미지를 메모리 안에서 계속 만들고 있는 것입니다.

예를 들어 게임 화면에 캐릭터와 배경, UI,
파티클 효과 같은 다양한 요소들이 함께 출력된다고 가정해보겠습니다.

GPU는 이 요소들을 하나씩 계산하면서 최종 색상 결과를 Frame Buffer 안에 계속 기록해 둡니다.

그리고 모든 계산이 끝난 뒤, 완성된 Frame Buffer 결과가 실제 모니터 화면으로 출력됩니다.

따라서 Frame Buffer는 현재 프레임의 최종 화면 이미지를 구성하는 공간이라고 할 수 있습니다.

그리고 Output Merger 단계는 바로 이 Frame Buffer를 실제로 갱신하는 역할을 담당하게 됩니다.

Depth Test, Blending, 최종 픽셀 기록 같은 작업들이 모두 이 과정 안에서 수행됩니다.

즉, 렌더링 파이프라인의 마지막 단계에서는
지금까지 계산된 결과들을 최종 화면 이미지 형태로 완성해가는 작업이 처리됩니다.


Output Merger 단계가 중요한 이유

Output Merger 단계는 렌더링 파이프라인의 마지막 단계입니다.

그래서 얼핏 보면 지금까지 계산된 결과를 단순히 화면에 출력하는 단계라고 생각할 수도 있습니다.

하지만 실제로는 최종 화면 결과를 결정하는 굉장히 중요한 역할을 담당하고 있습니다.

이 단계에서는 단순히 Pixel Shader 결과를 기록하는 것만 수행되지 않습니다.

Depth Test를 통해 어떤 픽셀이 실제 화면에 보여야 하는지를 판단하고,
Stencil Test를 이용해서 특정 영역만 렌더링하도록 제한할 수도 있습니다.

또한 Blending 과정을 통해 기존 화면 색상과 새로운 Fragment 색상을 자연스럽게 섞는 작업도 함께 이루어집니다.

특히 최근 게임 그래픽에서는 반투명 표현이나 파티클 효과,
UI 합성,
후처리 효과 같은 다양한 기술들이 적극적으로 사용됩니다.

예를 들어 연기 효과나 빛 번짐(Bloom) 같은 표현들은 단순히 픽셀 하나만 계산해서 끝나는 것이 아니라,
기존 화면 결과와 새로운 결과를 함께 조합하는 과정이 필요합니다.

그리고 이런 작업들의 상당수는 결국 Output Merger 단계와 연관되어 있습니다.

즉, Output Merger 단계는 단순히 “마지막 출력 단계”라기보다,
지금까지 계산된 결과들을 실제 화면 이미지 형태로 완성하는 단계라고 할 수 있습니다.

따라서 렌더링 파이프라인에서 이 단계는 최종 화면 품질과 직접적으로 연결되는 중요한 단계 중 하나입니다.


렌더링 파이프라인은 결국 화면 이미지를 만드는 과정이다

여기까지 렌더링 파이프라인의 핵심 흐름을 따라오면서 GPU가 화면 이미지를 어떻게 만들어가는지 단계별로 살펴봤습니다.

처음에는 Vertex 데이터를 조립하고(Input Assembly 단계),
이후에는 공간 변환을 수행하며(Vertex Shader 단계),
삼각형 내부의 픽셀 후보(Fragment)를 생성(Rasterizer 단계)합니다.

그리고 Pixel Shader 단계에서는 최종 색상을 계산하고,
마지막으로 Output Merger 단계에서 실제 화면 버퍼에 결과를 기록하게 됩니다.

Input Assembly > Vertex Shader > Rasterizer > PixelShader > Output Merger

즉, 렌더링 파이프라인은 단순히 그래픽스 API 안에 존재하는 기능 목록이 아니라,
GPU가 화면 이미지를 만들기 위해 발전해온 계산 공정 자체라고 할 수 있습니다.

또한 이 과정은 각각 독립적인 단계로 따로 존재하는 것이 아닙니다.

이전 단계에서 계산된 결과가 다음 단계로 계속 전달되면서 하나의 흐름처럼 이어지게 됩니다.

예를 들어 Vertex Shader 단계에서 수행된 공간 변환 결과는 Rasterizer 단계로 전달되고,
Rasterizer 단계에서 생성된 Fragment와 보간 데이터는 다시 Pixel Shader 단계에서 사용됩니다.

그리고 Pixel Shader에서 계산된 최종 색상 결과는 Output Merger 단계에서 실제 화면 이미지로 완성됩니다.

이전 단계의 출력이 다음 단계의 입력이라는 것을 이해하는 것은 그래픽스 프로그래밍을 학습할 때 굉장이 중요합니다.

따라서 렌더링 파이프라인은 단순한 순서 나열이라기보다,
GPU 내부에서 화면 이미지를 만들기 위해 이어지는 거대한 계산 흐름이라고 이해하는 것이 훨씬 중요합니다.

이 흐름을 전체 기준으로 이해하기 시작하면 최근 GPU 구조와 게임 엔진 렌더링 구조 역시 훨씬 자연스럽게 보이기 시작합니다.

또한 Draw Call, Material, Deferred Rendering, Post Processing 같은 다양한 그래픽 개념들도 결국
렌더링 파이프라인이라는 거대한 흐름 위에서 동작하고 있다는 점도 이해할 수 있습니다.


마무리

Output Merger 단계는 Pixel Shader 결과를 실제 화면 버퍼(Frame Buffer)에 기록하는 마지막 단계입니다.

하지만 실제로는 단순 출력만 수행하는 것이 아니라,
Depth Test, Blending, Frame Buffer 갱신 같은 중요한 작업들도 함께 처리합니다.

그리고 이 과정을 통해 GPU는 최종적으로 화면 이미지를 완성합니다.

지금까지의 시리즈에서는
Input Assembly,
Vertex Shader,
Rasterizer,
Pixel Shader,
Output Merger 단계가 왜 필요한지를 순서대로 정리해보았습니다.

다음 글에서는 지금까지 살펴본 전체 렌더링 파이프라인 흐름을 다시 정리하면서 CPU와 GPU가 실제로 어떻게 협력하면서 화면 이미지를 만들어내는지를 이어서 정리해보려고 합니다.


👉 게임 엔진 구조를 더 깊이 이해하고 싶다면

아래 강의를 통해 직접 구현해보는 것을 추천드립니다.

C++로 만드는 게임 엔진 프레임워크 강의

👉 C++로 만드는 게임 엔진 프레임워크 강의 바로가기

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다