• Advertisement
Sign in to follow this  

Deferred Shading vs Pre-pass lighting

This topic is 2084 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I just changed my implementation of deferred shading to pre-pass lighting (the algo discussed here: http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html). I still had the code for the old rendering and did some test to compare the two methods.

I first thought that pre-pass would be much faster when drawing many lights (I guess I was a bit naive), but when testing deferred shading was almost always faster on my card. Testing on some other cards, the difference changed a bit and on a laptop card with shared memory (that has no specific gpu ram), pre-pass lighting seems faster overall.

I have collected all my data here:
http://frictionalgames.blogspot.com/2010/10/pre-pass-lighting-redux.html

The biggest question for me right now is if I should skip the early-z pass (as Crytech seems to be doing for Crysis 2), but it just seem problematic. If I skip early z, then I choose to:
1) sort by depth, resulting in a lot of render state changes.
2) sort by render state, resulting in a lot of unneeded overdraw.

Would be very interesting if anybody else has tested these two rendering algos against each other. And would also be interested in hearing how all else do with the early-z pass.

Share this post


Link to post
Share on other sites
Advertisement
Interesting topic :) I've done testing with both, using similar G-buffer setups as you have (with depth being either an R32F rendertarget, or INTZ hardware depth stencil buffer) and found them to perform very close to each other, for the most part, as long as the batch & vertex count is moderately low.

About Z-prepass I've never bothered, so can't answer. Rather, I just sort by state first, and then draw each state "bucket" front to back to fill the G-buffer.

I can give data from one test scene, which is about 200K triangles and 110 objects in the initial view, and 600K triangles and 500 objects for the whole scene. It's lit by 20 unshadowed spotlights (without much overdraw, though), and on a Geforce 8800M GTS, the results are:
Prepass: 8.3 ms (initial) 9.9 ms (whole scene)
Deferred: 8.6 ms (initial) 6.4 ms (whole scene)

Light prepass is where I started with deferred lighting techniques, and I would want to like it :) as it's cool to have a slim G-buffer. However according to my results it seems that when it wins over deferred, the wins are small, but when vertex counts grow, then deferred can have a large advantage. Furthermore, with deferred shading it's easy to match the look of forward rendering, as the lighting pass accumulates the final framebuffer colors additively, whereas prepass has problems with limited range of the light accumulation buffer and constructing the specular highlights.

Share this post


Link to post
Share on other sites
Seems like you results are the same as mine!

I also want to like pre-pass ligthing :) But as you say, it is very rarely that it is better than deferred and when it is, the difference is slim.

Regarding the difference is light accumulation, I do not think this matters + pre-pass will give nicer results when many dark lights overlap. So I do not think there will be much difference with this. The screens I have tried so far with both algos look basically the same.

The big reason for me with sticking to pre-pass lighting, is that there are so much more material variety possible. Doing a materials that have rim-lighting and stuff like that all require extra passes on deferred shading, and any kind of skin rendering is not really possible. But it also feels wrong to switch to what seems like worse technique performance and precision-wise.

AgentC, what did you end up using for the application?

Share this post


Link to post
Share on other sites
At this stage there's no real application yet, it's just a result from my opensource engine Urho3D, which right now implements deferred & forward multipass shading.

However, I'm thinking that I might want to reimplement prepass mode to the public version just so that there's more choice, in case it's better for some (yet undecided) purpose!

Share this post


Link to post
Share on other sites
Once I had deferred rendering in my engine, too. And as you mentioned in you blog, deferred rendering was slower on older hardware and/or laptops that the LPP is.
Well, I am on a old laptop here! It just has a GeForce 8400GS Go which is pretty lame at EVERYTHING.
With deferred rendering I only had to place like 3 big lights into my scene and my FPS was at 8-10.

That's pretty much solved with the LPP. I get good framerates with it.
I would say, even if it is not faster than deferred rendering (Which it is not in my case), the freedom you get with your shaders is reason enough to use it.

Our artist always said: "I need emissive here, I need specular power there, and this thing would be cool and that even cooler, etc etc" and I ended up in having 5 MRTs for stuff.
That's pretty much solved with the LPP.

Share this post


Link to post
Share on other sites
Well it definitely depends on a lot of factors. Deferred rendering is typically very heavy on bandwidth, due to the fat G-Buffer (MSAA makes this even worse). Light prepass on the other hand requires rendering most of your geo twice, and this can hurt a lot depending on your scene. Multiple render targets can also be unusually painful on certain platforms, which makes light prepass more attractive. Then you have PS3 where SPU's can be used to handle the lighting pass of a light prepass renderer.

The important point here is that like with anything performance-related, it always varies depending on the usage and the target hardware.

Share this post


Link to post
Share on other sites
I just went back from a lighting prepass system to an ubershader that only supports a finite number of lights.

Just ask yourself if you really need 2000 lights in a scene and when you give the honest answer, long single pass shaders suddenly look more attractive again.

For a start, you can do lighting effects on translucent materials (which was my main reason for switching back tbh).

You just can't get faster than one pass. And shader execution speed is more likely to keep on going up in the future, at a faster rate than bandwidth widening, because faster shading is just cores++ which is more or less an unlimited upgrade path.

Your only real limit now is interpolators and the added a shitload more with DX10, along with an infinite shader length (sort of).

But the above isn't the current trendy thing, so I guess now I get flamed to death for having crap tech... :)

Share this post


Link to post
Share on other sites
Nope, you're not alone. At least on current generation consoles, forward rendering & ubershaders are still very common. Many people have switched to LPP, especially some of the major PS3 studios, but I think the majority of 360 & PS3 titles are still using more traditional techniques. (My last shipped title had an ubershader with ~12 lights.)

Yes, the artists want more lights in the scene, and we're always looking at ways to achieve that. But they also love transparency, so it's a balancing act. I will say that the many recent advances in post-process AA have pretty much eliminated that as a point in favor of forward rendering. But I don't think that the translucency solutions (Inferred lighting, or the similar technique from Little Big Planet) have caught on that fast.

Share this post


Link to post
Share on other sites
Some other food for thought:

Complex forward rendering needs a Z-pre-pass to reduce shading costs. This is less important with deferred, and not required in LPP.

Most deferred/LPP renderers also support forward lighting (e.g. for translucent objects). If a particular object needs a special shader, it can use forward lighting while the rest of the scene uses deferred/LPP.

LPP can be implemented without MRT, meaning it works on older cards (e.g. DX8).
LPP works with MSAA on DX9 (deferred needs DX10).

Inferred rendering (basically an extension of LPP) supports lighting of translucent surfaces (without requiring a forward-rendering path!), and also allows you to scale the cost of the lighting passes with mixed resolution rendering.

[Edit]
Quote:
Original post by Hardguy
I have collected all my data here:
http://frictionalgames.blogspot.com/2010/10/pre-pass-lighting-redux.html
This isn't the best competitive benchmark of both algorithms - it would be nice to see CPU ms and GPU ms reported seperately.

In the "4000 x boxes, 1 x point light" test, is that 4000 draw-calls, each with 12 triangles? If so, it would be a much fairer test if the boxes were drawn using 40 draw-calls, each with 1200 triangles...

[Edited by - Hodgman on October 22, 2010 11:20:13 PM]

Share this post


Link to post
Share on other sites
Sorry for digging this topic out but I recently I've been thinking about LPP (a.k.a. deferred lighting) vs deferred shading. I read some materials in the net and eventually came to a conclusion that deferred shading is indeed "better" in many ways. While I was still hesitating which technique would be nicer to use, I considered how adding parallax mapping would affect both pipelines. Now, tell me if I am wrong but... isn't it necessary in deferred lighting to do parallax mapping (or relief, or any other alike) twice, first in the g-buffer pass (need to offset normals), and then in the shading pass (to offset diffuse, specular and other textures). If that is so then it seems like a huge waste of GPU time, given that parallax/relief mapping techniques can be very expensive.

On the other hand, how would you handle cube-mapped materials and emissive materials in deferred shading? When it comes to cube maps I think I would simply blend it with diffuse map in the g-buffer pass, but what about emissive? Using another render target to store emissive doesn't sound nice. The only thing I can think of is to just re-render all emissive objects again (with emissive lighting only) after the deferred shading pass.

Share this post


Link to post
Share on other sites

On the other hand, how would you handle cube-mapped materials and emissive materials in deferred shading? When it comes to cube maps I think I would simply blend it with diffuse map in the g-buffer pass, but what about emissive? Using another render target to store emissive doesn't sound nice. The only thing I can think of is to just re-render all emissive objects again (with emissive lighting only) after the deferred shading pass.


Instead of a separate emissive RT, I would recommend binding the final output surface as one RT during the G-buffer pass, so that you can lay down cubemaps, emissive and ambient right there, instead of calculating their final image contribution later. Your mileage may vary, but personally I've found this more performant even on fairly old (2007) hardware than rendering a separate ambient quad to initialize the final image.

Share this post


Link to post
Share on other sites

[quote name='maxest' timestamp='1335901255' post='4936496']
On the other hand, how would you handle cube-mapped materials and emissive materials in deferred shading? When it comes to cube maps I think I would simply blend it with diffuse map in the g-buffer pass, but what about emissive? Using another render target to store emissive doesn't sound nice. The only thing I can think of is to just re-render all emissive objects again (with emissive lighting only) after the deferred shading pass.


Instead of a separate emissive RT, I would recommend binding the final output surface as one RT during the G-buffer pass, so that you can lay down cubemaps, emissive and ambient right there, instead of calculating their final image contribution later. Your mileage may vary, but personally I've found this more performant even on fairly old (2007) hardware than rendering a separate ambient quad to initialize the final image.
[/quote]

Yes this is how I do it as well.

Share this post


Link to post
Share on other sites
Yup, that's what I would do for cube maps, but emissive doesn't seem to fit there for me. To me emissive is yet another "light source" which should be independent of other lights in the scene. Though I can imagine that that would be hard to notice that material's emissive is "built-in" to the "surface color" RT g-buffer output and that dynamic scene lights amplify emissive contribution :).

Share this post


Link to post
Share on other sites
It will be independent. If you have an MRT layout like this:

Surface color
Normal
Depth
Final image

you'd write the diffuse texture color (but not the emissive) to the surface color map, which is the only thing (in addition to depth+normals, of course) the dynamic lights will "see" when calculating their contribution. If the material is *only* emissive, ie. it does not receive dynamic lights at all, you could write black to the surface color. And btw. that's also how you would do fog directly in the G-buffer pass: you'd lay the fog color to the final image, and at the same time fade the surface color smoothly to black according to fog settings, to prevent erroneously combining fog and dynamic lighting. Edited by AgentC

Share this post


Link to post
Share on other sites
Of course... I forgot that we can bind the final image RT in the g-buffer as well :).
When you wrote this "binding the final output surface" I was thinking about the combined albedo surface color, not the final final buffer :).

Just to "bump"... can anyone give feedback on my first question regarding parallax mapping effects? Do they have to be applied twice?

Share this post


Link to post
Share on other sites

Just to "bump"... can anyone give feedback on my first question regarding parallax mapping effects? Do they have to be applied twice?


Yes you'd have to do it twice, unless you wrote out the offset texture coordinate to a texture and read it in during your second pass.

Share this post


Link to post
Share on other sites

Yes you'd have to do it twice, unless you wrote out the offset texture coordinate to a texture and read it in during your second pass.

Huh, that is what I thought. Deferred lighting seems less and less attractive than deferred shading as I find out new things.
Thank you guys very much for your answers.

Share this post


Link to post
Share on other sites

[quote name='MJP' timestamp='1336069722' post='4937169']
Yes you'd have to do it twice, unless you wrote out the offset texture coordinate to a texture and read it in during your second pass.

Huh, that is what I thought. Deferred lighting seems less and less attractive than deferred shading as I find out new things.
Thank you guys very much for your answers.
[/quote]

I think Light Pre-Pass was useful back when hardware with no MRT support was still prevalent and back when the bandwidth cost of large gbuffers was too much to handle. This might still be true for last generation consoles, but most computers can handle deferred shading without sweating these days, so I think Light Pre-Pass is probably not as useful as it once was.

Share this post


Link to post
Share on other sites

I think Light Pre-Pass was useful back when hardware with no MRT support was still prevalent and back when the bandwidth cost of large gbuffers was too much to handle. This might still be true for last generation consoles, but most computers can handle deferred shading without sweating these days, so I think Light Pre-Pass is probably not as useful as it once was.

I found somewhere a nice blog post about deferred shading vs deferred lighting in which the author actually claimed that the bandwidth cost in case of deferred shading is/(can be) equal or even less than in deferred lighting. Think for instance about intermediate lighting buffers. Although in Unity 3D they fit all lighting in one RGBA8 buffer, but Crysis 2 for instance uses 2x RGBA16F, one for diffuse and the other for specular lighting. So here we would have:

deferred shading:
3x RGBA8 (depth, albedo, normal)
1x RGBA16F for lighting accumulation

deferred lighting:
2x RGBA8 (depth, normal); possible to use 1x RGBA8 on some hardware assuming we can sample the depth buffer
2x RGBA16F (diffuse acc., specular acc.)
1x RGBA16F for lighting accumulation

Of course, in deferred shading it is a bit trickier to achieve richer materials variety, but honestly if I had to use some more specific materials, rather than bloating the g-buffer I would rather render them in forward pass (you need to have this anyway, for transparent surfaces for instance). And deferred lighting also is not that much more flexible than deferred shading.

Share this post


Link to post
Share on other sites
Why on earth you would need all these for deferred lighting:
2x RGBA16F (diffuse acc., specular acc.)
1x RGBA16F for lighting accumulation

and then some how deferred shading does not have same needs? Apples vs oranges?

I have done prelight pass renderer that work using one rgba8 as G-buffer and one rgba8 as light accum buffer. This run on android devices even. http://www.ludumdare.com/compo/ludum-dare-23/?action=preview&uid=8170


On deferred renderer to save bandwith you don't want to read from all the g-buffers(depths and normals +spec power is enogh) when you do lights accum pass.
But at last when you do fullscreen directional light + ambient you resolve everything using all G-buffers and light accum buffer/s.

Share this post


Link to post
Share on other sites

Why on earth you would need all these for deferred lighting:
2x RGBA16F (diffuse acc., specular acc.)
1x RGBA16F for lighting accumulation


If you want separate RGB for diffuse and specular (which you really do smile.png) , then you need to output your lighting pass into two separate render targets. Then you need a third buffer to use as an output for your second geometry pass, where you combine the diffuse and specular and apply albedos. With deferred rendering you only need 1 render target since you don't have the intermediate diffuse/specular accumulation step, and you just accumulate final illumination directly.

Share this post


Link to post
Share on other sites

Of course, in deferred shading it is a bit trickier to achieve richer materials variety


That's not really the case though. It is in fact easier to get material variety in deferred shading and harder in light pre-pass. How would you implement Cook-Torrance, Blinn-Phong, Ward, Oren-Nayar, Lambert all side by side in a light pre-pass? Not easily. It's one of those false claims like the one about MSAA "just working" with light pre-pass. Edited by Chris_F

Share this post


Link to post
Share on other sites
But some deferred renderers use those 2x RGBA16F (diffuse acc., specular acc.) too and I was referring to those. This way albedo do not need to be read when doing lighting accumulation. Maybe there are just too many different implementations allready so that comparison will be night impossible with fair means.

Prepass lights need more bandwith for geometry and light accumulation but need less bandwith per light. For me pre light pass is only option becouse gles2.0 does not support mrt and rendering everything three/four times is not that cool.

But at the end I think you are right about prelight pass bandwith It's not that much better that many ppl claim.

Share this post


Link to post
Share on other sites

Prepass lights need more bandwith for geometry and light accumulation but need less bandwith per light.

Well, you read less, but you also need to write more if you want to have full-colored specular lighting. In that case in deferred lighting you're writing to two RGBA16F, while in deferred shading you just use one (the final lighting accumulation buffer) RGBA16F.


For me pre light pass is only option becouse gles2.0 does not support mrt and rendering everything three/four times is not that cool.

If you're targetting android then I guess that deferred lighting with tight diffuse packing (perhaps LUV color space?) and monochrome specular stored in one RGBA8 is a very good solution. When I typed all those buffers configurations I had big games in my mind; particularly the deferred lighting buffers configuration which I took from Crysis 2 presentation.

Share this post


Link to post
Share on other sites
So I stumbled upon this and I'm trying to understand Prepass Lighting. Right now I have an early version of a Deferred Shader.

I saw some posts with wording that made it seem like Prepass Lighting is Deferred Lighting. I remember at one point I decided to use Deferred Shading over Deferred Ligthing for some reason...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement