[그래픽스] Deferred Shading

윤태웅·2022년 8월 13일
0

그래픽스

목록 보기
8/13

개요

Deferred Shading에 대해 정리한다.
공부한 웹페이지: LearnOpenGL Deferred Shading

Forward Shading

Deferred Shading을 이해하기 위해서는
Deffered Shading의 반대개념인 Forward Shading에 대해 먼저 이해해야한다.
Forward Shading의 Forward는 StraightForward의 줄임말로 '정석 셰이딩'이라는 뜻을 가진다.
GPU는 화면을 렌더링하기위한 일련의 단계 '렌더링 파이프라인'을 거쳐서 화면을 렌더링한다.
다음은 DirectX11의 렌더링 파이프라인 그림이다.

이 렌더링 파이프라인을 1번만 거쳐서(Vertex Shader의 Space연산, Pixel Shader의 Lighting연산) GPU Back Buffer에 바로 렌더링하는 것을
Forward Shading 이라 한다.

Deffered Shading

용어

Deferred는 한국어로 '연기된' 이라는 뜻을 가진다.
Deferred Shading은 즉 '연기된 셰이딩'이다.

원리

Deferred Shading은 렌더링 파이프라인을 1번만 거치는 것이 아니라 2번 거친다(Two Pass Algorithm).

First Pass

1번째 파이프라인과정에서는 GBuffer(Geometry Buffer)에 Shading에 필요한 모든 자원을 저장한다.
저장하는 Item들의 예시는 다음과 같다.

  1. pixel의 World Space좌표
  2. pixel의 diffuse color
  3. pixel의 normal값
  4. pixel의 specullar값
  5. Shading계산에 쓰이는 Light들의 World Space좌표, Color
  6. Specullar계산을 위한 Player의 위치

이 외에도 프로그래머가 원하는 만큼 데이터를 GBuffer에 저장할 수 있다.
GBuffer에 값을 저장하기 위해서는 GPU가 MRT(Multiple Render Target)기능을 하드웨어적으로 지원해야하며 그래픽스 API또한 이 기능을 지원해야 한다(DirectX 9.0이상)

MRT 코드(DirectX 11)

struct PS_OUTPUT
{
    float4 Color: SV_Target0;
    float4 Normal: SV_Target1;
};
PS_OUTPUT PS(float4 p: SV_Position, float2 uv : TEXCOORD0)
{
      PS_OUTPUT output;
      output.Color = //Set first output
      output.Normal= //Set second output
      return output;
}

위 코드는 Single Pass에서 2개의 렌더링결과물(Color,Normal)을 저장하는 코드다.

Second Pass

2번째 파이프라인과정에서는 GBuffer에 저장된 자원들로 Shading연산을 한다.
2번째 파이프라인과정에서 Shading연산이 일어나기 때문에 Deferred라는 이름이 붙었다고 추론할 수 있다.
Second Pass는 First Pass와 다르게 단지 Pixel Shader에서 Lighting연산만 해주면 된다.
그 이유는 First Pass에서 필요한 Shading연산을 제외하고 필요한 연산을 처리해서 GBuffer에 저장하기 때문이다.

Second Pass Pixel Shader코드

Texture2D colorTexture : register(t0);
Texture2D normalTexture : register(t1);
SamplerState SampleTypePoint : register(s0);
cbuffer LightBuffer
{
    float3 lightDirection;
    float padding;
};
struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
};
float4 LightPixelShader(PixelInputType input) : SV_TARGET
{
    float4 colors;
    float4 normals;
    float3 lightDir;
    float lightIntensity;
    float4 outputColor;
    colors = colorTexture.Sample(SampleTypePoint, input.tex);//Color GBuffer값 추출
    normals = normalTexture.Sample(SampleTypePoint, input.tex);//Normal GBuffer값 추출
    lightDir = -lightDirection;
    lightIntensity = saturate(dot(normals.xyz, lightDir));
    outputColor = saturate(colors * lightIntensity);
    return outputColor;
}

Forward Shading대비 Deferred Shading의 장점,단점

장점:
1. Light연산이 엄청나게 줄어든다. 그 이유는 Forward Shading에서는 한 pixel위치에 존재하는 여러개의 pixel값들에 Lighting연산을 하고
Output Merger Stage에서 depth test를 통해 한가지 pixel값만 선정해 back buffer에 그리게 되는 반면에,
Deferred Shading에서는 일단 First Pass의 Output Merger Stage에서 depth test를 통해 한 pixel위치에서 'Light 계산하게될 pixel값'을 선정하고 Second Pass에서 해당 pixel값에다가만 Light계산을 취해서 back buffer에 그리게 되기 때문이다. 한 픽셀에 여러개의 Object가 겹쳐있을 수록 Deferred Shading에서의 성능이득이 커진다고 할 수 있다.

단점:
1. Color Blending을 통한 투명한 Object의 렌더링이 불가능하다. 그 이유는 Forward Shading에서는 OM stage에서 한 pixel위치에서 겹치는 위치값을 가지는 pixel값들의 alpha값 비교(Color Blending)을 통해 투명한 Object렌더링이 가능하지만. Deferred Shading에서는 First Pass에서 한 pixel위치에 한가지 값으로 fix하기 위해서 다른 pixel값들을 모두 버리게 된다. 그렇기 때문에 Second Pass에서 투명한 Object를 표현할 수 없다.
2. 하드웨어적으로 지원하는 AA효과가 떨어진다. MSAA같은 anti-aliasing은 하드웨어 Rasterization단계에서 일어나게 된다.
Deferred Shading에서는 Frist Pass에서만 Rasterization이 일어난다(Second Pass는 GBuffer결과물을 사용하기만 하기 때문). 그리고, 이때 AA을 적용할 수는 있다.
하지만, Deferred Shading은 Light계산이 이루어지기 전에 AA을 적용하기 때문에 최종 결과물이 Forward Shading과 다르게 나오는 이슈가 있다. 실제 게임의 예를 들자면, 스타크래프트2가 이러한 이슈 때문에 Deferred Shading을 적용하면서 AA을 적용하지 않는다.
3. 메모리를 더 많이 먹는다. Forward Shading을 쓰면, 1개의 Back Buffer에 값을 쓰기만 하는데. Deferred Shading은 Back Buffer와 같은 해상도를 가지는 Diffuse Texture, Normal Texture, Specullar Texture등등을 다 저장해야한다.

결론

현대 게임들에서 Deferred Shading은 Light계산 부담을 줄여서 더 퀄리티 좋고 부하가 큰 Light연산을 가능하게 해주는 기술이라고 할 수 있다.

0개의 댓글