Reputation: 545
I'm writing a deferred renderer and a few things come to mind. The render will be done in at least two passes: first I render positions, normals and diffuse+specular color into three different textures. Then I combine these in the final pass and do the lighting for each light and add postprocessing effects to produce the final image. This part I got working though.
Here comes the problem: how to do with shadows? The naive approach would be to render a depth map for each active light in a single pass each. So that means as many extra passes as there are lights. This seems to defeat the whole purpose of deferred shading to do all lighting in a single pass.
A better way would have been if I could render the depth maps together in a single pass. But is this even somehow possible? ..because to render the scene from a different perspective would require to do the same kind of culling as is done for the main camera. So rendering from the perspective of each light require just as much scenegraph traversal and vertex buffer bindings as rendering the main camera view. So it's quite expensive then.
But what is the proper way to do this? What is the standard way to render shadow maps in terms of multiple passes? Is it really necessary to do a separate render for every light that will contribute a shadow to the scene or is there a better and faster way to compute the sum of all shadows. Is there a way to do multiple perspective rendering to multiple framebuffers in a single shader pass?
Also I suppose it would be a good idea to bind two buffers for each lighting pass: one that contains sum of results from previous passes and one that contains pixel distances. Then the product of all lighting passes will be a shadow intensity map that can be passed to the final render pass.
The final render pass then only renders a single quad on the whole screen on which it does the postprocessing and shading. So it's at least 2+1 passes. And with 8 lights it would mean rendering the scene 10 times for every frame?
Upvotes: 2
Views: 851
Reputation: 17266
Firstly, I don't like the idea of "shadow intensity" or combining shadows. A shadow is lack of light. Only add light where there is light and you don't need to worry about shadows. In practice, this just means apply shadowing as you apply each light.
Rendering to multiple shadow maps at the same time can be done with the multiple viewport extension and geometry shaders. You could also use instancing and render to texture arrays. "OpenGL Insights, chapter 19 - Massive Number of Shadow-Casting Lights with Layered Rendering" comes to mind (as I'm an author of another chapter in the same book)
Something most games do is implement some kind of visibility data structure so that you don't have to draw stuff you know won't be visible. This can be very valuable when rendering shadow maps. You might want to look at trying to group geometry that's visible to the same lights and render shadow maps for those lights in one pass. That way you minimize the amount of geometry rendered that doesn't affect shadows. If you mostly have lights with shadows in completely separate areas of a scene then the visibility data structure will be more important than the vertex processing time saved with multiple viewport rendering.
Rendering lights with deferred rendering generally isn't done with a single full screen quad. One of the main advantages of deferred shading is the ability to localise lighting contributions. A the very basic level, draw some geometry over the pixels that could be lit by your light such as a small quad or circle. Then only fragment shaders for those pixels do any expensive lighting calculations. Next, you can start culling even more by bounding the fragments by depth. It's pretty common to use a mesh that represents the shape of your light's volume of influence.
Some related links (just me googling for stuff that looked decent in no particular order)...
Upvotes: 2