Here is an idea that should enable to render multiple lights with shadow volume without clearing the stencil buffer for every light (at least in some cases).
The point is to use some bits in the stencil buffer to identify the effects of various lights.
We assume:
-Zpass method
-viewer outside the shadow volumes
-s is the number of stencil bits
-n the number of “light bits”: we will see that we can treat 2^n lights without clearing the stencil buffer. The light bits are those on the left.
-m the number of “normal bits”: they will be used like in normal Zpass (of course s=n+m):2^mis the effective range of the buffer
-for light number i (i in [1,2^n]) we define A(i)=(i-1)*2^m
Now, you have probably found the idea: for each light, the relevant range of stencil buffer will be in [A(i),A(i+1)-1]. The following just describes the stencil settings to make things work.
Let’s consider a particular pixel, S is its stencil value.
draw normal geometry, with stencil test:
S<=A(i) (not the usual ==)
next light…
A few comments:
The trick is in the front pass: every pixel covered by a shadow volume directly jumps in the range of the current light and gets incremented if it is not already in this range. If it is, we just increment as usual.
Note that given the assumptions, the back pass can’t make the stencil value decrease outside of the range of the light.
I hope I’ve made it clear (I didn’t mention a few subtleties), tell me what you think about this (especially if I’m wrong).
Hehehe…
You’ve got it: Id had forgotten that stencil test is before Z test…
But anyway, has anyone heard of any kind of technique to reduce stencil clears? There must be one way…
You have to clear the stencil buffer to 0 for every light to reset the shadow volume enter/exit counter. If you don’t do this between lighs (applies to both zpass and zfail method), you will have incorrect counter values in the stencil buffer from the previous light. In other words, when it comes to rendering the geometry again that is supposed to be lit by the current light source (after having rendered the shadow volume) some of the stencil values might still be leftovers of the shadow volumes of the previous light source. Additionally, some counter values for the shadow volumes of the current light are thrown off. Therefore, the fragments corresponding to these incorrect stencil values will be incorrectly lit (or not lit, if the count was thrown off) by the current light source.
Don’t you “scrub out” your shadowed regions created in 2.?
Wouldn’t it be OK to just go…
Ambient Only
Shadow Buffer (Light1)
Shadow Buffer (Light2)
Lit
Certainly in my simple test it appeared to be OK. Im Using the nVidia “Robust Shadows” technique so the shadow volumes from one light source should not affect the volumes from another (ie. Shadow overdraw).
You would only get correct results if light 1 and light 2 are identical (same position or direction)
The method proposed here seem to suggest to subdivide the stencil buffer for each light, but it leads to complications and old GL can’t help. Neither can fp at the moment.
Suppose you have one red light, and one green light. Areas that are in shadow from the red light should be green if they’re not in shadow from the green light, and vice versa.
You can avoid clearing the stencil as often if you can limit the amount of enter/exit counting you’re prepared to accept. For example, you can slice 8 bits of stencil into 2 4-bit values; for the second light, you increment/decrement by 16. However, that can end up being extremely messy, and is “probably” not worth it.
We use some “box packing” technique that renders lights with the small nonoverlapping screen rectangles without clearing the stencil buffer.
If we can’t find a non overlapping light anymore we clear the stencil buffer and start over again.
This can save some clears…
The ones that were discussed but not actually implemented maybe a year or two ago? (Drat
If you use convex stencil volumes, you can of course use REPLACE with a single bit per light, which allows you 8 lights. But most stencil volumes aren’t.