포워드 렌더링 방식에서는 지오메트리를 픽셀로 변환하면서
매번 라이팅 계산을 하게 된다.
디퍼드 렌더링 방식을 사용한다면 버려질 픽셀에 대해라이팅 계산 비용을 절약할 수 있다.
(그렇다고 무조건 디퍼드 렌더링 방식이 좋은건 아니다.)
이번 글은 디퍼드 렌더링의 원리와
포워드 vs 디퍼드 방식에 대해 비교하는 내용을 담고 있다.
오버드로우 (Overdraw)
오버드로우는 같은 픽셀에 여러번 Pixel Shader가 실행되는 현상을 의미한다.
기본적으로 래스터라이저 실행 이후 바로 픽셀쉐이더가 실행되는 것이 아니라, 내부적으로 조기 깊이 테스트(Early-z test)가 이루어져 뒤에 있는 프래그먼트에 대해서 픽셀쉐이더를 실행하지 않는다. 하지만 픽셀쉐이더에서 discard나 clip이 사용된 경우, 조기 깊이 테스트가 실행되지 않는다. PS의 결과에 따라 픽셀이 존재 자체를 하지 않을 수도 있기 떄문에 버려질 픽셀의 깊이를 기록하지 않게 하기 위함이다.
이럴 경우, 생성된 모든 프래그먼트에 대해 픽셀쉐이더가 실행되게 된다.
Early-Z test가 진행되지 않는 경우는 다음과 같다.
| 상황 | Early-Z |
| 깊이 출력 (SV_Depth) | x |
| discard / clip | x |
| Alpha Test | x |
| PS에서 Depth 읽기 | x |
| 투명 객체 (Depth Write Off) | x |
| 단순 Opaque PS | o |
또, 조기 깊이 테스트가 진행 되더라도, 뒤쪽 기하가 먼저 렌더링 되면 깊이 테스트에 의해 제거되지 못해 동일 픽셀에 대해 픽셀 쉐이더가 여러번 실행된다. 픽셀 쉐이더에서는 모든 광원에 대한 라이팅 계산이 수행되는데, 결국 버려질 픽셀에 대해 이 무거운 작업을 실행한다면 이는 엄청난 비용의 낭비이지 않을까?…
Forward Rendering
위 Overdraw에서 말한 비용의 낭비는 특히 Forward 렌더링 방식일때의 문제점을 지적한 것이다.

Forward Rendering 방식은 지오메트리를 그리면서 라이팅까지 계산하여 렌더링하는 방식으로, 깊이 테스트가 실행되지 않거나 오버드로우 되는 경우에는 최종 픽셀에 기여하지 않을 픽셀들에 대해서도 라이팅 계산이 수행될 수 있다.
Geometry + Lighting Pass => sceneHDR
Deferred 렌더링은 이러한 오버드로우 상황에서 발생하는 불필요한 라이팅 계산을, 최종 가시 픽셀에 대해서만 수행하도록 분리함으로써 성능 비용을 줄이는 방식이다.
Deferred Rendering
Deferred Rendering 방식은 Forward 렌더링에서 발생하는 오버드로우 상황에서의 불필요한 라이팅 계산 비용을 줄이기 위해, 렌더링 과정을 ‘지오메트리 계산 단계’와 ‘라이팅 계산 단계’로 분리한 방식이다.
1. Geometry Pass => G-Buffer (RenderTarget x)
2. Lighting Pass => sceneHDR

Geometry Pass에서는 라이팅을 계산하지 않고, 라이팅 계산에 필요한 정보를 렌더 타겟에 기록한다. 다음으로 라이팅 패스에서는 Full Screen Quad를 그리며 지오메트리 패스에서 기록한 텍스처를 샘플링하여 라이팅을 계산한다. 즉 오버라이딩 되는 픽셀에서는 라이팅을 계산하지 않고, 최종 화면의 픽셀 수 만큼만 라이팅을 계산하게 된다.
1. Geometry Pass
지오메트리 패스는 라이팅 계산에 필요한 데이터를 여러 Render Target(G-Buffer)에 저장하는 패스이다. Geometry Pass에서 실행되는 Pixel Shader는 오버드로우가 발생하지만 비싼 라이팅 계산을 하지 않기 때문에 비용을 줄일 수 있다.
[ Geometry Pass ]
IA - Mesh(vertex), Material(Texture), Matrix...
VS - Clip Space 변환
RS - Fragment 생성
PS - G-buffer 값 기록 ⭐
G-buffer
지오메트리 패스의 PixelShader는 라이팅을 계산하지 않고, 라이팅 계산에 필요한 정보들을 여러 렌더타겟에 기록한다. 이 텍스처들을 G-buffer라고 한다. 그럼 라이팅 계산에 필요한 정보는 무엇이 있을까?
[ 라이팅 연산에 필요한 정보 ]
1. base_color
2. normal
3. metallic, roughness
4. Depth // Position 대신 사용! (메모리 대역폭을 줄이기 위함)
라이팅 연산에는 여러 벡터를 구해야한다. 이때 사용할 position값과, normal값. 그리고 BRDF연산에 사용되는 metallic, roughness값이 필수적으로 요구된다. 이 4가지가 라이팅 연산에 필요한 정보들이다. G-buffer는 별도의 특수한 버퍼를 의미하는 것이 아니라, 라이팅 연산에 사용되는 표면 정보들을 기록한 렌더 타겟들의 집합을 지칭하는 용어이다.
[ 라이팅 연산에는 필요 없지만, Geometry Pass에서 기록해야 하는 정보 ]
1. Emissive
2. AO
3. .. 기타 머티리얼 UV로 샘플링하는 텍스처 값들
위에서 언급한 4가지 데이터 이외에도 지오메트리 패스 단계에서 저장해야 하는 것들이 있다. 지오메트리 패스 이후의 Screen Space 기반의 패스에서는 원본 메쉬의 머티리얼 UV를 직접 알 수 없기 때문에, 머티리얼 UV로 샘플링 해야하는 텍스처들은 반드시 지오메트리패스에서 계산하여 RTV에 기록하고, 이후 패스에서 Screen Space UV로 샘플링할 수 있도록 해야한다.
- AO, Emissive 등
Emissive와 같은 텍스처는 지오메트리 패스에서 RTV에 기록되어 이후 패스에서 사용되지만, 라이팅 연산의 입력으로 사용되지는 않으므로 일반적으로 G-buffer에 저장된다고 부르지 않는다고 한다.

G-buffer에 Position을 넘기는 대신 Depth Buffer를 사용하는 이유?
라이팅 연산을 위해서는 vertex의 Position 정보가 필요하다. 하지만 이 값을 G-buffer에 기록하지는 않는다.
G-buffer는 지오메트리 패스에서 write하고 라이팅 패스에서 read한다. 이때 RTV가 하나씩 늘때마다 메모리, 대역폭 비용이 발생하며 Position값은 float3으로 많은 비용을 차지한다. 때문에 G-buffer에 position을 넣지 않고 지오메트리 패스에서 사용한 DSV의 텍스처를 바인딩하여 Depth값과 ScreenSpace의 UV로 WorldPosition을 복원하여 사용한다.
멀티 렌더 타겟(MRT)을 통한 RTV 기록
멀티 렌더 타겟(MRT)은 하나의 드로우콜에서 픽셀 셰이더가 여러 개의 Render Target(RTV)에 동시에 출력할 수 있도록 하는 기능이다. 일반적인 픽셀 셰이더는 하나의 렌더 타겟에만 값을 출력하지만, MRT를 사용하는 경우 픽셀 셰이더 출력에 SV_TargetN 시멘틱을 지정하여 각 렌더 타겟에 서로 다른 데이터를 기록할 수 있다.
// 멀티 렌더 타겟 설정
ID3D11RenderTargetView* rtvs[4] = { RTV0, RTV1, RTV2, RTV3 };
context->OMSetRenderTargets(4, rtvs, DSV);
// ------------------------------------
// PS Output (Deferred Rendering)
// ------------------------------------
struct PS_Output
{
//float4 WorldPos : SV_Target0; // Position 대신 Depth Buffer 사용
float4 Base_color : SV_Target0;
float4 Normal : SV_Target1;
float4 Material : SV_Target2;
float4 Emissive : SV_Target3;
};
// Geomatry Pass Pixel Sahder
PSOut PSMain(...)
{
PSOut output;
output.Base_color = float4(Base_color, alpha);
output.Normal = float4(Normal, 1.0f);
output.Material = float4(metallic, roughness, 0, 0);
output.Emissive = float4(Emissive, 1.0f);
return output;
}
2. Lighting Pass
라이팅 패스는 지오메트리 패스에서 생성된 G-buffer와 깊이값 텍스처, 기타 머티리얼 텍스처를 사용하여 최종 화면에 기여하는 픽셀에 대해서만 라이팅을 계산하는 패스이다.
라이팅 패스는 일반적으로 Full Screen Quad(또는 Triangle)를 그리는 Screen Space 기반의 패스로 구성되며, 이 과정에서는 더이상 메시의 Vertex 정보나 머티리얼 UV를 사용하지 않는다. 대신, 지오메트리 패스에서 기록된 G-buffer를 Screen Space UV로 샘플링하여 라이팅 연산을 수행한다.
[ Lighting Pass ]
IA - Full Screen Qaud
VS - Screen Space Vertex 생성
PS - G-buffer 값 샘플링 + 라이팅 계산 => sceneHDR ⭐
World Position 복원
라이팅 계산을 위해서는 픽셀의 World Position 정보가 필요하다. 하지만 포지션(float4)을 G-buffer에 기록하기에는 대역폭 비용이 많이 들기 때문에 Depth Buffer를 활용하기로 하였었다. 라이팅 패스에서는 Depth값과 Screen Space UV좌표를 이용해 World Position을 복원하여 사용한다.
float depth = DepthTexture.Sample(screenUV);
float3 viewPos = ReconstructViewPosition(screenUV, depth);
float3 worldPos = mul(InverseViewMatrix, float4(viewPos, 1.0)).xyz;
sceneHDR 출력
라이팅 패스의 결과는 HDR 색상 공간의 Render Target에 기록된다. 이 sceneHDR은 이후 Emissive합산, SSAO, Bloom, Tone Mapping등의 후처리 패스를 거쳐 최종 화면으로 출력된다.
Deferred Rendering 방식의 단점
Deferred 렌더링은 다수의 오버드로우 픽셀의 라이팅 계산 비용을 없애 다수의 광원을 효율적으로 처리할 수 있는 강력한 방식이지만, 라이팅과 지오메트리를 분리한 구조로 인해 몇가지 본질적인 한계를 가진다. 이로 인해 대부분의 상용 엔진은 여러 방식을 섞은 하이브리드 렌더링 방식을 사용하고 있다.
- 투명 오브젝트 처리의 어려움
디퍼드 렌더링의 지오메트리 패스는 하나의 픽셀에 하나의 표면 정보만 저장하는 구조이기 때문에 여러 레이어가 겹치는 투명 오브젝트(Alpha Blending)을 자연스럽게 처리하기 어렵다. 때문에 대부분의 상용 엔진에서는 디퍼드와 포워드 방식을 섞는 하이브리드 렌더링 구조를 사용한다.- Opaque 오브젝트 → Deferred
- Transparent 오브젝트 → forward
- 높은 메모리 사용량과 대역폭 비용
디퍼드 렌더링은 여러 개의 G-buffer(Render Target)를 사용하므로, 메모리 사용량과 대역폭 비용이 포워드 방식도가 높다. 이는 해상도가 높을수록 도욱 비용이 증가되며 모바일/ 저사양 PC에서는 부담이 크다. 이 문제 대문에 Position을 G-buffer에 기록하지 않는 것이다. 하지만 Normal, Material 등 필수 정보 만으로도 상당한 대역폭을 요구한다. - MSAA과의 나쁜 궁합
MSAA는 픽셀 내부를 여러 샘플러 나눠 가장자기 계산 현상을 줄이는 안티앨리어싱 기법으로, 품질은 좋지만 메모리와 성능 비용이 커서 디퍼드 렌더링과는 궁합이 좋지 않다. 때문에 상용 엔진들은 디퍼드 + MSAA 방식을 사용하지 않고 디퍼드 + TAA 방식을 사용한다. - 머티리얼 표현의 제약
디퍼드 렌더링에서는 라이팅 패스가 Screen Space에서 동작하므로 머티리얼 UV를 직업 사용할 수 없다. 이로 인해 레이어드 머티리얼, 디테일 텍스처, 복잡한 셰이딩 모델을 구현하려면 G-buffer 확장, Render Target 추가, 또는 Forward 패스 병행의 방식이 필요하다.
- 지오메트리 패스에서 UV 기반 텍스처 결과를 미리 계산해야함
- 라이팅 패스에서는 G-buffer에 없는 정보 사용 불가.
- 멀티 렌더 타겟 개수 및 하드웨어 제약
GPU는 사용할 수 있는 렌더 타겟의 개수에 제한이 있다. PC는 보통 8개이며, 모바일 GPU는 더 적다. - Forward 방식이 더 효율적인 환경일 수 잇음
디퍼드 렌더링은 라이팅 계산이 화면의 픽셀 수에 비례한다. 만약 화면에 아무 오브젝트가 없어도 라이팅 패스는 전체 화면에 대해 실행하게 된다. 즉, 광원이 매우 적고 오버드로우가 거의 없는 씬에서는 포워드 렌더링 방식이 더 효율적일 수 있다.
| 항목 | 단점 |
| 투명 처리 | 구조적으로 어려움 |
| 메모리/대역폭 | 사용량 높음 |
| MSAA | 적용 복잡, 비용 큼 |
| 머티리얼 | 표현 확장 어려움 |
| MRT | 하드웨어 제한 |
| 소규모 씬 | Forward보다 비효율 |
Forward vs Deferred
Forward Rendering
Geometry + Lighting => sceneHDR
- Geometry Pass에서 즉시 라이팅 계산 → 가려질 픽셀들에 대해서도 라이팅이 계산됨
- 비용 ≈ (그려진 픽셀 수) × (광원 수)
- 광원 수가 늘수록 급격히 느려지며, 오버드로우가 많을수록 최악임
Deferred Rendering
Geometry Pass => G-buffer
Lighting Pass => sceneHDR
- Geometry Pass에서 라이팅 계산을 하지 않고, G-buffer 기록
- Lighing Pass에서 최종 가시 픽셀에 대해서만 라이팅 계산 → 가려질 픽셀들은 라이팅을 계산하지 않음
- 비용 ≈ (화면 픽셀 수) × (광원 수)
- 오버드로우와 라이팅 비용이 분리되어, 광원이 많을수록 포워드 방식에 비해서 많은 비용이 절약됨
- 하지만 투명 오브젝트의 처리가 어렵고 MRT으로 인해 메모리와 대역폭의 부담이 있음
[ 결과 영상 ]
17_DeferredRendering 프로젝트와 PS_Gbuffer, PS_DeferredLighting 쉐이더를 참고하면 된다.
GitHub - wooj22/DirectX3D11_Study: DirectX3D11 공부용 레포지토리입니다.
DirectX3D11 공부용 레포지토리입니다. Contribute to wooj22/DirectX3D11_Study development by creating an account on GitHub.
github.com
'Programming > 컴퓨터그래픽스 (DX 11)' 카테고리의 다른 글
| [DirectX11] 포스트프로세싱(PostProcessing) Bloom 구현하기 (0) | 2025.12.23 |
|---|---|
| [DirectX11] IBL (Image-Based Lighting) (0) | 2025.12.11 |
| [DirectX11] PBR Pixel Shader 구현하기 (0) | 2025.12.11 |
| [PBR] 4. BRDF (0) | 2025.12.05 |
| [PBR] 3. 프레넬 효과(Fresnel)와 미세면 모델(Microfacet model) (0) | 2025.12.04 |