Sign in to follow this  
skyemaidstone

Self Shadowing Flickering

Recommended Posts

Hi guys,

After all your great help last time I've made a lot of progress but I've reached a problem I can't seem to solve and I suspect someone on here will be able to point me in the right direction with ease.

https://youtu.be/0PLK72HZxo8 (please excuse the video quality but it still shows the problem very well)

Saves me waffling for ages anyway. The rock in front of the player has an annoying flicking self shadowing problem.

The debug boxes along the top show the color map, normal, lighting,depth and the 3 cascades of the shadow map.

It all looks pretty nice for most of the time but some models just have that problem. I have a slight wipe between the cascades where the quality changes but i'll accept that for the minute. It flickers in the medium quality cascade too anyway (not the far one but then by then its hard to tell since its so far away)

Things i've tried:

  • Increasing my depth bias a bit in the shader (was set at 0.00035) but it starts to bad and the player starts to "peter pan"
  • Creating a simpler rock model but it has the same problem and I wan't to be able to use complex models anyway. Besides the player seems to self shadow fine but I guess I'm not zooming in and out.
  • I tried reducing the farclip of my camera down to something really small like 500 (near at 5) in case it was some depth precision problem. Doesn't seem to be, still flickers but maybe a red herring since I thought that was the most likely

Any ideas would be greatly appreciated..

 

 

Share this post


Link to post
Share on other sites

Thanks for the link although I'm not really 100% certain what the poster is saying. How would I set the bias outside my shader? For each cascade of my CSM I set a different bias. Should I be calculating the depth bias in the part of the codes that renders the models to the shadow map (ie just stores their depth) so that the bias is calculated at at per vertex level for each model?

The line of code that uses the normal + an offset doesn't seem to improve the situation, I just get weird artifacts then.

It's hard to solve this without even knowning exactly what my problem is. I thought It might be a depth precision problem or a cascade stabilisation problem but it seems it need to calculate the slope depth bias? Is that what this problem looks like?

This link seems to indicate that you're right and I do need to apply a depth bias on a per vertex basis using slope-scaled depth bias. 

Just not sure exactly how to do it. 

Edited by skyemaidstone

Share this post


Link to post
Share on other sites
For each cascade of my CSM I set a different bias

I always used one bias for the whole shadow mapping and I never seen multiple bias used somewhere. 

About the issue, you have often shadow issue on the slope and it's what slope-scaled depth bias can improve.
The link shows nicely that multiple method exists but yes, we are far to have perfect solution for shadows :(
I think the best is to play with all methods until have one solution which gives an acceptable visual for the rendering.
Then also maybe implement multiple method if different kind of scene is used and needs different tricks.

Edited by Alundra

Share this post


Link to post
Share on other sites

I've tried adding some normal bias which does improve it a bit but if i add too much the self shadowing starts to look disconnected as you'd expect.

I'm starting to think this is more a problem of stabilizing my cascades (i'm not doing that). I've read about making the shadow camera only move in texels but I tried that (or at least i think i did) and it made no difference or maybe i need to switch to that spheres method i've read about for making the shadowlightprojection . I could never get that to work properly though.

Shadows are such a pain.

Share this post


Link to post
Share on other sites

The problem using the bounding box is the change of projection which cause artefacts, using a stable cascade based on bounding sphere you got this problem removed.
You got also a problem called "the shimmering edge effect", this problem is caused by the move of the camera, to remove it you have to round to pixel size increments.

Share this post


Link to post
Share on other sites

I ended up just making a different depth and normal bias as a setting per game object. bit of a simple solution but it works a treat and no performance hit really. I still have a slight shimmer/jiggle but it's acceptable. I'd love it to be perfect though but if someone is staring that closely at my shadows then I must have made a very boring game.

I couldn't seem to figure out how to get an orthographic projection for my cascade from a sphere. Out of interest could anyone provide any code (pseudo code will do)?

Currently I make a frustrum for my cascade with:

                   lightsView = Matrix.Identity;
                    lightsViewProjectionMatrix = Matrix.Identity;


                    Vector3 sunlightdirection = new Vector3(0.21f, 0.11f, -0.5f);
                    ShadowLightPos = frustumCentroid + (sunlightdirection * 10);
                    ShadowLookAt = frustumCentroid;
                    ShadowLightView = Matrix.CreateLookAt(ShadowLightPos, ShadowLookAt, new Vector3(0, 1, 0));

                    Vector3.Transform(frustumCornersWS, ref ShadowLightView, frustumCornersLS);
                    Vector3 mins = frustumCornersLS[0];
                    Vector3 maxes = frustumCornersLS[0];
                    for (int i = 0; i < 8; i++)
                    {
                        if (frustumCornersLS[i].X > maxes.X)
                            maxes.X = frustumCornersLS[i].X;
                        else if (frustumCornersLS[i].X < mins.X)
                            mins.X = frustumCornersLS[i].X;
                        if (frustumCornersLS[i].Y > maxes.Y)
                            maxes.Y = frustumCornersLS[i].Y;
                        else if (frustumCornersLS[i].Y < mins.Y)
                            mins.Y = frustumCornersLS[i].Y;
                        if (frustumCornersLS[i].Z > maxes.Z)
                            maxes.Z = frustumCornersLS[i].Z;
                        else if (frustumCornersLS[i].Z < mins.Z)
                            mins.Z = frustumCornersLS[i].Z;
                    }

Then just make an Ortho projection for my cascade slice with:

 ShadowLightProjection = Matrix.CreateOrthographicOffCenter(mins.X, maxes.X, mins.Y, maxes.Y, -maxes.Z - 500f, -mins.Z);
 lightsView = Matrix.CreateLookAt(ShadowLightPos, ShadowLookAt, new Vector3(0, 1, 0));
 lightsViewProjectionMatrix = lightsView * ShadowLightProjection;

Any help with how to do that using a sphere would be greatly appreciated (and possibly rounding it to a shadowmap texel since I either didn't do that right or it made no difference).

Thanks.

 

Share this post


Link to post
Share on other sites

The frustum can be represented by a triangle which cover the whole visible scene from the actual camera.
You split this frustum and for each split you compute the orthographic projection.
To have stable cascade you can compute the radius and set this radius on width and height of the orthographic projection.
If you use the SDSM algorithm to find the tighter cascade from the depth buffer, you don't need to use stable cascade, that produces wasted space.
To compute the radius you simply need to use trigonometry because the frustum can be represented by a triangle.
Here the code to compute the radius :

// Tangent values.
float TanFOVX = tan(0.5f * FieldOfViewRadian * AspectRatio);
float TanFOVY = tan(0.5f * FieldOfViewRadian);

// Compute the bounding sphere.
Vector3 Center = CameraPos + CameraForward * (Near + HalfDistance);
CornerPoint = CameraPos + (CameraRight * TanFOVX + CameraUp * TanFOVY + CameraForward) * Far;

Here the code to compute the AABB :

// Scale needed to extract frustum points.
float scaleXInv = 1.0f / cameraProj(1, 1);
float scaleYInv = 1.0f / cameraProj(2, 2);

// Matrix needed to transform frustum corners into light view space.
Matrix4 cameraViewToLightProj = cameraViewInv * lightViewProj;

// Compute corners.
Vector3 corners[8];
float nearX = scaleXInv * nearZ;
float nearY = scaleYInv * nearZ;
corners[0] = Vector3(-nearX,  nearY, nearZ);
corners[1] = Vector3( nearX,  nearY, nearZ);
corners[2] = Vector3(-nearX, -nearY, nearZ);
corners[3] = Vector3( nearX, -nearY, nearZ);
float farX = scaleXInv * farZ;
float farY = scaleYInv * farZ;
corners[4] = Vector3(-farX,  farY, farZ);
corners[5] = Vector3( farX,  farY, farZ);
corners[6] = Vector3(-farX, -farY, farZ);
corners[7] = Vector3( farX, -farY, farZ);

// Compute corners in light space.
Vector3 cornersLightView[8];
for(int i = 0; i < 8; ++i)
  cornersLightView[i] = cameraViewToLightProj.Transform(corners, 1.0f);

// Compute the AABB.
ComputeAABBFromPoints(cornersLightView, 8, outMin, outMax);

This AABB code is not needed if you use the radius, because then the projection is only :

Matrix4 CascadeProjectionMatrix;
const float CascadeDiameter = 2.0f * CascadeBSphere.m_Radius;
CascadeProjectionMatrix.Ortho( CascadeDiameter, CascadeDiameter, -CascadeBSphere.m_Radius, CascadeBSphere.m_Radius );
Edited by Alundra

Share this post


Link to post
Share on other sites

Thanks for your help Alundra. I've rated up your post for trying to help me even though i must admit I don't understand the answer at all.

I'll do some more reading on the subject and maybe i'll understand how to use spheres to make the orthographic projections for my cascade frustum slices.

Thanks :)

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