Forward & Deferred rendering
https://m.blog.naver.com/lighting12/221237926447
https://gamedevelopment.tutsplus.com/articles/forward-rendering-vs-deferred-rendering--gamedev-12342
Forward Rendering
Forward rendering is the standard, out-of-the-box rendering technique that most engines use. You supply the graphics card the geometry, it projects it and breaks it down into vertices, and then those are transformed and split into fragments, or pixels, that get the final rendering treatment before they are passed onto the screen.

It is fairly linear, and each geometry is passed down the pipe one at a time to produce the final image.
Deferred Rendering
In deferred rendering, as the name implies, the rendering is deferred a little bit until all of the geometries have passed down the pipe; the final image is then produced by applying shading at the end.
Now, why would we do that?

Lighting Performance
Lighting is the main reason for going one route versus the other. In a standard forward rendering pipeline, the lighting calculations have to be performed on every vertex and on every fragment in the visible scene, for every light in the scene.
If you have a scene with 100 geometries, and each geometry has 1,000 vertices, then you might have around 100,000 polygons (a very rough estimate). Video cards can handle this pretty easily. But when those polygons get sent to the fragment shader, that's where the expensive lighting calculations happen and the real slowdown can occur.
The expensive lighting calculations have to execute for each visible fragment of every polygon on the screen, regardless if it overlaps or is hidden by another polygon's fragments. If your screen has a resolution of 1024x768 (which is, by all means, not very high-res) you have nearly 800,000 pixels that need to be rendered. You could easily reach a million fragment operations every frame. Also, many of the fragments will never make it to the screen because they were removed with depth testing, and thus the lighting calculation was wasted on them.
If you have a million of those fragments and suddenly you have to render that scene again for each light, you have jumped to [num lights] x 1,000,000
fragment operations per frame! Imagine if you had a town full of street lights where each one is a point-light source...
The formula for estimating this forward rendering complexity can be written, in big O notation, as O(num_geometry_fragments * num_lights)
. You can see here that the complexity is directly related to the number of geometries and number of lights.
Now, some engines optimize this, by cutting out lights that are far away, combining lights, or using light maps (very popular, but static). But if you want dynamic lights and a lot of them, we need a better solution.
Deferred Rendering to the Rescue
Deferred Rendering is a very interesting approach that reduces the object count, and in particular the total fragment count, and performs the lighting calculations on the pixels on the screen, thereby using the resolution size instead of the total fragment count.
The complexity of deferred rendering, in big O notation, is: O(screen_resolution * num_lights)
.
You can see that it now doesn't matter how many objects you have on the screen that determines how many lights you use, so you can happily increase your lighting count. (This doesn't mean you can have unlimited objects—they still have to be drawn to the buffers to produce the final rendering result.)
Let's see how it works.
The Guts of Deferred Rendering
Every geometry is rendered, but without light shading, to several screen space buffers using multiple render targets. In particular, the depth, the normals, and the color are all written to separate buffers (images). These buffers are then combined to provide enough information for each light to light the pixels.


By knowing how far away a pixel is, and its normal vector, we can combine the color of that pixel with the light to produce our final render.
Which to Pick?
The short answer is, if you are using many dynamic lights then you should use deferred rendering. However, there are some significant drawbacks:
- This process requires a video card with multiple render targets. Old video cards don't have this, so it won't work on them. There is no workaround for this.
- It requires high bandwidth. You're sending big buffers around and old video cards, again, might not be able to handle this. There is no workaround for this, either.
- You can't use transparent objects. (Unless you combine deferred rendering with Forward Rendering for just those transparent objects; then you can work around this issue.)
- There's no anti-aliasing. Well, some engines would have you believe that, but there are solutions to this problem: edge detection, FXAA.
- Only one type of material is allowed, unless you use a modification of deferred rendering called Deferred Lighting.
- Shadows are still dependent on the number of lights, and deferred rendering does not solve anything here.
If you don't have many lights or want to be able to run on older hardware, then you should stick with forward rendering and replace your many lights with static light maps. The results can still look amazing.
Unity WebGL only supports Deferred Rendering Path if WebGL2.0 is available. On WebGL1.0, Unity WebGL runtime will fallback to Forward Rendering.
:: Deferred Rendering ::
파이프 라인의 구조를 보면, Fragment Shader나 Pixel Shader에서 수행할 때, 일반 색상 정보... 텍스처 정보만 넘겨서 디스플레이에 올린 픽셀의 set을 만들어두고, 최종적으로 별도의 Fragment Shader를 통해서 일괄적으로 광원 처리 등의 고급연산을 수행하는 방식을 말한다.
해당 방식의 경우, 연산을 수행하기 전에 화면에 쓸 픽셀 정보에 접근할 수 있으므로 다양한 효과를 적용하기 좋고, 또한 일괄적으로 고급연산을 처리하니까 포워드 랜더링 보다는 다수의 오브젝트에 대해 실시간 광원 연산의 퍼포먼스 면에서 더 좋은 품질의 랜더링을 얻을 수 있다는 장점을 가진다.
다만, VRAM 크기 만큼의 버퍼가 필요하므로, 해상도가 높아질수록 메모리 요구량이 높아진다는 단점을 가진다.
:: 비교 ::
포워드 랜더링에서는 모든 파이프라인 단위로 광원 연산이 적용된다. 만약 Geometry( * 그래픽스 분야에서는 랜더링할 오브젝트를 나타내는 단위 ) 가 100개 존재하고, 각 Geometry가 1000개의 정점을 가진다면, 수행해야 할 연산은 100 * 1000 = 100,000 번이 된다.
이런 큰 단위 연산은, 정점 셰이더의 경우에는 100,000 정도야 가볍게 2D 스크린으로 매핑해서 다음 프로그램에 넘길 수 잇지만, Fragment Shader 등의 고급 연산을 수행해야 하는 경우에는 병목현상을 일으킬 수 있는 위험성을 가지게 되는 것이다.
(정점 셰이더는 일 끝내고 놀아서, 퍼포먼스가 떨어지고 Fragment 셰이더는 일이 밀려서 퍼포먼스가 떨어지고)
근본적인 원인은 다음과 같은 작업 절차 때문이라고 한다.
1. 광원이 어디서 비추고 있을지 모르므로, 일단은 오브젝트의 Depth 등을 고려하지 않고 view port 안에 있는 오브젝트라면 광원 연산의 대상으로 삼음.
2. 이후에 z-buffer에 의해 은면제거가 되는 과정에서 1에서 힘들게 연산해놓은 데이터 중 일부가 쓰레기 값이 되어버림.
(Fragments are potential pixels that will end up on the screen if they do not get culled by the depth test.)
3. 광원이 1개인 경우에는 해당 환경.. 100,000개의 정점에 각각 연산이 수행된다.
4. 광원이 n개라면 그 n배가 발생하며, 최종적으로는 광원의 갯수 n , 정점 수 m에 대해 O(mn)의 시간복잡도를 가지게 된다.
위와 같은 특징 때문에, 광원이 많이 존재하는 환경.. 그리고 오브젝트가 많이 있는 환경에서 퍼포먼스가 떨어질 수 밖에 없고, 이를 해결하기 위해서 정적 광원에 한하여 다음과 같은 솔루션들이 등장했다.
1. 정적 광원 여러 개를 미리 묶어서 1개처럼 다룬다.
2. 멀리 있는 정적 광원은 무시한다.(빛의 감쇠)
3. 라이트 맵을 사용한다.
다만, 동적인 광원에는 대응하지 못했고 디퍼드 랜더링의 탄생배경이 되었다.
디퍼드 랜더링의 경우에는 오브젝트의 숫자가 몇 개이던 디스플레이의 해상도에 선형시간을 달리기 때문에, 광원의 갯수 n , 화면의 해상도 r 에 대해 O(nr)의 시간복잡도를 가진다.
이 경우 r은 상수이니까, 오브젝트가 많은 환경에서는 포워드 랜더링보다 퍼포먼스가 좋게 나오는 것이다.
* 다만, 이미 픽셀Set가 정해졌다는 것은 깊이 버퍼 등이 전혀 고려되지 않는다는 말이므로 은면이 필요한 광원 연산.. 이를 테면, 불투명이나 굴절 같은 재질이 적용되는 오브젝트를 그릴 수 없다.
이러한 경우에는 포워드 랜더링과 혼용하는 방식으로 극복하고 있으며, 같은 맥락으로 안티 알리아싱도 불가능하며, 최근의 랜더러들을 그러한 결점을 보완한 것이 많다고 한다.
:: 기타 ::
* 별로 중요하지 않은 내용.
다음과 같은 경우에 디퍼드 랜더링을 사용한다.
1. 다수의, 실시간 동적 광원을 랜더링할 때
2. 그래픽 카드에 다수의 버퍼가 존재하여 광원을 적용하기 전에 화면 정보를 저장할 수 있을 때
댓글
댓글 쓰기