Page 1 of 3

Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Jul 26, 2012 2:03 pm
by foxbat
I've released a demo of my shadowing implementation for large outdoor scenes, based on the technique used in Crysis. My implementation uses custom ShadowCameraSetup and shaders.

Here are details on the two techniques used. Each technique may be used independently, but I've included both in this demo.

Stable Cascaded Shadow Mapping
- Remains stable in world space, independent of camera translation and rotation
- Shadows rendered in multiple cascades (implementation uses 4 cascades) giving good shadow resolution over view range
- Blending between cascades

Implementation limitations:
- Only works with directional lights
- Branching is required in fragment shader for cascade selection (could be eliminated by packing cascades into single shadow map)


Rotated Poisson Disk sampling
- Poisson Disk filter is rotated per pixel using a jitter rotation map
- Eliminates shadow edge jaggies at the expense of adding some noise
- filtering is stable in world space to minimise buzzing
- More samples (texture lookups) gives less noise. Implementation uses 8 samples, but can easily be modified for more
- IMO looks better than PCF for similar number of texture lookups (mileage may vary)

Image

Image
Self shadowing

Image
Debug Visualisation of cascades (note blending)

Image
Rotated Poisson Disk filtering (8 samples)


Download windows demo and cross-platform source (MIT license).

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Jul 26, 2012 2:39 pm
by Mind Calamity
Kudos to you! This is very, very awesome! Probably the best shadowing technique I've seen lately. Quite good on performance too. Thanks a lot for sharing it :)

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Jul 26, 2012 2:51 pm
by DavlexDesign
Kudos to you foxbat,

I've been looking at this very same approach for close up scene shadows in my project, this should really help me out.
thank you very much.

Alex

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Jul 26, 2012 3:53 pm
by bstone
Unbelievable! I just mentioned this method a week ago as the best one for terrains and here you go - foxbat to the rescue :D.

If somebody manages to implement the UV packing of the shadow atlas now then this will be the uber shadows method for large scenes in Ogre.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Jul 26, 2012 4:39 pm
by scrawl
Very nice, the demo works in Wine on Linux as well btw.

The only problem I can see with it is that near shadows (first split) have more blur (in world space) than far shadows (last split). Not that much of a problem anyway, since you have blending between that. But couldn't that be solved easily by considering the texture size for the blur radius?

Why do you use BitBucket to upload a source zip file, instead of the source itself? That kind of defeats the purpose of version control.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Jul 27, 2012 10:18 am
by foxbat
If somebody manages to implement the UV packing of the shadow atlas now then this will be the uber shadows method for large scenes in Ogre.
I agree, that would be an awesome feature. I looked at this briefly a while back. I think the most efficient way to do it would be to render each map into a different rect within the same texture, but that's a fairly low level render system feature and as far as I know Ogre doesn't currently support this (correct me if I'm wrong). Second best option would be to render each separately and then pack on the CPU or GPU. The cost of packing would need to be weighed against the cost of branching.
Why do you use BitBucket to upload a source zip file, instead of the source itself? That kind of defeats the purpose of version control.
I uploaded the source archive for convenience in case there are people who want to download the source once-off and don't want to install a Mercurial client. But you're right; version control is the much better option for most people.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Jul 27, 2012 10:25 am
by al2950
@foxbat

Checked out the demo and it is very impressive. Would like you to see yout shadow camera system added to the Ogre repo :). As for the texture atlas thing the RTSS can do that, well sort of. There is a sub render state called instanced viewports, which will allow you to render several viewports to a single texture using one set of render calls. However its not part of the RTSS component but part of the sample (not sure why!).

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Jul 27, 2012 10:35 am
by bstone
foxbat wrote:render each map into a different rect within the same texture, but that's a fairly low level render system feature and as far as I know Ogre doesn't currently support this (correct me if I'm wrong)
I don't see any issues here. Get texture's render target, clear it before rendering the first shadow map, configure the viewport to cover the packed bounding box and clear no buffers (can overlap the bounding box of the previous cascade, no problem), render to the texture, move to the next cascade. Something like that.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Sun Jul 29, 2012 1:39 pm
by foxbat
al2950 wrote:Would like you to see yout shadow camera system added to the Ogre repo
I think that's a good idea. Adding an additional ShadowCameraSetup option should be pretty straight forward.

More complicated would be deciding what to do with the shared GPU parameter set used for passing the cascade transform offsets to the shader. This is used as an optimisation since there's no need to pass the complete matrix for every cascade (due to partial similarity of the matrices). The user should still be able to pass full matrices using the existing Ogre functionality if they don't want to use the offsets method. Perhaps the easiest solution would be to provide a hook to let the user get the cascade offsets and setup their own GPU parameters. Another way would be to add an auto parameter for the cascade offsets, only to be used in CSM mode.

The Poisson Disk filtering is implemented in shader only, so it can happily exist outside of the Ogre repo unless it would be useful to have as a demo.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Mon Jul 30, 2012 1:22 pm
by bstone
See how PSSM shadow camera setup handles plane split points. I think you should be able to use the same approach for passing cascade offsets and it will be coherent across shadow setups.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Tue Jul 31, 2012 10:54 am
by foxbat
I believe OGRE's PSSM implementation requires texWorldViewProjMatrix0 through texWorldViewProjMatrix3 to be sent to the fragment shader (one matrix for each shadow texture). My CSM implementation can work this way also, but actually requires less information; just texWorldViewProjMatrix0 for the first cascade and then a vector for each additional cascade. Doing it this way means fewer calculations are required in the fragment shader (if you do your transforms in the fragment shader) or fewer texcoord registers used (if you do your transforms in the vertex shader) :)

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Tue Jul 31, 2012 5:21 pm
by bstone
That's totally controlled by the shadow receiver material declaration. You can pass whatever you want to the shadow receiver v/f programs. The texture projection matrix are supported by Ogre's material system via param_named_auto. But PSSM's split points are not for example. To work around that PSSM simply requires the "pssmSplitPoints" parameter to be set manually in the shadow receiver's material fragment program by the user code. You can do the same with your offset vectors. Hopefully that makes sense.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Wed Aug 01, 2012 12:33 pm
by scratchyrice
This is great!

How would I go about using this with normal mapped objects?

Thanks

Scratchy

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Wed Aug 01, 2012 11:01 pm
by scrawl
Carefully "merge" the normal mapping shader together with the shadow receiver shader from this demo. That's the only way to go.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Aug 02, 2012 11:09 am
by foxbat
I agree; combining the two into a single shader is probably the easiest solution and should be quite efficient. If your scene has a lot of overdraw you may get a performance benefit by doing an early Z pass (add a minimal pass before the main pass and set colour_write off).

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Thu Aug 02, 2012 12:45 pm
by scratchyrice
Thanks foxbat and scrawl. I thought that might be the way forward but just needed to be sure. I will give this a go as i am currently using the rtss in my engine and the performance hit is just unacceptable considering all i want is some directional shadowing plus normal mapping. Im good with core engine mechanics, ai and physics - but when it comes to shaders i have not a clue! lol

Cheers

Scratchy

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Tue Aug 07, 2012 11:26 am
by duststorm
Wow, amazing! :D I've been away for a week and look what's happened behind my back :wink:
I was seriously considering implementing this myself after bstone mentioned it.
Can't wait to test it out with Ogre::Terrain for real-time self-shadowing.

I'll probably have a try at incorporating it into RTSS, that will make it easy to combine it with eg. normal mapping.


EDIT: just tried the demo, it compiles without a hassle on linux thanks to the CMake setup.
One small mistake with the materials though: the textures for the skybox should have lowercase names (eg. "stormy_fr.jpg" instead of "stormy_FR.jpg"). On linux and OS X this matters, and will otherwise result in a white sky.

A quick hint: you can enable the cascade debug by uncommenting the "#define DEBUG_CSM" line in media/core/ShadowReceiver.cg

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Mon Aug 13, 2012 10:39 am
by duststorm
I did a quick test with it and I found an issue with normals when scaling models. Normalizing the normal in the shadow receiver shader fixes this. I made a pull request with a fix to your bitbucket repo.

I found that it was really easy to incorporate it into your own application, kudos to that. Just make sure that you create a CSMGpuConstants object BEFORE loading any materials, as some constants need to be set in advance (or shaders will fail to compile). In the example application framework you could do this by overriding the loadResources() method, as the demo illustrates.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Mon Aug 13, 2012 1:12 pm
by foxbat
Thanks for the fixes. I've pulled them into the repo :)

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Wed Aug 15, 2012 11:32 am
by lygyue
How a nice job! Do you have shader code for point light? Please sent me if you have. Thanks alot.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Aug 17, 2012 4:41 pm
by duststorm
To give you a heads-up: I'm working on a modified TerrainMaterialGenerator that also supports this shadow technique. But as I don't have much time at the moment I work on it for short periods of time.

Having experimented with it a little more I really have to express praise for this wonderful shader. The poisson filtering does a wonderful job at smoothing out the shadows, and the fade between cascades is something that not even Crysis has but makes the shadows really fluent.
I'm really amazed at how incredibly stable the shadows are. Even with moving lights and objects it does a pretty decent job.

There are a few things I'd like to improve on it when I get the time, like how split points are set and how parameters are passed to the shader. I would also make it more configurable, like the texture resolution and number of cascades. It would also be nice to be able to enable or disable the debugging and poisson disk filtering from code. Apart from that it's great.

Here' s a teaser (it's not completely working yet):
screenshot08172012_172827517_small.jpg
Stable CSM on terrain (debug)
screenshot08172012_172827517_small.jpg (137.36 KiB) Viewed 28055 times
The intended end-result is a terrain with pagedGeometry trees and a dynamic day-night cycle using Caelum or SkyX. For this to look decent I need the shading of the tree impostors to vary with the changing lighting and terrain needs to cast dynamic shadows (as opposed to using pre-calculated lightmaps to store which part is shadowed). I'm confident that I'll be able to realize that with this shadow technique.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Aug 17, 2012 6:27 pm
by amigoface
very nice !

highly intersted to see the results

btw : using skyx with the volumetric clouds will look much better ;)

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Fri Aug 17, 2012 7:54 pm
by Mind Calamity
Duststorm, that's just plain awesome! Without the colorful lights it'd look pretty realistic :)

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Sat Aug 18, 2012 12:37 am
by foxbat
Nice work Duststorm. Feel free to make all the improvements you want. :)
lygyue wrote:How a nice job! Do you have shader code for point light? Please sent me if you have. Thanks alot.
The CSM shadowing technique is designed for directional lights and very narrow spotlights (only directional lights have been implemented). You will need to use a different shadowing technique for point lights. The poisson filtering shader code is independent of shadow projection, so you should be able to use it on point lights without modification.

Re: Cascaded Shadow Mapping & Poisson Disk filtering

Posted: Sat Aug 18, 2012 7:02 am
by DavlexDesign
foxbat wrote:Nice work Duststorm. Feel free to make all the improvements you want.
I second that, for the closer up stuff, this would be really really nice.

Alex