Scaled slope bias and transparent shadows fixes

This commit is contained in:
2026-10-31 01:10:21 -07:00
parent 29f0765864
commit f45ad72056
15 changed files with 126 additions and 48 deletions

View File

@ -595,3 +595,4 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
#endif
#endif

View File

@ -24,7 +24,7 @@ uniform vec2 smSizeUniform;
#ifdef _ShadowMapAtlas
uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
#if defined(_Clusters) && defined(_Spot) && defined(_ShadowMap)
#if defined(_Clusters) && (defined(_Spot) || defined(_LTC)) && defined(_ShadowMap)
uniform vec4 tileBoundsSpotArray[maxLightsCluster];
#endif
vec4 tileBounds = vec4(0.0, 0.0, 1.0, 1.0);
@ -180,7 +180,7 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube,
#endif
) {
const float s = shadowmapCubePcfSize; // TODO: incorrect...
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
float compare = lpToDepth(lp, lightProj) - bias * 1.5 - 0.0001;
ml = ml + n * bias * 20;
#ifdef _InvY
ml.y = -ml.y;
@ -321,7 +321,7 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
, const bool transparent
#endif
) {
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
const float compare = lpToDepth(lp, lightProj) - bias * 1.5 - 0.0001;
ml = ml + n * bias * 20;
int faceIndex = 0;
const int lightIndex = index * 6;
@ -408,10 +408,16 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
if (transparent == false) {
vec3 transResult = vec3(0.0);
vec2 tileMin = pointLightTile.xy;
vec2 tileMax = pointLightTile.xy + pointLightTile.z;
#ifdef _FlipY
tileMin.y = 1.0 - tileMax.y;
tileMax.y = 1.0 - pointLightTile.y;
#endif
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
vec4 smt = texture(shadowMapTransparent,
clamp(uvtiled + vec2(x, y) / smSize, 0.0, 1.0));
clamp(uvtiled + vec2(x, y) / smSize, tileMin, tileMax));
transResult += (smt.a < compare) ? smt.rgb : vec3(1.0);
}
}
@ -437,15 +443,15 @@ vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapAtlas
// use tile PCF
#ifdef _SMSizeUniform
vec2 smSizeAtlas = smSizeUniform * (tileBounds.zw - tileBounds.xy);
vec2 smSizeAtlas = smSizeUniform;
#else
vec2 smSizeAtlas = shadowmapSize * (tileBounds.zw - tileBounds.xy);
vec2 smSizeAtlas = shadowmapSize;
#endif
return PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSizeAtlas,
lPos.xy, lPos.z - shadowsBias - 0.0001, smSizeAtlas,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
@ -462,7 +468,7 @@ vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
lPos.xy, lPos.z - shadowsBias - 0.0001, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
@ -499,11 +505,22 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
// ..
}
float worldPerTexel(const mat4 LWVP, const vec2 smSize) {
return max(1.0 / abs(LWVP[0][0]), 1.0 / abs(LWVP[1][1])) / smSize.x;
}
float nlSlopeBias(const vec3 n, const mat4 LWVP, const float wpt) {
vec3 ldir = normalize(vec3(LWVP[0][2], LWVP[1][2], LWVP[2][2]));
float ndotl = max(abs(dot(n, ldir)), 0.05);
float tanTheta = min(sqrt(1.0 - ndotl * ndotl) / ndotl, 1.5);
return wpt * tanTheta * abs(LWVP[2][2]);
}
vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 eye, const vec3 p, const float shadowsBias
const vec3 eye, const vec3 p, const vec3 n, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
@ -522,8 +539,10 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
int casi;
int casIndex;
mat4 LWVP = getCascadeMat(d, casi, casIndex);
vec4 lPos = LWVP * vec4(p, 1.0);
float wpt = worldPerTexel(LWVP, smSize);
vec4 lPos = LWVP * vec4(p + n * 0.5 * wpt, 1.0);
lPos.xyz /= lPos.w;
float scaledBias = shadowsBias + nlSlopeBias(n, LWVP, wpt);
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSunArray[casi];
@ -536,7 +555,7 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize,
lPos.xy, lPos.z - scaledBias, smSize,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
@ -547,7 +566,7 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
lPos.xy, lPos.z - scaledBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
@ -569,8 +588,10 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
casData[casIndex2 + 2],
casData[casIndex2 + 3]);
vec4 lPos2 = LWVP2 * vec4(p, 1.0);
float wpt2 = worldPerTexel(LWVP2, smSize);
vec4 lPos2 = LWVP2 * vec4(p + n * 0.5 * wpt2, 1.0);
lPos2.xyz /= lPos2.w;
float scaledBias2 = shadowsBias + nlSlopeBias(n, LWVP2, wpt2);
vec3 visibility2 = vec3(1.0);
// use lPos2 coordinates for second cascade, not lPos
#ifdef _ShadowMapAtlas
@ -582,7 +603,7 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize,
lPos2.xy, lPos2.z - scaledBias2, smSize,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
@ -593,7 +614,7 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize
lPos2.xy, lPos2.z - scaledBias2, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
@ -612,4 +633,4 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0);
}
#endif
#endif
#endif