Advertisement

Why snap the stabilized cascade shadow mapping sphere radius using 16?

Started by February 29, 2024 10:23 PM
2 comments, last by Alundra 9 months, 3 weeks ago

Hi!
I seen long time ago this specific line:

sphereRadius = std::ceil(sphereRadius * 16.0f) / 16.0f;

in: https://github.com/TheRealMJP/Shadows/blob/master/Shadows/MeshRenderer.cpp

Why MJP is snaping to 16?
Actually he is snaping on the next 16, not using floor.
Thanks!

It's probably a fudge factor since MJP neglects to calculate the actual texels-per-meter resolution. I guess 16 is “enough” in some system of units.

Here is how to do it exactly:

const Float32 unitsPerTexel = (2.0f*frustumSphereRadius) / Float32(shadowMapSize);

// Round the AABB center to the nearest texel and transform to world space.
const SIMDReal4 lightSpaceCenter = unitsPerTexel * math::floor( lightSpaceAABB.getCenter()/unitsPerTexel + 0.5f );
const SIMDReal4 worldSpaceCenter = lightBasis * lightSpaceCenter;

// Remove center offset from the AABB.
lightSpaceAABB -= lightSpaceCenter;

// Round the AABB to the nearest texel, including Z coordinate.
lightSpaceAABB.min = unitsPerTexel * math::floor( lightSpaceAABB.min/unitsPerTexel + 0.5f );
lightSpaceAABB.max = unitsPerTexel * math::floor( lightSpaceAABB.max/unitsPerTexel + 0.5f );
Advertisement

OK I see, thanks, because it was a question since a while and I wondered if there was a real explanation.
Thanks for the code about it! And thanks for the explanation that this snap is not necessary if you stabilize in texel space properly.
I personally use this code to stabilize the shadow projection, 2048 is the shadow map resolution:

// Stabilize the cascade by rounding the matrix determining the fractional offset in texel space.
const Vector4 origin = m_cascadeViewProjArray[i].Transform(Vector4(0.0f, 0.0f, 0.0f, 1.0f));
const float scaledOriginX = origin.m_x * (2048.0f / 2.0f);
const float scaledOriginY = origin.m_y * (2048.0f / 2.0f);
const float roundedScaledOriginX = static_cast<float>(Math::Round(scaledOriginX));
const float roundedScaledOriginY = static_cast<float>(Math::Round(scaledOriginY));
const float roundOffsetX = roundedScaledOriginX - scaledOriginX;
const float roundOffsetY = roundedScaledOriginY - scaledOriginY;
const float scaledRoundOffsetX = roundOffsetX * (2.0f / 2048.0f);
const float scaledRoundOffsetY = roundOffsetY * (2.0f / 2048.0f);
m_cascadeProjArray[i].m_values[0][3] += scaledRoundOffsetX;
m_cascadeProjArray[i].m_values[1][3] += scaledRoundOffsetY;

This topic is closed to new replies.

Advertisement