rendering: improve main light shadow receiver filtering

This commit is contained in:
2026-04-13 03:14:06 +08:00
parent 95edf0435f
commit adb6fe4659
3 changed files with 669 additions and 19 deletions

View File

@@ -93,6 +93,49 @@ Shader "Builtin Forward Lit"
return output;
}
float SampleShadowVisibility(float2 sampleUv, float receiverDepth)
{
if (sampleUv.x < 0.0f || sampleUv.x > 1.0f ||
sampleUv.y < 0.0f || sampleUv.y > 1.0f) {
return 1.0f;
}
const float shadowDepth = ShadowMapTexture.Sample(ShadowMapSampler, sampleUv).r;
return receiverDepth <= shadowDepth ? 1.0f : 0.0f;
}
float ResolveShadowPcfAxisWeight(int offset)
{
const int absoluteOffset = abs(offset);
if (absoluteOffset == 0) {
return 6.0f;
}
if (absoluteOffset == 1) {
return 4.0f;
}
return 1.0f;
}
float ComputeShadowPcfVisibility(float2 shadowUv, float receiverDepth, float2 shadowTexelSize)
{
float weightedVisibility = 0.0f;
float weightSum = 0.0f;
[unroll]
for (int offsetY = -2; offsetY <= 2; ++offsetY) {
const float weightY = ResolveShadowPcfAxisWeight(offsetY);
[unroll]
for (int offsetX = -2; offsetX <= 2; ++offsetX) {
const float weight = weightY * ResolveShadowPcfAxisWeight(offsetX);
const float2 sampleUv =
shadowUv + float2((float)offsetX, (float)offsetY) * shadowTexelSize;
weightedVisibility += SampleShadowVisibility(sampleUv, receiverDepth) * weight;
weightSum += weight;
}
}
return weightSum > 0.0f ? weightedVisibility / weightSum : 1.0f;
}
float ComputeShadowAttenuation(float3 positionWS, float3 normalWS, float3 lightDirectionWS)
{
#ifndef XC_MAIN_LIGHT_SHADOWS
@@ -136,25 +179,10 @@ Shader "Builtin Forward Lit"
const float receiverDepth = shadowNdc.z - gShadowSampling.receiverDepthBias;
#endif
const float2 shadowTexelSize = gShadowMapMetrics.inverseMapSize;
float visibility = 0.0f;
[unroll]
for (int offsetY = -1; offsetY <= 1; ++offsetY) {
[unroll]
for (int offsetX = -1; offsetX <= 1; ++offsetX) {
const float2 sampleUv =
shadowUv + float2((float)offsetX, (float)offsetY) * shadowTexelSize;
if (sampleUv.x < 0.0f || sampleUv.x > 1.0f ||
sampleUv.y < 0.0f || sampleUv.y > 1.0f) {
visibility += 1.0f;
continue;
}
const float shadowDepth = ShadowMapTexture.Sample(ShadowMapSampler, sampleUv).r;
visibility += receiverDepth <= shadowDepth ? 1.0f : 0.0f;
}
}
visibility *= (1.0f / 9.0f);
const float visibility = ComputeShadowPcfVisibility(
shadowUv,
receiverDepth,
shadowTexelSize);
const float shadowStrength = saturate(gShadowSampling.shadowStrength);
return lerp(1.0f - shadowStrength, 1.0f, visibility);
#endif