Cascaded or parallel-split shadow maps Bounding Box slice selection

Started by
19 comments, last by B_old 14 years, 11 months ago
Fair enough answer I guess. Lets see what amazon has to offer...
Advertisement
I read these articles and want to be sure that we was talking about same things. Tryed aproximate solution from ShaderX 7 article for shadows stabilization, works great, I really like it, very simple but so effective.
Than there was a solution proposed for cases when the same point is rendered into several split shadow maps and we choose the best one. But I have impression that Johan Andersson on GDC was expaining a better approach on split's shadow maps utilization, what he called "Bounding Box slice selection" or this was just a fix for cases when point is in several shadows maps at the same time?
Stupid me, next slide shows actuall code of this Bounding Box slice selection approach ))) Now I understand it better - we check calculated shadow map UVs for every point: if uv is proper (0..1) than point is in this slice, if point have proper UV's in more than one slice, we choose closest one.
Just a question; how is the lack of shimmer with movement solved?
@Matt Aufderheide
Aproximate solution described in ShaderX 7 4.1, is improved version of technique described in ShaderX 6 Stable Rendering of CSM, it utilizes shadow map space much better. At the same time shadow will be stable to some degree of camera movement or rotation, so there will be a point where it will change, but this is not happening every frame, in my scene and constants suggested in book I don't see any shadow map movement when camera rotates as well as moves a bit, it changes when you move further but it's hard to notice because of the actuall movement, maybe my camera is running too fast.

I've implemented split selection scheme similar to described by Johan Andersson: first, check if current point can be inside each split (this is done by checking UV's that would be used to sample shadow maps in every split, simple 0..1 check), if you have more than one proper split than sample closest one to camera. This is comparison with regular by depth selection of split:
Parallel-split shadow maps Split selection methods
I'm not using texture arrays or atlas, just three separate shadow maps for three splits. This is code for selecting best split:
// "focused" is a {light view croped projection matrix}float4	toSunPos1 = mul(float4(pixelWorldPos, 1), focused1); float4	toSunPos2 = mul(float4(pixelWorldPos, 1), focused2);float4	toSunPos3 = mul(float4(pixelWorldPos, 1), focused3);// pixel's shadow map sampling coordinates for each splitfloat3	shadowCoord1 = getShadowCoord(toSunPos1);float3	shadowCoord2 = getShadowCoord(toSunPos2);float3	shadowCoord3 = getShadowCoord(toSunPos3);//check that UV's are in 0..1 range, don't forget to check XYZ and not only XY (UV)bool	s1 = all(abs(shadowCoord1 - 0.5f) < 0.5f);bool	s2 = all(abs(shadowCoord2 - 0.5f) < 0.5f);bool	s3 = all(abs(shadowCoord3 - 0.5f) < 0.5f);if(s1){	  ... sample shadow map of first split ...}else if(s2){	  ... sample shadow map of second split ...}else if(s3){  ... sample shadow map of third split ...}


This is not optimal way for sure and it uses branching, so only SM3.0.

[Edited by - Viik on May 8, 2009 3:33:28 PM]
Hi Viik, thanks for the code you posted. I tried to apply it to my shadow maps and it almost works. :) That is, I have situations were it fails.

Should this work regardless of the way I generate my shadow map? I am under the impression, that I sometimes choose the closer split although it doesn't contain the shadow data I am looking for.

Here is what I do:
//This is just to decide between the first or second split!float4 pos0 = mul(float4(viewPos.xyz, 1.0f), g_shadowTransforms[0]);float4 pos1 = mul(float4(viewPos.xyz, 1.0f), g_shadowTransforms[1]);		float3 shadowProj0 = pos0.xyz / pos0.w;float3 shadowProj1 = pos1.xyz / pos1.w;			//I use an atlas with 4 shadowmaps in one texture, so the first shadowmap should be between 0 and 0.5 for uv.if (shadowProj0.x > 0.f && shadowProj0.x < 0.5f&&  shadowProj0.y > 0.f && shadowProj0.y < 0.5f&&  shadowProj0.z >= 0.f && shadowProj0.z < 1.0f){    //sample the first split}else {    //sample the second split}

Can you so a mistake in the code? Maybe I have to generate the map in a special way though...

EDIT:
I believe I have to slightly adjust the way I generate shadowmaps. When I render my objects into the shadowmap I cull those objects that don't intersect the volume, which the split-section of the camerafrustum extended towards the light makes up (I believe you know what I mean). This works perfectly well with paralles splits. If I use the bounding box shader code though, this can be a problem.
Now I need to figure out another way to cull objects when generating the shadow maps. Not really sure, what to do there though.

[Edited by - B_old on May 12, 2009 9:25:58 AM]
From vector name I would say that you transform pixel view position into shadow map space instead of pixel world position:
float4 pos0 = mul(float4(viewPos.xyz, 1.0f), g_shadowTransforms[0]);

This approach is used when your split shadow maps overlap, so objects that belong to overlap section would not be culled and will be rendered into both shadow maps. Just check what you see in each split.

Another thing, are you sure that:
float3 shadowProj0 = pos0.xyz / pos0.w;
float3 shadowProj1 = pos1.xyz / pos1.w;
is enought for you to get proper shadow map space coordinates? As in my case
getShadowCoord() is more complex, as I need to move coordinates to 0..1 range and invert Y direction:
float3	getShadowCoord(float4 postAtLight){  float3 shadowCoord = (0.5 * postAtLight.xyz / postAtLight.w) + float3( 0.5, 0.5, 0.5 );   shadowCoord.y = 1.0f - shadowCoord.y;   return shadowCoord;}
Quote:Original post by Viik
From vector name I would say that you transform pixel view position into shadow map space instead of pixel world position:
float4 pos0 = mul(float4(viewPos.xyz, 1.0f), g_shadowTransforms[0]);

Indeed, but we both end up with the pixel position in lightspace. I hope.
Quote:Original post by Viik
This approach is used when your split shadow maps overlap, so objects that belong to overlap section would not be culled and will be rendered into both shadow maps. Just check what you see in each split.

I don't understand. What approach?

Quote:Original post by Viik
Another thing, are you sure that:
float3 shadowProj0 = pos0.xyz / pos0.w;
float3 shadowProj1 = pos1.xyz / pos1.w;
is enought for you to get proper shadow map space coordinates? As in my case
getShadowCoord() is more complex, as I need to move coordinates to 0..1 range and invert Y direction:
*** Source Snippet Removed ***

Yes I am sure, my coordinates already are in the correct range. The matrix g_shadowTransform does all this in fact.

Actually I can get it to work. The biggest problem I have now is to determine which objects exactly I have to draw.
Thanks for the quick reply.
Quote:I don't understand. What approach?

Approach of choosing split not by view space depth, but by spheres or split bounding box.

Btw, I remember that I had a bug like you described when in first implementation I didn't checked Z value of calculated texture coordinates.

This topic is closed to new replies.

Advertisement