Skip to main content
gamedev.net
🔒 Locked

CSM texture swimming

Started by Quat 1 reply 1.8k views
Original Post
Quat
Quat
I want to confirm that my understanding of the translation problem that causes flickering at the edges of shadows when the camera moves in CSM is correct. When the camera moves a small amount, the cascade volumes also move. This means that different points in the world are sampled by the shadow map. It is possible that a subtexel movement could cause a point P that was on a shadow edge in frame N to not be in shadow in frame N+1 since (since the points being sampled by the shadow map changed). This would cause a flicker along the edge between frame N and N+1. The solution is to move the cascade view volume in world space units that correspond to texel sizes in the shadow map. In this way, we always sample the same grid of world space points. Is that correct?
-----Quat
B_old
B_old
As far as I understand it, there can be two reason for shadow swimming. One is caused by camera translation and can be reduced like you are describing it. The other one is cause by camera rotation and can be reduced by keeping the shape of the shadow camera frustum equal between frames. I hope that makes some sense for you, but that is how I got rid of the shadow swimming.

Unfortunately, moving objects can still cause the shadow edges to flicker, and I don't know of any real solution to this apart from some kind of anti aliasing.
csisy
csisy
I've read a documentation from DICE: "Shadows Decals: D3D10 techniques from Frostbite" here
and I don't understand where I have to insert the code which is in the 24th page of the doc:


float f = viewSize / shadowMapSize;
Position.x = round(Position.x / f) * f;
Position.y = round(Position.y / f) * f;


I use only one pass now for each light:
- render shadow map with a viewProj matrix which is calculated by AABB's, based on the nvidia's paper:


void Shadow::ComputeMatrices()
{
ComputeFrustumCorners();

view = Matrix::LookAt(Vector3::Zero, light->direction, Vector3::Up);
Vector3 min = Vector3::Max;
Vector3 max = Vector3::Min;

Vector4 transformed; for (int i = 0; i < NUM_CORNERS; i++)
{
transformed = Vector4::Transform(frustumCorners, view);
transformed /= transformed.w;

if (transformed.x < min.x)
min.x = transformed.x;
if (transformed.y < min.y)
min.y = transformed.y;
if (transformed.z < min.z)
min.z = transformed.z;

if (transformed.x > max.x)
max.x = transformed.x;
if (transformed.y > max.y)
max.y = transformed.y;
if (transformed.z > max.z)
max.z = transformed.z;
}

float scaleX = 2.0f / (max.x - min.x);
float scaleY = 2.0f / (max.y - min.y);
float offsetX = -0.5f * (min.x + max.x) * scaleX;
float offsetY = -0.5f * (min.y + max.y) * scaleY; cropMat.m[0][0] = scaleX;

cropMat.m[1][1] = scaleY;
cropMat.m[2][2] = 1.0f;
cropMat.m[3][0] = offsetX;
cropMat.m[3][1] = offsetY;
cropMat.m[3][3] = 1.0f;

proj = Matrix::OrthographicOffCenter(-1, 1, -1, 1, min.z, max.z);
viewProj = view * proj * cropMat;

finalMat = viewProj * textureMat;
}


where texture matrix is


float texOffset = 0.5f + (0.5f / (float)shadowSize);
float bias = 0.003f;
textureMat = Matrix(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
texOffset, texOffset, -bias, 1.0f);


the viewProj is used to render the shadow map:


float4 wPos = mul(float4(InPosition, 1.0f), world);
Position = mul(wPos, viewProj);
Depth = Position.z;


and the finalMat is used to render the shadow:


float4 position;
position.xyz = eyePosition + normalize(EyeRay) * depthText;
position.w = 1.0f;

float4 shadow = mul(position, shadowMat);
shadow.xy /= shadow.w;

//...


So where should I have to insert the correction code?

Thanks
sorry for my bad english

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.