Jump to content
  • Advertisement
Sign in to follow this  

Cascaded Shadow Maps (choosing level)

This topic is 3160 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
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
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:

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:

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!