Skip to main content
GameDev.net gamedev.net
🔒 Locked

Terrain shadowmaps

Started by Pancake Oct 29, 2004 at 5:14 AM 6 replies 1.1k views
Original Post
Pancake
Pancake
Now I already have a tiled shadowmap system working and it looks pretty nifty. However depending on the size of the to be rendered object it can need several shadowmaps to properly shadow it. A large building can easily require the nearest 3 or 4 shadowmaps and this is kinda whats bugging me. the shadow-part of the fragmentshader is very short but looking up 4 shadowmaps per pixel does sound very costly. from this thread: http://www.beyond3d.com/forum/viewtopic.php?start=20&t=16267
Quote:
I don't believe in perspective shadow maps. For an outdoor scene, you need to make "cropped and mip mapped" shadow buffers. One buffer is used to just cover the area up to 1000 units away, the next one covers 2000 units, the next 4000, etc. You may need to do six or more levels like this, but you can use stencil select to avoid any overdraw, so it is basically the same problem as stitching together a cube of shadow buffers for a point light. John Carmack
So I was really wondering what carmack ment with the stencil select to avoid overdraw (as I don't really understand what he ment with that). And has anyone tried something like this yet?
SimmerD
SimmerD
What he means is that one terrain chunk may have several shadow maps applied to it. You want to render part of the terrain chunk with one shadow map, and a second part of the chunk with another shadow map. Unfortunately, the shadow maps may not like up nicely with chunk geometry boundaries, so you need a way of rendering only the appropriate pieces for each shadow map.

One way is to user clip planes, but this is not guaranteed to produce the same geometry Z, color & texture coordinates as the terrain chunk without user clip planes on. You could pre-clip all geometry to shadow map boundaries, but this only works for static geometry.

So, you want a raster-level test like alpha test or stencil. Alpha test has the problem that it doesn't get anti-aliased. So, you're left with using stencil to select areas of the screen that apply to one shadow map or another.
Soiled
Soiled
For stencil-selecting I'm guessing that Carmack means drawing backfaces of the six orthographic light frusta into stencil buffer (the six light frusta are always roughly centred around view position and don't intersect near plane - I'm assuming Carmack was talking about something like the sun in Pancake's quote). Each frustum draw increments stencil. So pixels in the tightest frustum get stencil 0, the next tightest frustum get 1, etc. Then when rendering scene, any geometry that overlaps N light frusta needs N draw calls each of which uses a single shadowmap lookup.

That means six full-screen rasters (not a screen-size quad but the inside of a closed light frustum which surrounds view position) are needed to set stencil which seems like it might be expensive (perhaps not so bad with early zcull) plus you need to render all shadowed geometry first (but that has other benefits) - maybe it's not so bad unless you're vertex limited. Is there a better way to set the stencil in this case that doesn't require full-screen rasters ?

Another option, other than stencil, is to hierarchically partition your scene (at pre-compile) so that all leaf nodes always fit in the smallest of the six light frusta. That way you can always draw such that you never cross more than two shadowmaps - but that might be a bit restrictive if shadowmap covers small area in which case could use stencil for nearest one or two light frusta only (instead of all six). So you never have more than 2 shadow map lookups but it's still more expensive than the one shadowmap lookup used by stencil approach but you get the benefit of being able to smoothly blend the shadows across the boundary. With the stencil method there might be a visible shadow transition across the shadowmap boundary if the shadow map resolution/filtering is not high enough. Er... just realised, the stencil approach can do two shadowmap lookups (since the shadowmaps overlap) and blend between them to avoid a seam at shadowmap boundary.

So I guess that means use stencil only on the light frusta that need it.

Also Carmack noted in "Quakecon 2004 Keynote" that because of stencil he doesn't need to clamp his shadowmaps and so presumably he can stuff multiple shadowmaps into one texture. Although you can do this by blending to zero before reaching edge of shadowmap. I'm guessing that the stencil approach is mainly to allow a chunk of geometry to overlap more than two light frusta without the complications of blending more than two shadowmaps.

btw: SimmerD, thanks for pointing out the stencil test being multi-sampled.
Pancake
Pancake
Thanks for the explanation guys

I'm not sure I fully understand your way of doing it Soiled. After reading SimmerD's post I was thinking of something like this: you'd first render the part (no color writes) that covers the closest shadowmap and set it's stencil value to 1 then render the stuff that covers the 2nd map and set the stencilvalue to 2, ect. Depthtesting is set to GL_LESS so you won't overwrite the closer stuff and use a small shader to discard any fragments that exceed the far distance of the respective shadowmaps range.
The final pass will render the closest geom with only the first shadowmap bound where stencil equals 1, ect..
Something like that?

So it's not going to give much of a speedup but make it easier on managing the whole stuff. Another advantage would be that you'd have more free texcoords avalable since with 3 shadowmaps per pass you'd eat up 4 texcoords (1 extra for the distance, but you could use that for calculating fog as well so it's not that big of a deal) because thats what has been bugging me a lot. Doesn't leave much free texcoords for the rest of the shader.

BTW the harsh transitions between 2 different shadowmaps are not much of a problem when the distances are chosen correctly. PSM's also help with making any seams practically invisible.
Soiled
Soiled
Yes, that would work. You're using texkill by the sounds of it so you probably don't need stencil. I was thinking of using stencil instead of texkill to do the clipping for a few reasons (i) SimmerD pointed out that texkill doesn't get antialiased but stencil does (so the two different resolution shadows across boundary get antialiased when using a multisample backbuffer), (ii) texkill bypasses the early z-buffer and hence texkill rendered geometry is not an effective z-occluder (because the decision whether to write to zbuffer or not occurs in pixel shader which is too late in the pipeline to write to the early z-buffer).

So I was thinking of rendering the whole scene as z-only first and then rendering each orthographic light frustum (ie box) associated with each shadow map into the stencil buffer (similar to what shadow volumes do) to set them to the same stencil values you mentioned. Since viewpoint is inside this light frustum box its backfaces are rendered. Render the smallest light frustum first so *all* visible geometry outside the nearest light frustum gets set to stencil of 1 (inside is 0). Then render the next biggest light frustum (with stencil op set to increment) and this sets all visible geometry outside this second light frustum to stencil of 2, etc. In the final pass render as usual.

Actually it's more efficient to render biggest frustum first and smallest last and use the stencilop replace instead of increment and use a stencil test of ==0 to avoid setting stencil pixels more than once.

Perhaps another optimisation is to avoid rendering the entire light frustum into stencil (which covers entire screen). Determine geometry (or its bounding volumes), inside view frustum, that intersects with difference between two light frustums ... ie, the region where a shadowmap is used. Project these bounding volumes into screen-space of viewer and generate a 2D bounding rectangle and render this instead of the light frustum. Might save some stencil fill in some cases.
Pancake
Pancake
I completly forgot about texkill bypassing the early z test. But at least I understand your idea about doing it now though. Thanks for re-explaining it :-)
A possible optimization: You don't have to render all 6 lightfrustums (assuming we are using 6 shadowmaps for an entire landscape) You don't have to render the last lightfrustum since there is no geometry beyond that to be rendered. Also you would only need the select for the closest 3 or 4 shadowmaps, if an object is on the border of map 5 and 6 just use the 6th shadowmap since it's so far away I doubt you'll notice the difference. That should lower the fillrate cost a lot as well.

Just thought of something, this approach won't work on translucent objects..
Soiled
Soiled
That's true. And only set stencil for objects that actually cross a shadowmap boundary.

I guess for translucent objects it's back to texkill. So they don't get *written* into early zbuffer which is ok since they're not going to occlude many objects (because they're rendered after all opaque objects). I'm pretty sure they should still get early z-rejected (even though using texkill - AFAIK texkill only affects where the z-writes go, late or early z-buffer, and hence only affects *future* z-rejects). You do lose antialiasing for multisample buffers though but not much can be done about that I guess.

[Edited by - Soiled on November 1, 2004 11:03:56 PM]
Pancake
Pancake
Translucent objects will be a different beast to slay but I'll worry about that later on. Just wanted to say thanks for the help you gave :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.