Managing lights in the render pipeline in huge worlds

Started by
4 comments, last by obhi 12 years, 9 months ago
Hi all,
A question I am facing is how to manage lights in a portal based system when objects are pushed into the render queue.

Currently what I am doing is pushing the lights into a lighting queue and based on the importance of the light taking the first n sorted lights for shadow generation and then doing the illumination pass. The problem in a real world scenario will be, suppose I have a terrain lit by the sun and a house nearby with interior lit by any other source. The regions will be connected via portal. So, if I am rendering from the terrain I should take the sun for shadow generation while rendering from the room from a perspective where the terrain is visible, the shadowing should not only take into account the house's light source but also the terrain's? Also considering multiple point lights may have different influence radius if I have 5 street lamps how do I go about casting shadows from them. Should I use the lazy shadow generation scheme using 1 cube map and rendering from each point light's pov to it and then rendering the light using it ( or generating an occlusion map used in deferred shadowing by it )? Or should I just use 1 directional light to do the same (probably the approximation that has to be done based on if multiple lights are visible). But I am sure this is not going to give me correct shadows for eg, on wall corners which has an adjacent light because that light will not be used for shadow generation.

Can anyone shed some lights how professional games manage shadow generation in huge world structures with multiple lights.

Thanks for any help.
obhi
What if everyone had a restart button behind their head ;P
Advertisement
Today, well I was observing how this is actually happening in real world with multiple lights around, (in a hallway to my office).
So, I think its ok to approximate and take the first n closest light into account for shadow generation, where n is the cap for the amount of shadow map supported.

I am also considering the fact that while transiting regions say from indoors to outdoors, a certain delay can be added to change the type of texture used for shadow map because of change in the main source's light type may be.
What if everyone had a restart button behind their head ;P
Not sure if I follow your way exactly, but to put it simple: render every light that effects the stuff you see.

Easier said than done of course. For one thing, lights can be placed in rooms that you can't see, and still cast shadows in the visible rooms. And if you have a big world, you may indeed want to limit the amount of lights. What I do is giving each light an importance factor (highest, high, medium, low, very low). This factor is a combination of:
- Manual factor given by artist (usually based on the light size, position and strength. A silly lamp in the corner of a room is less important than a big projector beam)
- Distance from camera
- Visible? If placed in a room that is currently not visible AND far enough from the camera, skip it)

This priority also tells on which resolution to render the shadowMap. The most important ones get the highest resolution shadowMaps. The less important ones have to deal with less quality. However, there are more "low-quality" slots available than high-quality. If the list of High-Priority lights is full, the weakest(furthest) light is degraded to a lower quality and tries to fit in that list.

The sun/moon is fairly simple. These should always have top-priority. Unless you really can't see them anymore because you are deep indoor somewhere. The other lights have to fight for a spot in the listings, based on the 3 factors. I have to admist this is not perfect yet either. Sometimes lights suddenly pop in or out when rotating the camera. A fade-in/out would mask that bug, but can be difficult to make.


Now when you are doing sorting, you can render their eventual shadowMaps, and finally render them into the scene. Basically each light will have it's own shadowMap, and the results of each light will be summed together. pixelColor = resultLight1 + resultLight2 + ...
The exact implementation depends whether you use a Deferred/Inferred rendering approach, or good old forward rendering. With forward rendering, you'll have to draw the object again for each light (and use additive blending to sum all the results). Which is why Deferred Rendering is popular nowadays; you only have to render the geometry once (or twice) no matter how much lights there are. Then render the lights themselves as simple volumes or screenquads.

Rick

First thanks for that insight Rick. I read about lights being given an importance factor to choose and given a shadow map slot before, but it really clears up when you said you choose that factor to also resolve what resolution the shadow map should be chosen.
My main problem was cosidering this fact (which apparently I couldnt state simply in my last posts):

Given a certain distribution of lights visible from a perspective in the currently rendered frame, and assuming the lights are spot light type, and also each having same importance factor (street lamps lets say with no moon), so I have to allocate say 2 shadow maps to at the most two nearest light (lamps). Now with this approach clearly the street will cast shadows in only the areas influenced by the two spot lights and the others will just illuminate (considering a deferred approach) without the shadow maps.

To resolve this issue, I thought of having 1 shadow map per light type, and before the illumination pass generate the shadow map for say n lights (not all visible ones), and accumulate the shadow or occlusion factors in a accumlating buffer in the view/screen space of the camera. This will solve the memory constraints but I dont know the implications of such an approach will have on GPU state changes.

But I am quite sure this case is far fetched so probably this approach will not be necessary.

Thanks again for the reply.

obhi

What if everyone had a restart button behind their head ;P
Well, as far as I know, you can't put multiple lights into a single shadowMap. If you want 6 streetlamps casting shadows, you'll need 6 shadowMaps as well. And rendering the 6 lights one by one as well. Now 6 isn't that much for modern hardware, don't worry. And also don't forget a large portion of the scene gets litten by Global Illumination. Calculating that in realtime is extremely difficult, but you can come quite far with faking or eventually using pre-baked lightMaps. It's the whole mixture of things that finally sets the scene.

What you could do is simplifying distant lights of course. Point or spotlights without shadowMaps are much easier to render. They don't need a shadow(depth)map, and you can render many, many of them on modern hardware (with a Deferred renderer). Sure the results aren't always correct. Then again, who will see that for a distant light? The lamppost in particular doesn't cast many noticeable shadows anyway. Not sure, but I can imagine GTA does such a thing. And on even larger distances, they replace the light with a cheap flare sprite.
Ah, I have done good old light map generation and radiosity before. But I want to have day/night cycles which is where I think I wont go for static lm's.
Let me explain why I think 1 shadow map per light type can be enough (only for a deferred renderer or a forward with a pre-z pass)

1. With pre-z you already have the depth buffer.
2. For light l where l ranges from 1 to n
3. Bind (according to light type) shadow map s
4. Render to the shadow map depth buffer from light pov
5 Bind z buffer from z-pre pass, the shadow map s
6. Bind an occlussion map (8 bit texture) as render target
7. Render a full screen quad
8. In the shader: (EDIT: fragment shader I mean)
9. use the z buffer,clip space coords, canvas size, near and far planes to generate world position of the rendered point.
10. calculate occlusion factor (occFactor): based on light distance to point (in light's space) and projected distance from shadow map, compare and set an occlusion factor.
11. fragOut += (occFactor)
12. End for

This occlusion map now can be used for any other illumination pass for any light so no need of specialzed light passes.
This approach I guess is called Deferred Shadowing (or something similar).

However I think it is probably not necessary and may incur overhead because of the state changes and render target changes.
May be a deferred context might help it in someway I donno..

Anyway, I think I understand the approximation most games do inorder to avoid taking every light into account. 6 shadow maps, I havent tried that much but will give it a shot after revamping my rendering pipleline.

Thanks again.
obhi
What if everyone had a restart button behind their head ;P

This topic is closed to new replies.

Advertisement