Shadow Maps, multiple lights and textured entities

Hi,

I have problems combining shadow maps and textured entities.

When doing multiple passes with additive blending to apply the shadow maps, the textured entities (with GL_MODULATE, on Texture Unit 0) become lightier than they should.

Example:

Scene with 2 lights: Light1 projects shadows, Light2 doesn’t.

Pass 1:
Build the shadow map of Light1.

Pass 2:
Draw the scene with only ambient color for Light1 and ambient/diffuse/specular for Light2.

Pass 3:
Enable additive blending (GL_ONE, GL_ONE) to add contributions of Light1.
Enable ShadowMap with depth Comparison (on Texture Unit 1) and draw the scene (with its textures on Texture Unit 0).

The textured entities become lightier than they should, while non-textured entities are fine (the lit parts have the same illumination they have if I disable ShadowMaps).

Am I doing something wrong?
What is the correct way to get the correct illumination for textured entities when using additive blending with multiple passes?

Enable ShadowMap with depth Comparison (on Texture Unit 1) and draw the scene (with its textures on Texture Unit 0).

Do you still have blending on at this point?

Enable additive blending (GL_ONE, GL_ONE) to add contributions of Light1.

…and at this point it’s all looking good? (without shadows of course)?

Yes, it’s the Pass 3: I enable additive Blending AND the ShadowMap texture compare and then I draw the scene.

No it’s not. If I don’t enable the ShadowMap texture compare and I do the Additive blending pass adding the Light1 contribution to the whole scene, the entities with texture are lighter than they should.

Maybe drawing modulated textures in successive additive passes is not the right thing to do… Probably I’m adding the texture intensity more times than I should.
For example, if a pixel is in full light for Light1 and Light2, drawing it in one pass will result in the texture pixel with full intensity, but if I do it in 2 passes I would add the intensity of the texture 2 times (one in the first pass due to full Light2 illumination and one in the second additive blending pass due to the full Light1 illumination).
Am I missing something?

Originally Posted By: BionicBytesQuote:
Enable additive blending (GL_ONE, GL_ONE) to add contributions of Light1.
…and at this point it’s all looking good? (without shadows of course)?

No it’s not. If I don’t enable the ShadowMap texture compare and I do the Additive blending pass adding the Light1 contribution to the whole scene, the entities with texture are lighter than they should.

Right. So you need to fix this part first before even considering the shadow mapping contribution.

Maybe drawing modulated textures in successive additive passes is not the right thing to do

I think it is. That’s how my deferred engine is ultimately doing it.

For example, if a pixel is in full light for Light1 and Light2, drawing it in one pass will result in the texture pixel with full intensity, but if I do it in 2 passes I would add the intensity of the texture 2 times

Right. Think about it. If light1 adds a bright area to the scene, then a second (euqally) bright light on the same spot should double the intensity at that point.

So, with this in mind…do you still have a problem?

If the problem is about saturation, then there are ways to handle it. When adding light a couple of time, all RGB channels are saturated and you only see white.

If so, consider using High Dynamic Range (HDR) instead. In the end you transform back into the range 0-1, using Tone mapping.

Yes I do.
If with one pass I get the full texture intensity (which is the result I consider correct) and with 2 passes I get the double of intensity, how can I get the full texture intensity with 2 passes?

These are the pictures of:

Lighting without textures
Lighting with textures in 1 pass (Light1 and Light2)
Lighting with textures in 2 passes (Light1 + Light2)

If with one pass I get the full texture intensity (which is the result I consider correct)

This is the part I don’t agree with. What makes you so sure your single pass is actually correct?
The multi-pass approach is generally considered correct with additive blending. If light 1 adds a contribution of 200 (out of a max 255) to the scene, a second light may also add 200/255. The total white at the scene an these points would be 400. There is nothing wrong with this result even if it’s past the max RGBA values of 255 (that’s why you need to be using RGBA16F light accumulation buffers and tone mapping).

Ok, those pictures help put things into perspective.
However, it would be more useful to just see the effects of diffuse lighting (no ambient). Also, reduce the intensity of both lights so that when combined, they don’t saturate to pure white. If you can focus the second light so it does not affect the whole cube (spot light?) then that would also help us visualise the combined effect of the lights.
From what I’ve seen, the two pass approach looks better because the more lights you add to the scene - the more washed out everything is going to become.

Considering that Shadow Maps is today a mature approach, I guess that many developers faced this issue. Where can we learn/read more on how to combine all these factors and get a perfect looking rendering?

Is there any white paper / article on this subject on the net?

Thanks,

Alberto

Where can we learn/read more on how to combine all these factors and get a perfect looking rendering?

Read any material that teaches you to not use the fixed-function pipeline. It’s hard to say what exactly your problem is without seeing all of your lighting parameters and such, but odds are good it has something to do with some lighting state.

Shaders are much, much easier to control.

Also, HDR is kind of important. But since you seemed to ignore that, I’m not sure how much we can help. We can only tell you what you ought to be doing and how everyone else solved it.

Alfonse,

Do you mean we cannot complete perfect Shadow Maps without using shaders or HDR?

Is it possible that there is no way to combine these multiple passes without going out from the 0-1 RGB color range using the fixed-function pipeline?

Thanks again,

Alberto

Of course. Shaders where invented expecting they would not be ignored …
Even using shaders, or shaders+HDR, you will only be closer to perfection and still not touching it.

Using a linear workflow and proper gamma correction in and out is mandatory for any “close to perfection” renderer.
http://www.geeks3d.com/20101001/tutorial-gamma-correction-a-story-of-linearity/
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch24.html
http://renderwonk.com/blog/index.php/archive/adventures-with-gamma-correct-rendering/
http://beautifulpixels.blogspot.com/2009/10/gamma-correct-lighting-on-moon.html

and lots of others.

Thanks ZbuffeR,

I believed that basic shadow maps could be implemented without the need of shaders or HDR to avoid going beyond the 0-1 RGB color range…

Now at least we know we can give up trying… :frowning:

Alberto

Your problem isn’t shadow maps. It’s multiple lights. As I said, you’re probably doing something wrong in your fixed-function lighting setup code. Which would be much easier to see and much more obvious if you were using shaders instead of arcane fixed-function commands.

I solved the problem in the following way:

During the shadowmap passes (with additive blending to add the lights contribution), the entities with textures are drawn without texture and with white material.

Then I do a final pass with the textures enabled and multiplicative blending (GL_DST_COLOR, GL_ZERO), to multiply the texture color by the lighting intensity resulting from the previous passes.

Regarding the shaders, we spent much time to make them work but due to difficulties in managing general cases (parallel split shadow maps, multiple lights with shadows) we decided to stick with the fixed functionality for now.
Furthermore, with shaders we would still have to do multiple passes, so the problem of adding the texture contributions would still be there.

Alfonse,

Do you think we can do perfect parallel-split-shadow-maps with multiple lights yielding shadows on both non-textured and textured object using the arcane fixed function commands?

A this stage we are not trying to go fast but to get the correct result without involving shaders and HDR even if it requires a number passes.

Thanks,

Alberto

Furthermore, with shaders we would still have to do multiple passes, so the problem of adding the texture contributions would still be there.

No, it wouldn’t. As I said, your problem likely comes from some lighting thing that you’ve set up but don’t quite understand. What you are doing, rendering multiple passes and adding the contributions together, is called “forward rendering”. It is a common technique, and it has been done for ages. It is a solved problem.

If you’re getting incorrect results, it’s clearly because of something you’re doing.

The point I was making with shaders is that you would be able to see everything. It wouldn’t be hidden in arcane OpenGL fixed function garbage. If there’s a bug in your shader code, then just debug it using common shader debugging techniques. This too is a solved problem.

Shaders are easier to use because you can see everything. Every lighting function is executed exactly as you wrote it. Not hidden behind state and variables and junk; it’s there, plain as day.

Do you think we can do perfect parallel-split-shadow-maps with multiple lights yielding shadows on both non-textured and textured object using the arcane fixed function commands?

A better question would be… why would you want to?

Why go through all the trouble of implementing a complicated shadow mapping technique… when you’re using crappy fixed-function lighting and no HDR or gamma-correction? It’s like buying a sports car and using it only for 5 minute drives to the store. Or using hundred-dollar bills as toilet paper.

There’s no point in using a high-fidelity graphics technique like shadow mapping if you aren’t going to combine it with other high-fidelity graphics techniques.

Hi Alfonse,

If you’re getting incorrect results, it’s clearly because of something you’re doing.

Yes probably, we need to understand where…

A better question would be… why would you want to?

Why go through all the trouble of implementing a complicated shadow mapping technique… when you’re using crappy fixed-function lighting and no HDR or gamma-correction? It’s like buying a sports car and using it only for 5 minute drives to the store. Or using hundred-dollar bills as toilet paper.

The reason is simple: we want to run on all GPUs legacy and modern. Even with graphics drivers not updated.

Thanks again,

Alberto

Not necessarily. From context you’re talking about the proposed multiple passes to add the contribution for each light to the scene (accounting for its shadowing). If the number of lights isn’t huge, you can do all this in a single pass by doing the lighting/shadowing calcs for all lights in the shader (see next post).

Though at some point though, you bump into limits on the number of uniforms you can have (too many lights/shadow maps), or end up using too much memory for shadow maps, and end up having to break it into multiple passes.

However, in the many lights case, both of these tend to be very wasteful of GPU resources, so you end up thinking about Deferred Rendering techniques.