Hi, I am trying to implement stable cascaded shadow maps but I am still getting shadow shimmering.
Here is my code for non-stable CSM (the part where you calculate all the lightviewprojection matrices):
//this function calculates projection frustums for every split and later uses it to get frustum in world space
std::array<DirectX::XMFLOAT4X4, MAX_CASCADES_NUM> projectionMatrices = RecalculateProjectionMatrices(camera);
std::array<DirectX::XMMATRIX, MAX_CASCADES_NUM> lightViewProjectionMatrices;
for (UINT i = 0; i < MAX_CASCADES_NUM; ++i)
{
///frustum in world space
BoundingFrustum frustum(DirectX::XMLoadFloat4x4(&projectionMatrices[i]));
frustum.Transform(frustum, DirectX::XMMatrixInverse(nullptr, camera.View()));
///get frustum corners
std::array<DirectX::XMFLOAT3, frustum.CORNER_COUNT> corners;
frustum.GetCorners(corners.data());
///calculate frustum center and radius using bounding sphere
BoundingSphere frustumSphere;
BoundingSphere::CreateFromFrustum(frustumSphere, frustum);
XMVECTOR frustumCenter = XMLoadFloat3(&frustumSphere.Center);
FLOAT radius = std::ceil(frustumSphere.Radius);
///calculating light view matrix
XMVECTOR lightDir = XMVector3Normalize(XMLoadFloat3(&light.direction));
static const XMVECTOR zero = DirectX::XMVectorSet(0, 0, 0, 1);
XMVECTOR up = camera.Right(); // XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
XMVECTOR lightPos = -lightDistanceFactor * radius * lightDir + frustumCenter;
///NEW view matrix
XMMATRIX V = DirectX::XMMatrixLookAtLH(lightPos, frustumCenter, up);
///transform frustum corners in light view space to calculate AABB for orthographic projection
FLOAT l = std::numeric_limits<float>::max();
FLOAT b = std::numeric_limits<float>::max();
FLOAT n = std::numeric_limits<float>::max();
FLOAT r = std::numeric_limits<float>::min();
FLOAT t = std::numeric_limits<float>::min();
FLOAT f = std::numeric_limits<float>::min();
for (auto& corner : corners)
{
//transform corners into light space
XMStoreFloat3(&corner, DirectX::XMVector3TransformCoord(DirectX::XMLoadFloat3(&corner), V));
l = std::min(l, corner.x);
r = std::max(r, corner.x);
b = std::min(b, corner.y);
t = std::max(t, corner.y);
n = std::min(n, corner.z);
f = std::max(f, corner.z);
}
XMMATRIX P = DirectX::XMMatrixOrthographicOffCenterLH(l, r, b, t, nearFactor*n, farFactor*f);
XMMATRIX lightviewprojection = V * P;
lightViewProjectionMatrices[i] = lightviewprojection;
}
return lightViewProjectionMatrices;
That part works as excepted.
This part should calculate stable CSM lightviewprojection matrices but, while I still get shadows the shimmering doesn't disappear (it actually gets a bit worse):
std::array<DirectX::XMFLOAT4X4, MAX_CASCADES_NUM> projectionMatrices = RecalculateProjectionMatrices(camera);
std::array<DirectX::XMMATRIX, MAX_CASCADES_NUM> lightViewProjectionMatrices;
for (UINT i = 0; i < MAX_CASCADES_NUM; ++i)
{
///frustum in world space
BoundingFrustum frustum(DirectX::XMLoadFloat4x4(&projectionMatrices[i]));
frustum.Transform(frustum, DirectX::XMMatrixInverse(nullptr, camera.View()));
BoundingSphere frustumSphere;
BoundingSphere::CreateFromFrustum(frustumSphere, frustum);
XMVECTOR frustumCenter = XMLoadFloat3(&frustumSphere.Center);
FLOAT radius = std::ceil(frustumSphere.Radius * 16.0f) / 16.0f;
XMVECTOR lightDir = XMVector3Normalize(XMLoadFloat3(&light.direction));
static const XMVECTOR zero = DirectX::XMVectorSet(0, 0, 0, 1);
static const XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
//you can ignore this texel snapping part since the camera rotation also causes shimmering
//taken from altex tardif site
//FLOAT texelsperunit = depthMapSize / (2.0f * radius);
//XMMATRIX lookat = XMMatrixLookAtLH(zero, -lightDir, up);
//lookat = lookat * XMMatrixScaling(texelsperunit, texelsperunit, texelsperunit);
//XMMATRIX inverselookat = XMMatrixInverse(nullptr, lookat);
//frustumCenter = XMVector3TransformCoord(frustumCenter, lookat);
//XMVectorSetX(frustumCenter, floor(XMVectorGetX(frustumCenter)));
//XMVectorSetY(frustumCenter, floor(XMVectorGetY(frustumCenter)));
//frustumCenter = XMVector3TransformCoord(frustumCenter, inverselookat);
XMMATRIX V = DirectX::XMMatrixLookAtLH(frustumCenter, frustumCenter + lightDistanceFactor * radius * lightDir, up);
FLOAT l = -radius;
FLOAT b = -radius;
FLOAT n = -nearFactor * radius;
FLOAT r = radius;
FLOAT t = radius;
FLOAT f = farFactor * radius;
//DirectX::XMFLOAT3 cascadeExtends(2 * radius, 2 * radius, 2 * radius);
///calculating light view matrix
XMMATRIX P = DirectX::XMMatrixOrthographicOffCenterLH(l, r, b, t, n, f);
//this produces shadows (unstable) if this view matrix is used:
//XMVECTOR lightPos = -lightDistanceFactor * radius * lightDir + frustumCenter;
//XMMATRIX V = DirectX::XMMatrixLookAtLH(lightPos, frustumCenter, up);
//auto c = frustumSphere.Center;
//XMStoreFloat3(&c, DirectX::XMVector3TransformCoord(DirectX::XMLoadFloat3(&c), V));
//XMMATRIX P = DirectX::XMMatrixOrthographicOffCenterLH(c.x - radius, c.x + radius,
// c.y - radius, c.y + radius,
// nearFactor*(c.z - radius), farFactor*(c.z + radius));
lightViewProjectionMatrices[i] = V * P;
}
I also can visualize my cascades with RGB color and and display depth maps on the screen if you have some debugging advices.
Thanks in advance.