Jump to content
  • Advertisement
Sign in to follow this  
dpadam450

Cascaded Shadow Maps (choosing level)

This topic is 3077 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I recently implemented a 2-system CSM. 1 map local, 1 covers the whole scene. My shader uses the basic idea given by an Nvidia whitepaper to use the z-depth to choose what Shadow Map to use. Shader code is something like: if(EYE_Z < 10) use local shadow map else Linear blend from Local to Global from Z = 10, to Z = 20 I.E. z = 10 means 1.0*Local z = 15 means .5*Local +.5*Global z >= 20 means 1.0*global If I put in a total of say 3 or 4 CSM's, I would have to have a bunch of if statements. Is this how everyone is doing it? Should I also put my CSM's into a 3D-texture to make it easier?

Share this post


Link to post
Share on other sites
Advertisement
Er...
I'm not sure about shader implementation, but couldn't you use something like this:

shadow_map_unit = get_unit(EYE_Z);
z_for_comparison = magic_formula(EYE_Z);

The simplest case (but haven't thought about it) is
get_unit: floor(EYE_Z)
magic_formula: EYE_Z-floor(EYE_Z)

I guess you have directional light, so "magic_formula" will be a simple linear interpolation, if you have the starting and end values.

If you have arbitrary values (cascades), then I guess if-else is the simplest/fastest, but if you can express the relation between the cascades with a function (thus the start-end values), you could get the shadow_map_unit and the z_for_comparison directly, using this function (more precisely its inverse)

It's just an idea, maybe you can do something with it (if it makes sense at all)

Share this post


Link to post
Share on other sites
Quote:
Should I also put my CSM's into a 3D-texture to make it easier?
I think that would be actually worse, only relatively small amount of fragments will need to fetch both shadow maps.


We use different approach, it takes into acount not only distance but the area covered by shadow maps as well.

1) First, you project fragment position into first split\cascade shadow map.
float4 fragmentSMPos = mul(float4(fragmentWorldPos.xyz, 1), SM1Matrix);

2) Then you convert fragments coordinates to shadow map texture space and check them:
bool s = all(abs(shadowCoord - 0.5f) < 0.5f); //shadowCoord is the fragmentSMPos, converted to 0..1 texture range

3) If all values of s are true then fragment is definately belongs to first split and you fetch shadow map to calculate shadow term:

if(s){
float sm_depth = tex2D(sm1_sampler, shadowCoord);
....calculate shadow term....
}

4) If one or more s components is false, you get back to step 1 and project fragment into next split shadow map and repeat all steps:

else{
fragmentSMPos = mul(float4(fragmentWorldPos.xyz, 1), SM2Matrix);
.....
}

Dynamic branching won't be an issue as mostly it will occur only on edges of splits\cascades. And if you already found to which cascade fragment belongs branching practically avoids other calculation. In worst case you will check all splits, but this will be true only for most distance fragments.


Adapting this for your case wiil require following:
1) Fetch not one but two shadow maps at the same time for a splits which you want to blend, so that would be one of the steps 3.
2) Use projected fragment posititon (-1..1) or texture coordinates (0..1) used to fetch shadow map, to blend from one shadow term to another.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!