06. Deferred Rendering

DV·2024년 5월 12일

DirectX_3D

목록 보기
7/13

📒Deferred Rendering


: 지연 렌더링

  • Deferred: 연기된, 지연된

📌Foward Rendering

Straight Forward Shading.
렌더링 파이프라인을 1번만 거쳐서 GPU Back Buffer(GBuffer)에 바로 렌더링

  • Mesh 하나를 그릴 때마다 모든 계산을 시행
  • 라이팅 계산: Mesh의 수에 비례
    • 불필요한 연산 발생: 빛의 영향을 받지 않은 Mesh에 대해서도 연산

📌Deferred Rendering

: 렌더링 파이프라인을 크게 2번 거쳐 렌더링 (Two Pass Algorithm)

  • Foward Rendering의 단점을 보완한 렌더링 기법으로, 멀티 렌더 타겟 사용

  • Two Pass

    • First Pass
      : Gbuffer라고 칭하는 여러개의 버퍼에 오브젝트 정보 렌더링
      • Diffuse, Screen Space Normal, Specular, Smoothness, Screen Space Depth등의 정보를 기록해 사용함
    • Second Pass
      : 기록된 정보들을 토대로 셰이딩 연산 (라이팅 연산)
      • 모든 오브젝트들의 GBuffer을 렌더링한 후(Deffered) 라이팅 계산함
      • 즉, 한 번에 렌더링이 완료되지 않고
      • 기록된 오브젝트의 정보들을 사용해 렌더링 완료함

[장점]

  • 특정 정보만 따로 분리해 다룰 수 있으므로
  • 특정 영역에 관한 추가적인 연산, 효과 적용 가능
  • 광원을 많이 사용하는 경우 Forward보다 빠를 수 있음
    • 겹친 픽셀을 포함해 모든 픽셀마다 Light 연산을 하는 대신 Light마다 한 번의 연산만 진행

[단점]

  • 광원을 적게 사용하는 경우 Forward보다 느림
    • 더 많은 렌더링 횟수
    • 더 많은 메모리 사용 (Texture)
  • 반투명한 물체 처리가 어려움
    • PASS1에서 한 오브젝트의 값으로 모든 데이터를 결정하므로 겹쳐있는 오브젝트 처리가 어려움
  • Anti-Aliasing 성능 하락
    • MSAA같은 anti-aliasing은 하드웨어 Rasterization 단계에서 수행됨
    • Deferred Shading에서는 Frist Pass에서만 Rasterization 수행
    • Second Pass는 GBuffer결과물을 사용하기만 하므로 Rasterization 수행되지 않으므로 AA 적용 불가능
    • 이러한 이유로 Deferred Shading은 Light계산이 이루어지기 전에 AA을 적용하므로 최종 결과물이 예상한 값과 다르게 나올 수 있음

📒Deferred에서의 Lighting


: Deferred rendering을 적용하면 광원에 대한 연산만을 따로 다룰 수 있음

  • 라이트가 미치는 영향을 따로 기록
  • 빛 번짐, Bloom 등과 같은 기능을 사용하기 쉬워짐

📌Forward Lighting과의 연산흐름 차이

: (Deferred) 화면 결정 후 -> 라이팅 연산

  • Forward Shading:
    한 pixel위치에 존재하는 여러개의 pixel값들에 모두 Lighting 연산 후 depth값 비교해 하나의 pixel만 그림

  • Deferred Shading:
    First Pass를 통해 한 pixel 위치에서 'Light 계산하게될 pixel값'을 선정, Second Pass에서 해당 pixel값만 Light연산 후 그림

    • 즉, 한 픽셀에 여러개의 Object가 겹쳐있을수록 Deferred Shading의 성능이득 증가

📌Light MRT

: 전용 Texture에 빛의 영향 기록

  • 연산시점: Deferred 물체가 그려진 이후

    • Deferred: Lighting 연산 받음
    • Forward: (따로 처리 않는 이상) Lighting 처리 않음
  • 렌더링 요청 주체: Light

    • Forward: 모든 Mesh마다 Lighting 연산 적용
    • Deferred: 각 Light Object가 렌더링 요청
  • 빛의 영향 범위 판단: Position 정보를 기록해둔 Texture 사용

    • 예를 들어, Position Texture에 기록이 없다면 물체가 존재하지 않는 부분 ➡️ 빛 기록 안함
    • 예를 들어, (Point Light rendering 시) Position Texture에 기록이 있다면 Point Light의 범위 안으로 들어오는지 판단

📌Setting

[Texture]
: 2개의 CBuffer 사용

  • Diffuse: 세기
  • Specular: 반사광

[Setting]

  • DepthStencil Type: NO_TEST_NO_WRITE
  • Blend State Type: ONE_ONE
    • 기존1 : 신규1 비율로 믹스
  • Culling: CULL-FRONT
    • CULL-NONE: Light rendering이 두 번 호출됨
    • CULL-BACK: Light 범위 안으로 카메라가 들어가면 Light 연산하지 않음

📌Volume Mesh Check

: Directional Lihgt가 아닌 경우 빛이 영향을 주는 범위를 알기 위해 Volume Mesh check가 필요함

  • VolumeMesh: 광원이 영향을 주는 범위
    • VolumeMesh만큼 호출된 전체 픽셀에 빛을 적용시키면 안 됨
    • VolumeMesh만큼 호출된 곳에서도 빛이 영향을 주는 부분만 적용시켜야 함

📒Volume Mesh Check


[빛의 영향 범위를 확인하는 여러 방법들]

  • 방법1: Position Texture 사용
  • 방법2: Stencil 사용

📌방법1: Position Texture 사용

: Position Texture를 사용해 Pixel shader에서 한 번에 빛의 영향 범위 판단

  • VolumeMesh 안에 들어오는지 판단
    1. 호출된 픽셀 위치를 UV로 환산
    2. 추출한 UV로 Position Texture 샘플링
    3. 얻은 좌표정보로 VolumeMesh와의 거리 측정
      • 역으로 연산 (Screen➡️World➡️LocalSpace of VolumeMesh)
      • 좌표계 역연산: 변환행렬(View Inv * World Inv)을 바인딩해 사용
    4. 거리 측정 결과로 내외부 판단
  • 장단
    • 장: 빠름 (PS에서 바로 연산 가능)
    • 단: VolumeMesh의 기하학적인 특징이 있어야 함 - 내외부 판단 위해

📌방법2: Stencil 사용

: VolumeMesh의 BackFace, FrontFace, Stencil에 대해 총 3번 렌더링 결과로 빛의 영향 범위 판단

  • VolumeMesh 안에 들어오는지 판단

    1. Volume Mesh용 DepthStencil State 제작

      • BACKFACE용
      • FRONTFACE용
      • STENCIL용
    2. BACKFACE 렌더링
      : Light의 뒷부분 관점에서 VolumeMesh의 내부판단

      • DepthFunc: BackFaceCheck
      • DepthStencilType: Greater
        • 더 뒤에 있으면 통과
        • 먼저 그려진 물체들이(Deffered) VolumeMesh의 뒷면보다 앞에 존재한다면
        • 즉, light의 영향 범위 안쪽이라면
    3. FRONTFACE 렌더링
      : Light의 앞부분 관점에서 VolumeMesh의 내부판단

      • DepthFunc: FrontFaceCheck
      • DepthStencilType: Less
        • 더 뒤에 있으면 통과
      • FrontFace.StencilFailOp: DECR
        • 두 번 증가하는 현상 방지
    4. STENCILCHECK
      : 예상하는 Stencil 값인지 확인

      • DepthFunc: NEVER
      • DepthStencilType: Equal
        • 같으면 통과
      • OMSetDepthStencilState: 2번째(idx 1) pram으로 예상하는 Stencil 값 전달
      • StencilEnable = true
        • RenderTarget없이 DepthStencil Texture만 세팅
        • 즉, RenderTarget에 색을 내보내는 Pixel Shader 단계 수행 X
      • StencilPassOp: INCR
  • 장단

    • 장: VolumeMesh의 기하학적인 특징이 없어도 가능 - 내외부 판단 위해
    • 단: 느림 (렌더링이 3번 발생)

[Stencil 단계 3~4를 한 단계로 합치기]
: 2~3 단계는 한 단계로 수행할 수 있음

  • DepthStencilType: CULL_NONE
  • 각 구조체마다 세팅

📒Stencil Buffer


: 렌더링해야 할 곳에 특정 값을 설정해, back buffer의 일정 부분만 rendering되도록 함

  • off-screen buffer
  • 해상도: Backbuffer, depth buffer와 동일함
  • ex) 거울, 그림자, 아웃라인

References
[1] Deffered Rendering: https://learnopengl.com/Advanced-Lighting/Deferred-Shading
[2] Stencil Buffer: https://dis.dankook.ac.kr/lectures/game09/wp-content/uploads/sites/16/1/1171436988.pdf

0개의 댓글