Skip to content

Commit

Permalink
[Port] [2022.3] [HDRP] Fix NaNs and clamping in PCSS
Browse files Browse the repository at this point in the history
Partial fix for [UUM-31577](https://jira.unity3d.com/browse/UUM-31577) that eliminates a class of artifacts from High-Quality (PCSS) shadows. The fix is applicable to point and spot lights.

Fix for [UUM-62513](https://jira.unity3d.com/browse/UUM-62513) that eliminates a class of artifacts from High-Quality (PCSS) shadows.
  • Loading branch information
mseonkim-unity authored and Evergreen committed Aug 15, 2024
1 parent cd0e347 commit 943c743
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ real PenumbraSizeDirectional(real Reciever, real Blocker, real rangeScale)
return abs(Reciever - Blocker) * rangeScale;
}

bool BlockerSearch(inout real averageBlockerDepth, inout real numBlockers, real lightArea, real3 coord, real2 sampleJitter, Texture2D shadowMap, SamplerState pointSampler, int sampleCount)
bool BlockerSearch(inout real averageBlockerDepth, inout real numBlockers, real lightArea, real3 coord, real UMin, real UMax, real VMin, real VMax, real2 sampleJitter, Texture2D shadowMap, SamplerState pointSampler, int sampleCount)
{
real blockerSum = 0.0;
real sampleCountInverse = rcp((real)sampleCount);
Expand All @@ -116,32 +116,42 @@ bool BlockerSearch(inout real averageBlockerDepth, inout real numBlockers, real
offset = real2(offset.x * sampleJitter.y + offset.y * sampleJitter.x,
offset.x * -sampleJitter.x + offset.y * sampleJitter.y);

real shadowMapDepth = SAMPLE_TEXTURE2D_LOD(shadowMap, pointSampler, coord.xy + offset, 0.0).x;
real U = coord.x + offset.x;
real V = coord.y + offset.y;

if (COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, coord.z))
//NOTE: We must clamp the sampling within the bounds of the shadow atlas.
// Overfiltering will leak results from other shadow lights.
if (U < UMin || U > UMax || V < VMin || V > VMax)
{
blockerSum += shadowMapDepth;
numBlockers += 1.0;
// Discard the sample (it is located outside the shadow map, and it may correspond to another cube map face).
}
else
{
real shadowMapDepth = SAMPLE_TEXTURE2D_LOD(shadowMap, pointSampler, float2(U, V), 0.0).x;

if (COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, coord.z))
{
blockerSum += shadowMapDepth;
numBlockers += 1.0;
}
}
}
averageBlockerDepth = blockerSum / numBlockers;

return numBlockers >= 1;
// Return the depth value of the far plane if none of the samples are valid
averageBlockerDepth = (numBlockers > 0) ? (blockerSum / numBlockers) : UNITY_RAW_FAR_CLIP_VALUE;

return numBlockers > 0;
}

real PCSS(real3 coord, real filterRadius, real2 scale, real2 offset, real2 sampleJitter, Texture2D shadowMap, SamplerComparisonState compSampler, int sampleCount)
real PCSS(real3 coord, real UMin, real UMax, real VMin, real VMax, real filterRadius, real2 sampleJitter, Texture2D shadowMap, SamplerComparisonState compSampler, int sampleCount)
{
real UMin = offset.x;
real UMax = offset.x + scale.x;

real VMin = offset.y;
real VMax = offset.y + scale.y;

real sum = 0.0;
real sampleCountInverse = rcp((real)sampleCount);
real sampleCountBias = 0.5 * sampleCountInverse;
real ditherRotation = sampleJitter.x;

real numValidSamples = 0;

for (int i = 0; i < sampleCount && i < DISK_SAMPLE_COUNT; ++i)
{
real2 offset = ComputeFibonacciSpiralDiskSample(i, filterRadius, sampleCountInverse, sampleCountBias);
Expand All @@ -153,16 +163,19 @@ real PCSS(real3 coord, real filterRadius, real2 scale, real2 offset, real2 sampl

//NOTE: We must clamp the sampling within the bounds of the shadow atlas.
// Overfiltering will leak results from other shadow lights.
//TODO: Investigate moving this to blocker search.
// coord.xy = clamp(coord.xy, float2(UMin, VMin), float2(UMax, VMax));

if (U <= UMin || U >= UMax || V <= VMin || V >= VMax)
sum += SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(coord.xy, coord.z)).r;
if (U < UMin || U > UMax || V < VMin || V > VMax)
{
// Discard the sample (it is located outside the shadow map, and it may correspond to another cube map face).
}
else
{
sum += SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(U, V, coord.z)).r;
numValidSamples += 1.0;
}
}

return sum / sampleCount;
// Return the unoccluded (unshadowed) value if none of the samples are valid
return (numValidSamples > 0) ? (sum / numValidSamples) : 1.0;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,18 @@ float SampleShadow_PCSS(float3 tcs, float2 posSS, float2 scale, float2 offset, f
float shadowMapRes = scale.x * shadowAtlasInfo.x; // atlas is square
float resIndepenentMaxSoftness = 0.04 * (shadowMapRes / 512);

real halfTexelOffset = 0.5 * shadowAtlasInfo.y;

real UMin = offset.x + halfTexelOffset;
real UMax = offset.x + scale.x - halfTexelOffset;

real VMin = offset.y + halfTexelOffset;
real VMax = offset.y + scale.y - halfTexelOffset;

//1) Blocker Search
float averageBlockerDepth = 0.0;
float numBlockers = 0.0;
bool blockerFound = BlockerSearch(averageBlockerDepth, numBlockers, min((shadowSoftness + 0.000001), resIndepenentMaxSoftness) * atlasResFactor, tcs, sampleJitter, tex, samp, blockerSampleCount);
bool blockerFound = BlockerSearch(averageBlockerDepth, numBlockers, min((shadowSoftness + 0.000001), resIndepenentMaxSoftness) * atlasResFactor, tcs, UMin, UMax, VMin, VMax, sampleJitter, tex, samp, blockerSampleCount);

// We scale the softness also based on the distance between the occluder if we assume that the light is a sphere source.
// Also, we don't bother if the blocker has not been found.
Expand All @@ -336,7 +344,7 @@ float SampleShadow_PCSS(float3 tcs, float2 posSS, float2 scale, float2 offset, f

//3) Filter
// Note: we can't early out of the function if blockers are not found since Vulkan triggers a warning otherwise. Hence, we check for blockerFound here.
return PCSS(tcs, filterSize, scale, offset, sampleJitter, tex, compSamp, filterSampleCount);
return PCSS(tcs, UMin, UMax, VMin, VMax, filterSize, sampleJitter, tex, compSamp, filterSampleCount);
}


Expand Down

0 comments on commit 943c743

Please sign in to comment.