Sign in to follow this  
MARS_999

Cascade shadow mapping?

Recommended Posts

MARS_999    1627
I have been looking for some info on implementing this technique or has anyone tried it themselves? Any background info on it would be great also. Thanks

Share this post


Link to post
Share on other sites
Brian Lawson    147
I've implemented it (at least what my interpretation of it was -- as there's not a whole lot out there on it, at least that I could find) with pretty good results.

To me at least, CSM was a lot more straight forward and intuitive in terms of handling its special cases rather than some of the more complicated issues and special cases associated with things like Perspective Shadow Maps or Trapezoidal Shadow Maps.

In essence you can divide your viewing frustum up into several regions -- dedicating a shadow map to each region.

I currently split the frustum into two regions. You can do more, but then it'll require a more complicated shadow caster/receiver determination algorithm -- which could start to get a little crazy. The two region approach essentially gives you a "higher-rez" region closer to the camera and a "lower-rez" region beyond the "high-rez" region's cutoff.

The only real issues at that point are handling the areas of adjacency -- i.e. the border between each region and the regions of light frusta overlap -- as you'll have a "virtual" light frustum bounding each "region".

Share this post


Link to post
Share on other sites
wolf    852
Brian, this sounds interesting. How did you construct the view frustum for those two shadow maps?

Share this post


Link to post
Share on other sites
Ingenu    1629
I got this link around here I think :
http://appsrv.cse.cuhk.edu.hk/~fzhang/pssm_vrcia/shadow_vrcia.pdf
Parallel Split Shadow Mapping, basically what you want, it's quite effective and waste less fillrate and memory (smaller ShadowMaps).

Share this post


Link to post
Share on other sites
wolf    852
did you implement this? I think it is not usable in a game or a game like environment.

Share this post


Link to post
Share on other sites
Ingenu    1629
Quote:
Original post by wolf
did you implement this? I think it is not usable in a game or a game like environment.


Not yet, but I plan on doing it "soon"...

Share this post


Link to post
Share on other sites
Brian Lawson    147
Quote:
Original post by wolf
Brian, this sounds interesting. How did you construct the view frustum for those two shadow maps?


I don't know if what I implemented is what is described in that paper -- as I've never seen or read that paper before. When I get a chance I'll take a look at it just to see whether it is or is not what I've done.

As for constructing the two "virtual" light frusta, it's pretty straight forward. As you know, a directional light only needs to use an orthographic projection - no perspective projection required.

In this particular case, you'll be constructing two "virtual" frusta -- one to tightly bound each of the regions of your split viewing frustum.

I believe I actually maintain two separate shadow frusta with the camera's frustum -- one representing each of the two regions.

One of each of those corresponds to the high-rez and low-rez shadow regions in the visible viewing region.

To construct the two "virtual" light frusta I simply build a view matrix using the direction of the light. Then transform each of the eight frustum corners into view space and compute the max/min x, y, and z values (assuming your light view matrix has you looking down the z-axis). Those max/min x/y/z values will then give you all the info you need to build an orthographic projection matrix that tightly bounds that portion of the view frustum. You may want to give yourself a little lee-way on the negative side of the z-axis to allow for you to properly cull/detect off-screen shadow casters that while not "visible" will cast shadows into the viewing region.

At this point, you now have the light's ViewProj matrix for each shadow region, which can be used to render the corresponding shadow depth buffer for each region.

Share this post


Link to post
Share on other sites
MARS_999    1627
Thanks for the info Brian would it be possible to contact you on your method or get a quick tutorial on it? Sounds like a good method... As of now I have frustum culling working for my pathing system, but not sure how to implement that for shadowmapping also??? Thanks

Share this post


Link to post
Share on other sites
wolf    852
Quote:
To construct the two "virtual" light frusta I simply build a view matrix using the direction of the light. Then transform each of the eight frustum corners into view space and compute the max/min x, y, and z values (assuming your light view matrix has you looking down the z-axis). Those max/min x/y/z values will then give you all the info you need to build an orthographic projection matrix that tightly bounds that portion of the view frustum. You may want to give yourself a little lee-way on the negative side of the z-axis to allow for you to properly cull/detect off-screen shadow casters that while not "visible" will cast shadows into the viewing region.

I used pretty much the same method. The problem is that all the viewing frusta have to start at the same line ... so you render a bunch of objects twice or more(... with two maps these are the ones that are in the first slice). I will post a few other thoughts in the next mail ... I just need to make a few figures to show what I mean.

[Edited by - wolf on May 20, 2006 9:32:23 PM]

Share this post


Link to post
Share on other sites
wolf    852
Here is how the sliced view frustum looks like:
Cascaded Shadow Maps / Sliced View Frustum
Figure 1
Here is how the light view frustum calculation is handled:
Cascaded Shadow Maps / Light View Frustum Calculation
Figure 2
Here is the problem with shadows that cross view frustas. This is the reason why all the light view frusta have to start at the same line and the reason for the overdraw.
Cascaded Shadow Maps / A Tree Casts a shadow in the following slice
Figure 3
here is the problem with the tree that is outside the view frusta but should cast a shadow into the scene.
Cascaded Shadow Maps / A Tree is outside the light view frustum but should cast a shadow into the view frustum
Figure 4
And here is the same scenario from a side view. This time I painted two different times of day.
Cascaded Shadow Maps / A Tree is outside the light view frustum but should cast a shadow into the view frustum - side view
Figure 5
The orthographic projection of the lower sun should catch the tree ... if it is not culled?

Let the discussion begin ....

[Edited by - wolf on May 20, 2006 9:57:20 PM]

Share this post


Link to post
Share on other sites
Brian Lawson    147
Wolf,

Your diagrams are all correct up until the last one -- I'm not sure what's going on there. I chose only to split the viewing frustum into two regions for the reasons you mention (I'll explain more below).

Think carefully about this -- but anytime the direction of the light is NOT perpendicular to your viewing direction, you will have regions of "virtual" light frustum overlap. If it's not clear, simply diagram out a more simplified version using only two cascading regions instead of 4 or 5.

So, it's those resions of overlap that can be problematic -- but are relatively easy to deal with.

For starters you'll cull objects that are fully contained within each region into that region's shadow caster list. Objects that split the border will go into both regions' shadow caster lists. From there you can easily render out your shadow depth buffer assigned to each region.

When doing the shadow determination pass -- you will need to sample from ALL regions' shadow depth buffers because it's possible that an object in one region is casting shadows onto an object in another region.

And it was for that very reason that I chose to go with only two regions -- fill rate consumption when sampling from more than two shadow depth buffers starts to become unreasonable -- especially when implementing 3x3 PCF on top of it.

Does that make sense?

Share this post


Link to post
Share on other sites
wolf    852
Hey Brian,
I just added a better description. Figure 5 shows two different times. The one where the sun is lower, is the one that might be a challenge.
You can also replace the tree by a skyscraper .. same problem. I try to understand the implications of this situation.
As long as anything is in the light view frustum, it should catch the tree/skyscraper ... but I have to tweak my culling here. What do you think?

Share this post


Link to post
Share on other sites
Guoshima    204
well .. I have also basically the same implementation, but I still use deferred shading (still want to go to forward but didn't have the time yet). The shadow overlap problem becomes very easy then. You just give your 2 or 3 shadow maps to the shader and calculate the distance from the camera per pixel and select the shadow map to use there. No overlap problems then :)

I calculate my view frustra a little bit like they do in the parallel split algorithm. I use the Ci and Ci+1 (like described in the article) to set the near and far distance. From this I construct a box with certain radius, and create my view projection matrices to construct a 'camera' object. I then use this camera object to cull my scene (same culling system as my normal view camera with portals, antiportals and stuff like that), so I am sure that all the casters are inside. I do have to virtually modify my near and far plane during the culling to make sure that outside objects are culled correctly, but when rendering I reset my near and far to best optimized values. I don't know yet if a scy scraper will cast shadows into my scene yet, because I haven't tested this, but I presume it shouldn't be to hard to keep and extra list somewhere with the few very very big objects, and do some projective frustum culling or something to see if they will cast shadow or not. That's at least what I'm gonna try :)

I currently have 3 shadow maps. I can choose between 512, 1024 and 2K shadow maps. I use VSMs and blur only the one closest to the camera. Like this I don't have the pixel shader cost of performing PCF, and blurring on 512 is very cheap :) The 512 is actually more than good enough, for static objects and trees. As mentioned before I can't seem to get a good quality on neary characters and dynamic objects. I think I will use stencil shadows when dynamic characters and objects are close to the camera. Like this I always have perfect self shadowing, and I can even take a look at the soft stencil shadow methods, because I won't be drawing a lot of those.

Regards,
Kenzo

Share this post


Link to post
Share on other sites
Brian Lawson    147
Quote:
Original post by wolf
Hey Brian,
I just added a better description. Figure 5 shows two different times. The one where the sun is lower, is the one that might be a challenge.
You can also replace the tree by a skyscraper .. same problem. I try to understand the implications of this situation.
As long as anything is in the light view frustum, it should catch the tree/skyscraper ... but I have to tweak my culling here. What do you think?


Wolf -- gotcha. Two different times of day. :)

Okay, so one other detail I accidentally left out, was that when constructing the light's "view" matrix prior to transforming the 8 corners of each frutum into light space -- that view matrix is "virtually" positioned at the centroid of each frustum. The bottom line is you have to pick some sort of starting reference point position to transform the frustum corners into the light's view space.

With that info you can use the max/min x/y values to construct your max/min extents for your orthographic projection and you can use the max/min z-values to compute what your far clip plane distance will need to be. Like I said before, you'll likely want to back up your near clip plane some arbitrary distance so that you're certain to catch shadow casting objects that aren't necessarily IN the camera's viewing frustum, but ARE between it and the light source and casting shadows into the viewing frustum.

I use two 1k x 1k maps, however we can go upto two 4k x 4k maps. I looked at the VSM demo and didn't like the hard edges I saw around the edges of the shadows. Is that fixable or not? PCF is not that expensive these days since NVidia implements it in the silicon and I believe ATI has a variant on that now too.

For high detailed self-shadows -- per-object shadow maps are your answer. :)

Share this post


Link to post
Share on other sites
Guoshima    204
the problem with per object shadow maps, are that you might need quite a lot of those, because every near object might need its own shadow map (2 object can cast shadows onto each other). And how do you solve an object receiving shadows from quite a few casters. A single shader with more than 4 shadow maps seems rather expensive. You can off course project it onto the object, but then you get the nasty shadow overlapping problem .. Stencil shadows solve all these issues.

The good thing with VSMs are the blurring (which makes it cheap on 1600 x 1200 resolution with 512 shadow maps) and anisotropic filtering. And you don't have the big zbias and slopescale parameters to tweak to solve the z-fighting. The problem on the other hand is the need for 2 channels (preferable floating point), so it wastes more video memory (64 bit render targets), and you can't use the fast z rendering, since your not using depth buffers anymore .. But making your code work for VSM and PCF is a simpl modifications, so it's easy to compare the 2.

Regards,
Kenzo

Share this post


Link to post
Share on other sites
wolf    852
Quote:
Okay, so one other detail I accidentally left out, was that when constructing the light's "view" matrix prior to transforming the 8 corners of each frutum into light space -- that view matrix is "virtually" positioned at the centroid of each frustum. The bottom line is you have to pick some sort of starting reference point position to transform the frustum corners into the light's view space.

With that info you can use the max/min x/y values to construct your max/min extents for your orthographic projection and you can use the max/min z-values to compute what your far clip plane distance will need to be. Like I said before, you'll likely want to back up your near clip plane some arbitrary distance so that you're certain to catch shadow casting objects that aren't necessarily IN the camera's viewing frustum, but ARE between it and the light source and casting shadows into the viewing frustum.

I will check my code more thoroughly and get back to you and describe how I do it ... I just do not have access to the source currently.


Quote:
The good thing with VSMs are the blurring (which makes it cheap on 1600 x 1200 resolution with 512 shadow maps) and anisotropic filtering. And you don't have the big zbias and slopescale parameters to tweak to solve the z-fighting.

Do you have that running in a game like environment? Any problems with light bleeding? I wonder how much the light bleeding problem is showing up ...

Other than this: I wonder if Figure 3, 4 and 5 show the same problem.

Share this post


Link to post
Share on other sites
Brian Lawson    147
Quote:
Original post by Guoshima
You can off course project it onto the object, but then you get the nasty shadow overlapping problem ...


I literally just fixed this problem five minutes ago. The way I handle shadows is I accumulate ALL shadows into an offscreen shadow buffer the size of the frame buffer. I render projected self-shadows with batched multiplicative passes after I've done all generalized envornmental shadowing. Of course, for the past several months the shadow overlapping problem has been bugging the heck out of me. But, there is actually an easy solution to it.

Once you've got all of your shadows in the shadow buffer, you can run a pass that takes max( ShadowBufferPixel, fShadowIntensity ) and this will filter out the over dark regions that resulted from the multiplicative projected self-shadows. It works perfectly -- I just tested it. :)

Stencil shadows were not even an option for me as I have to support all kinds of alpha tested geometry on both our environment objects and our characters. Not to mention, stencil shadows chew up too much fill-rate.

Share this post


Link to post
Share on other sites
Light bleeding is, IMO, prohibitive in the current VSM algorithms.

There are however plenty of ideas for solving this (alluded to in forums here on Gamedev) so I wouldn't say it's a dead end - in fact I think it's a very promising research direction.

Share this post


Link to post
Share on other sites
Guoshima    204
Quote:

I literally just fixed this problem five minutes ago. The way I handle shadows is I accumulate ALL shadows into an offscreen shadow buffer the size of the frame buffer. I render projected self-shadows with batched multiplicative passes after I've done all generalized envornmental shadowing. Of course, for the past several months the shadow overlapping problem has been bugging the heck out of me. But, there is actually an easy solution to it.

Once you've got all of your shadows in the shadow buffer, you can run a pass that takes max( ShadowBufferPixel, fShadowIntensity ) and this will filter out the over dark regions that resulted from the multiplicative projected self-shadows. It works perfectly -- I just tested it. :)


That's actually quite a good idea. The only problem is that you need an extra render pass on all your geometries, for only the shadows. This can increase the drawcall amount quite a bit. But deferred shading can help here of course quite nicely then. And you can blur the texture also then (allthough that you migh get haloing effects).

If I get your algorithm correctly, you perform the following.
- divide frustum into different regions
- render shadow map of region, and imm. render the shadow result into an off screen buffer
- render next shadow map with same texture, and add to the current tmp buffer
- add the projected shadows onto this
(- blur the tmp texture)
- max out the shadow contribution (can be done together with blur pass)
- render scene using tmp texture

Seems like a nice approuch, and you don't have to wast to much video memory.

Quote:

Do you have that running in a game like environment? Any problems with light bleeding? I wonder how much the light bleeding problem is showing up ...


yip I have, and it works fine actually. With indoor spotlight I can have sometimes some light bleeding, but with enough radiosity lightmaps in the scene, you don't really notice it (if you would make a Doom kind of game you probably would). With the outdoor environments I don't really have the problem when I combine it with CSM. With LiSPSM the bleeding was really obvious, because of all the depth data into a single texture. The best thing to do is simply try and add it to your current implementation. It's very easy and you can see the result yourself. Make sure you put your depth value between -1 and 1 on floating point targets. Really makes a big improvement.

Regards,
Kenzo


Share this post


Link to post
Share on other sites
wolf    852
Quote:
- render shadow map of region, and imm. render the shadow result into an off screen buffer
- render next shadow map with same texture, and add to the current tmp buffer
- add the projected shadows onto this
(- blur the tmp texture)
- max out the shadow contribution (can be done together with blur pass)
I use a 2D screenspace texture here. So I alpha blend the depth results into a 2D screenspace texture and apply this texture to all the objects in the scene.
This technique uses the texture cache a bit better, which is important on some platforms ....

Quote:
Hey wolf did you get my email?
I do not think so. When should I received it ...

Share this post


Link to post
Share on other sites
MARS_999    1627
Quote:
Original post by wolf
Quote:
- render shadow map of region, and imm. render the shadow result into an off screen buffer
- render next shadow map with same texture, and add to the current tmp buffer
- add the projected shadows onto this
(- blur the tmp texture)
- max out the shadow contribution (can be done together with blur pass)
I use a 2D screenspace texture here. So I alpha blend the depth results into a 2D screenspace texture and apply this texture to all the objects in the scene.
This technique uses the texture cache a bit better, which is important on some platforms ....

Quote:
Hey wolf did you get my email?
I do not think so. When should I received it ...


I emailed you a few days ago? Your contact info on the gamedev.net listing?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this