[GPU] Forward Rendering vs. Deferred Rendering

예전에 FlexRendering에서 Deferred Rendering에 대해 작성한 적이 있다. FlexRendering에서 사용하는 Deferred Rendering은 Tile-based Rendering을 의미하는 것 같다. 하지만, 보통 Graphic 연산에서 Deferred Rendering은 다른 의미로 더 많이 사용되는 것 같다. 이 글에서 Forward Rendering과 Deferring Rendering에 대해서 작성하였다. 이 글은 출처 1의 내용을 기반으로 작성하였다.

Forward Rendering

Forward Rendering은 OpenGL등을 처음 배우게 되면 사용하는 Graphic Rendering 방법이다.

그림 1: Forward Rendering 연산 순서 (출처 1)

그림 1은 Forward Rendering 연산 순서이다. 보통 우리가 눈으로 확인하는 1개의 Frame을 그리기 위해서는 여러 개의 Drawcall을 사용한다. 각 Drawcall은 Vertex Shader, Geometry Shader (옵션), Fragment Shader 순서에 따라서 연산을 수행하여 최종 Frame을 생성한다. Forward Rendering은 하나의 Drawcall 계산을 할 때마다 Light (빛) 연산을 수행하여 Object의 색상을 결정한다. 매 Drawcall 연산이 완료될 때마다 Framebuffer에 결과값을 업데이트한다. 만약 Drawcall 중간중간 Framebuffer을 출력하면 Frame의 결과가 변한 것을 확인할 수 있다.

Deferred Rendering

Deferred Rendering은 Forward Rendering과 달리 Light 연산을 마지막에 수행한다.

그림 2: Deferred Rendering 연산 순서 (출처 1)

그림 2는 Deferred Rendering 연산 순서이다. Forward Rendering과 달리 Deferred Rendering은 Drawcall 결과값을 여러 개의 Render Target에 저장하게 된다. 여기서 말하는 Render Target은 아마도 Framebuffer을 의미하는 것 같다. 항상 모든 Framebuffer가 Display로 출력될 필요가 없다. Off-Screen Rendering 같은 경우 결과 값을 특정 메모리(Framebuffer)에 저장할 수 있다. 여기서 말하는 Render Target은 최종 이미지로 출력하는 Framebuffer가 아니라 중간 중간 값을 저장하는 또 다른 Framebuffer로 생각하면 된다.  Off-Screen 및 Framebuffer에 대한 글은 출처 2에 상세하게 설명되어 있다. 그림 2에서 처럼 여러 개의 Drawcall을 사용하여 Depth, Normals, Color 값을 계산하여 각기 다른 Render Target에 결과값을 저장하게 된다. 이렇게 저장된 Render Target (Framebuffer) 데이터 값을 사용하여 최종 색상을 결정하여 Final Render Target (Framebuffer)에 결과값을 저장한다.

그림 3: Deferred Rendering 결과물 (출처 1)

그림 3은 Deferred Rendering을 사용하여 하나의 이미지를 생성한 결과를 보여준다. 3개의 다른 Render Target을 합쳐서 하나의 Final Render Target을 생성하는 것을 확인할 수 있다.

Lighting Performance (Forward Rendering vs. Deferred Rendering)

왜 Deferred Rendering을 사용하냐는 질문에 답이 필요하다. 출처 1에 따르면 Deferred Rendering은 Light (빛) 연산 Overhead을 줄일 수 있다고 한다. Forward Rendering은 Light 연산을 하기 위해서 모든 Object에 대한 색상 연산을 수행해야 한다. 예를 들어 하나의 Object의 색상이 100개의 Fragment로 구성되어 있으며 10개의 가로등이 있는 곳에서 색상 연산을 수행하게 되면 총 10 Light * 100 Fragment 번의 연산이 필요하다. Forward Rendering의 연산량을 Big O Notation으로 표현하면 O(#_object_fragments * #_lights)가 된다. Object의 개수(또는 Object의 Fragment 수)가 급격히 증가하거나 Light 의 개수가 늘어나면 연산량이 많이 증가한다. (특정 Object가 다른 Object에 의해서 가려질지 아니면 제일 가까이 있어서 화면에 출력될지 모르기 때문에 모든 Object에 대한 색상 연산이 필요하다. #_object_fragments는 모든 Object의 Fragment 수를 의미하기 때문에 Screen Resolution보다 큰 경우가 일반적이다)

반면 Deferred Rendering은 각 Light 개수에 대해서 한 번의 색상 연산이 필요하다고 한다. 각 Light는 모든 Fragment 색상에 대한 연산을 수행하기 때문에 Big O Notation으로 표현하면 O(screen_resolution * #_lights)가 된다. 결과적으로 Light의 개수가 많거나 Object의 개수가 급격히 많아지는 경우 Deferred Rendering의 성능이 Forward Rendering보다 좋아진다.

Problem of Deferred Rendering

  • Mobile Device 같은 경우 Forward Rendering을 더 많이 사용한다. Deferred Rendering의 경우 여러 개의 Render Target을 저장하기 위해 많은 Memory 공간이 필요하다. 이와 더불어 Render Target 데이터를 Loading 하기 위해서 High Memory Bandwidth가 필요하다. 모바일의 경우 보통 Graphic Memory를 따로 가지고 있지 않고 System Memory를 같이 사용하고 있다. Mobile Device의 System 메모리는 보통 아주 제한적이다. 추가로 Mobile Device는 아주 제한된 Bandwidth로 인해서 Render Target의 데이터 값을 로딩하는 데 오랜 시간이 걸린다.
  • Deferred Rendering은 Transparent (투명한) Objects의 색상 연산을 수행할 수 없다. 이와 더불어 Edge Detection을 할 수 없기 때문에 Anti-Aliasing 연산을 수행할 수 없다.

출처

  1. https://gamedevelopment.tutsplus.com/articles/forward-rendering-vs-deferred-rendering–gamedev-12342
  2. https://learnopengl.com/

Leave a Comment