🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Deferred vs Forward shading

Started by
13 comments, last by D956 4 years, 4 months ago

Now I have been looking and reading into lots of examples, papers and could not come to conclusion which one is best to use. https://learnopengl.com/Advanced-Lighting/Deferred-Shading writes that 1847 lights would be never possible with forward rendering. Again there is this guy https://www.3dgep.com/volume-tiled-forward-shading/, who has a demo that runs thousands of lights with forward clustered + BHV. This guy again tells that both (Deferred & Forward) have advantages and disadvantages and mix them https://github.com/dtrebilco/lightindexed-deferredrender. So I'm kind of confused. I think for best performance I must go with clustering + BHV, but for the Deferred or Forward choice.. no idea. Maybe Both?

Advertisement

The problem of finding the lights affecting a pixel is the same for both, so any technique (BVH, binning lights to coarse tiles /cells, froxels etc.) is applicable for forward and deferred methods.
(Exception: Only with deferred you can draw the light volumes as polygons and accumulate the lighting, which was the first common practice to do deferred lighting, but seems much less common nowadays.)

But: with forward some GPU threads at the edges of triangles will do no work, while with deferred there are no such unused areas.
Conclusion would be that small triangles and costly lights gathering hurts forward more than deferred.

Downside of deferred is extra bandwidth to fill the GBuffers and restricted material options.

Both arguments make the best choice still depending on scene and materials, but not necessarily so much on the number of lights anymore.

trsh said:
Maybe Both?

For transparency support you may need a forward path in any case. So it makes sense to start with that, but keep a deferred path in mind.
In the end you might end up using deferred for most parts of the scene (e.g. static background with standard PBR material), and using forward for special materials (transparency, custom shaders, special effects…)

One more point to think about is support for raytracing. For this, you may need ability to gather affecting lights at any hitpoint, even offscreen.
From that perspective having a global acceleration structure for lights like BVH becomes more attractive, eventually.

One can note that there's a sexy third option called deferred texturing, that I don't believe has shipped yet in a project: https://therealmjp.github.io/posts/bindless-texturing-for-deferred-rendering-and-decals/

Basic idea is in the primary pass you read an indirection texture to the compressed material you want to use for rendering. A lot of the benefits of deferred, an absolute ton of triangles, and no restrictions on materials. Unfortunately you also (generally) need to output a bunch of extra odd parameters like UV gradients so it doesn't really end up saving bandwidth over deferred. Combined with the oddity of the whole process I'm not sure how popular it'll end up being, as the most obvious use case is with all virtualized textures as that just works right into deferred texturing pipeline, but only Idtech does that still.

Another option in between would be a thin gbuffer prepass with z, normal and roughness, then deferred lighting, then final full texturing and materials pass using the lit results in forward manner.

There are just too many options. Likely the best way to narrow it down is having some other technical restrictions and requirements.

JoeJ said:

Another option in between would be a thin gbuffer prepass with z, normal and roughness, then deferred lighting, then final full texturing and materials pass using the lit results in forward manner.

There are just too many options. Likely the best way to narrow it down is having some other technical restrictions and requirements.

And what would be performant for shadows?

If you're reading older articles about deferred rendering/shading, you have to keep in mind that deferred rendering came about before things like forward+ and clustered forward were introduced (mainly because those techniques rely on things like compute shaders and generalized buffer access in all shader stages, which were not at all a thing in the 2000's when deferred rendering started becoming popular). So when you see an older article like that make a comparison to forward rendering, they're really comparing with old-school forward rendering techniques. These generally fell into two categories:

  1. Single-pass rendering, with some fixed number of lights affecting each draw call (which might be dictated by hardware/API limits if using fixed-function lighting).
  2. Multi-pass rendering, where each draw is submitted multiple times with additive blending to sum the contribution from all light sources. In the worst case this means you do NumMeshes * NumLights draw calls.

Neither of these scaled up very well because they both tied your lighting granularity to your draw call granularity. If you wanted fewer draw calls with large meshes, you would either blow through your fixed lighting limit and/or need to draw that mesh many times to get the correct result. Deferred rendering decouples your geometry from lighting, which fixes that problem. Once more modern forward rendering techniques showed up they also solved that problem, just in a different way.

As for whether modern deferred vs. modern forward is better, I don't think there's a definitive answer on that one. Really nice-looking games continue to come out with both approaches, so I don't think you're going to be limited whichever route you choose. However JoeJ does bring up a great point in that you probably want a G-Buffer to do hybrid ray-tracing techniques, so if you're interested in that things then deferred may be a better choice.

@MJP Can you point me to some Modern forward and deferred lighting techniques / sources / papers?

Nice resources are ‘frame breakdowns’, e.g. https://aschrein.github.io/2019/08/11/metro_breakdown.html

http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/

http://www.adriancourreges.com/blog/2015/03/10/deus-ex-human-revolution-graphics-study/

… exist for many popular games.

trsh said:
And what would be performant for shadows?

The deepest rabbit hole of all?

I could link to many adventurous papers about efficient shadowed many lights, or approximate area light shadows, or compression of static shadows… if you have a certain interest.

But to me all this seems mostly unpractical / not worth it. (My biggest hope in RT is to get rid of shadow maps, and i don't think it's worth to invest in SM any longer. But not everybody agrees here.)

In practice, probably cascades for sun and some shadowed, some unshadowed local lights + shadow map cache makes sense mostly. Depends on the game, but i'm not really up to date what's the norm here actually.

The shading that I implemented is “Clustered Shading", based on this paper (http://www.humus.name/Articles/PracticalClusteredShading.pdf), from the guys that made Just Cause 3, etc…

The cool thing about clustered shading is that you can share your lighting-informating between forward and deferred rendering. The light lists you build are identical for both, making it extremely easy to have both forwrad and deferred passes. That is great for comparing the performance based on your scenario, as well as having forward-passes for ie. transparency if you decide to use deferred shading as the main render path.

@Juliean Do you have a public repo? And for shadows?

This topic is closed to new replies.

Advertisement