Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5b7a88a
PCSS visibility cone z offset and sampling pattern improvements
robcupisz Mar 30, 2021
eb6a366
Remove shadow softness fitting - it doesn't help anymore
robcupisz Mar 30, 2021
a946f8c
Area lights use PCSS when shadows set to high quality
robcupisz Mar 30, 2021
325c73e
PCSS: improved visibility cone sampling pattern. Fixed atlas- and sha…
robcupisz Apr 19, 2021
aa2784f
Merge branch 'master' into HDRP/soft-shadow-improvements
robcupisz May 7, 2021
c805d08
Merge branch 'master' into HDRP/soft-shadow-improvements
robcupisz May 7, 2021
94d1862
Revert merge mishap
robcupisz May 7, 2021
19bc178
Merge branch 'master' into HDRP/soft-shadow-improvements
robcupisz May 7, 2021
61e5ec7
Merge commit 'f2cccc2e3dfc5a77ca0cd2794c606ae58d6b089e' into HDRP/sof…
robcupisz Jun 2, 2021
ad06657
Merge branch 'master' into HDRP/soft-shadow-improvements
tlaedre Sep 7, 2021
23d1d52
Merge branch 'master' into HDRP/soft-shadow-improvements
robcupisz Nov 8, 2021
0ad33c5
Re-enable the Very High Quality shadow filtering option
robcupisz Nov 8, 2021
1ca3384
Merge branch 'master' into HDRP/soft-shadow-improvements
robcupisz Dec 3, 2021
df72f18
Hook up the minimum blur intensity setting
robcupisz Dec 16, 2021
6dfd38a
Fix issues related to the shadowmap's scale in atlas
robcupisz Dec 31, 2021
ccfe84b
rename
robcupisz Jan 12, 2022
c602a12
Fix the sampling cone being flipped
robcupisz Jan 12, 2022
b0bda2a
Fix issues related to the shadowmap's size and scale in atlas, properly
robcupisz Jan 12, 2022
b0e7f5b
Merge remote-tracking branch 'origin/master' into HDRP/soft-shadow-im…
tlaedre Feb 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1276,10 +1276,18 @@ static void DrawShadowMapAdditionalContent(SerializedHDLight serialized, Editor

if (lightType == HDLightType.Area && serialized.areaLightShape == AreaLightShape.Rectangle)
{
EditorGUILayout.Slider(serialized.evsmExponent, HDAdditionalLightData.k_MinEvsmExponent, HDAdditionalLightData.k_MaxEvsmExponent, s_Styles.evsmExponent);
EditorGUILayout.Slider(serialized.evsmLightLeakBias, HDAdditionalLightData.k_MinEvsmLightLeakBias, HDAdditionalLightData.k_MaxEvsmLightLeakBias, s_Styles.evsmLightLeakBias);
EditorGUILayout.Slider(serialized.evsmVarianceBias, HDAdditionalLightData.k_MinEvsmVarianceBias, HDAdditionalLightData.k_MaxEvsmVarianceBias, s_Styles.evsmVarianceBias);
EditorGUILayout.IntSlider(serialized.evsmBlurPasses, HDAdditionalLightData.k_MinEvsmBlurPasses, HDAdditionalLightData.k_MaxEvsmBlurPasses, s_Styles.evsmAdditionalBlurPasses);
if (HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.shadowFilteringQuality == HDShadowFilteringQuality.VeryHigh)
{
EditorGUILayout.Slider(serialized.slopeBias, 0.0f, 1.0f, s_Styles.slopeBias);
EditorGUILayout.Slider(serialized.normalBias, 0.0f, 5.0f, s_Styles.normalBias);
}
else
{
EditorGUILayout.Slider(serialized.evsmExponent, HDAdditionalLightData.k_MinEvsmExponent, HDAdditionalLightData.k_MaxEvsmExponent, s_Styles.evsmExponent);
EditorGUILayout.Slider(serialized.evsmLightLeakBias, HDAdditionalLightData.k_MinEvsmLightLeakBias, HDAdditionalLightData.k_MaxEvsmLightLeakBias, s_Styles.evsmLightLeakBias);
EditorGUILayout.Slider(serialized.evsmVarianceBias, HDAdditionalLightData.k_MinEvsmVarianceBias, HDAdditionalLightData.k_MaxEvsmVarianceBias, s_Styles.evsmVarianceBias);
EditorGUILayout.IntSlider(serialized.evsmBlurPasses, HDAdditionalLightData.k_MinEvsmBlurPasses, HDAdditionalLightData.k_MaxEvsmBlurPasses, s_Styles.evsmAdditionalBlurPasses);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,6 @@ public class Styles
public static readonly GUIContent[] shadowBitDepthNames = { new GUIContent("32 bit"), new GUIContent("16 bit") };
public static readonly int[] shadowBitDepthValues = { (int)DepthBits.Depth32, (int)DepthBits.Depth16 };

// TEMP: HDShadowFilteringQuality.VeryHigh - This filtering mode is not ready so disabling in UI
// To re-enable remove the two following light and re-enable the third one
public static readonly GUIContent[] shadowFilteringNames = { new GUIContent("Low"), new GUIContent("Medium"), new GUIContent("High") };
public static readonly int[] shadowFilteringValue = { 0, 1, 2 };

public const string memoryDrawback = "Adds GPU memory";
public const string shaderVariantDrawback = "Adds Shader Variants";
public const string lotShaderVariantDrawback = "Adds multiple Shader Variants";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,11 +355,7 @@ static void Drawer_SectionShadows(SerializedHDRenderPipelineAsset serialized, Ed

if (!serialized.renderPipelineSettings.supportedLitShaderMode.hasMultipleDifferentValues)
{
// TEMP: HDShadowFilteringQuality.VeryHigh - This filtering mode is not ready so disabling in UI
// To re-enable remove the wo following light and re-enable the third one
int value = EditorGUILayout.IntPopup(Styles.filteringQuality, serialized.renderPipelineSettings.hdShadowInitParams.shadowFilteringQuality.enumValueIndex, Styles.shadowFilteringNames, Styles.shadowFilteringValue);
serialized.renderPipelineSettings.hdShadowInitParams.shadowFilteringQuality.enumValueIndex = value;
//EditorGUILayout.PropertyField(serialized.renderPipelineSettings.hdShadowInitParams.shadowFilteringQuality, Styles.filteringQuality);
EditorGUILayout.PropertyField(serialized.renderPipelineSettings.hdShadowInitParams.shadowFilteringQuality, Styles.filteringQuality);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2500,7 +2500,7 @@ void SetCommonShadowRequestSettings(HDShadowRequest shadowRequest, VisibleLight
shadowRequest.shadowSoftness = softness;
shadowRequest.blockerSampleCount = blockerSampleCount;
shadowRequest.filterSampleCount = filterSampleCount;
shadowRequest.minFilterSize = minFilterSize * 0.001f; // This divide by 1000 is here to have a range [0...1] exposed to user
shadowRequest.minFilterSize = minFilterSize * 0.01f; // This divide by 1000 is here to have a range [0...1] exposed to user

shadowRequest.kernelSize = (uint)kernelSize;
shadowRequest.lightAngle = (lightAngle * Mathf.PI / 180.0f);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,80 +86,128 @@ static const float2 fibonacciSpiralDirection[DISK_SAMPLE_COUNT] =
float2 (0.9205789302157817, 0.3905565685566777)
};

real2 ComputeFibonacciSpiralDiskSample(const in int sampleIndex, const in real diskRadius, const in real sampleCountInverse, const in real sampleCountBias)
// Samples uniformly spread across the disk kernel
real2 ComputeFibonacciSpiralDiskSampleUniform(const in int sampleIndex, const in real sampleCountInverse, out real sampleDistNorm)
{
real sampleRadius = diskRadius * sqrt((real)sampleIndex * sampleCountInverse + sampleCountBias);
real2 sampleDirection = fibonacciSpiralDirection[sampleIndex];
return sampleDirection * sampleRadius;
sampleDistNorm = (real)sampleIndex * sampleCountInverse;

// sqrt results in uniform distribution
sampleDistNorm = sqrt(sampleDistNorm);

return fibonacciSpiralDirection[sampleIndex] * sampleDistNorm;
}

real PenumbraSizePunctual(real Reciever, real Blocker)
// Samples denser near the center - important for blocker search
real2 ComputeFibonacciSpiralDiskSample(const in int sampleIndex, const in real sampleCountInverse, out real sampleDistNorm)
{
return abs((Reciever - Blocker) / Blocker);
sampleDistNorm = (real)sampleIndex * sampleCountInverse;

// Third power chosen arbitrarily - center area is really that much more important
// TODO: experiment with other radial functions, still overweighing the center though
sampleDistNorm = sampleDistNorm * sampleDistNorm * sampleDistNorm;

return fibonacciSpiralDirection[sampleIndex] * sampleDistNorm;
}

real PenumbraSizePunctual(real receiver, real blocker)
{
return abs((receiver - blocker) / blocker);
}

real PenumbraSizeDirectional(real Reciever, real Blocker, real rangeScale)
real PenumbraSizeDirectional(real receiver, real blocker, real rangeScale)
{
return abs(Reciever - Blocker) * rangeScale;
return abs(receiver - blocker) * rangeScale;
}

void FilterScaleOffset(real3 coord, real maxSampleZDistance, real shadowmapSamplingScale, out real2 filterScalePos, out real2 filterScaleNeg, out real2 filterOffset)
{
real d = shadowmapSamplingScale * maxSampleZDistance / (1 - coord.z);
real2 target = (coord.xy + 0.5) * 0.5;

filterScalePos = (1 - target) * d;
filterScaleNeg = target * d;
filterOffset = (target - coord.xy) * d;
}

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 maxSampleZDistance, real2 shadowmapInAtlasScale, real2 posTCAtlas, real3 posTCShadowmap, real2 sampleJitter, Texture2D shadowMap, SamplerState pointSampler, int sampleCount)
{
real blockerSum = 0.0;
real sampleCountInverse = rcp((real)sampleCount);
real sampleCountBias = 0.5 * sampleCountInverse;
real ditherRotation = sampleJitter.x;

// The z extent of the filter cone shouldn't go beyond the near plane of the shadow. Near plane at 1.
maxSampleZDistance = min(1 - posTCShadowmap.z, maxSampleZDistance);

real2 filterScalePos, filterScaleNeg;
real2 filterOffset;
FilterScaleOffset(posTCShadowmap, maxSampleZDistance, shadowmapInAtlasScale.x, filterScalePos, filterScaleNeg, filterOffset);

for (int i = 0; i < sampleCount && i < DISK_SAMPLE_COUNT; ++i)
{
real2 offset = ComputeFibonacciSpiralDiskSample(i, lightArea, sampleCountInverse, sampleCountBias);
real sampleDistNorm;
real2 offset = ComputeFibonacciSpiralDiskSample(i, sampleCountInverse, sampleDistNorm);
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;
offset = offset * (offset > 0 ? filterScalePos : filterScaleNeg) + filterOffset * sampleDistNorm;

real blocker = SAMPLE_TEXTURE2D_LOD(shadowMap, pointSampler, posTCAtlas + offset, 0.0).x;

if (COMPARE_DEVICE_DEPTH_CLOSER(shadowMapDepth, coord.z))
real zoffset = maxSampleZDistance * sampleDistNorm;

if (COMPARE_DEVICE_DEPTH_CLOSER(blocker, posTCShadowmap.z + zoffset))
{
blockerSum += shadowMapDepth;
blockerSum += blocker;
numBlockers += 1.0;
}
}
averageBlockerDepth = blockerSum / numBlockers;
averageBlockerDepth = numBlockers > 0 ? blockerSum / numBlockers : posTCShadowmap.z;

return numBlockers >= 1;
}

real PCSS(real3 coord, real filterRadius, real2 scale, real2 offset, real2 sampleJitter, Texture2D shadowMap, SamplerComparisonState compSampler, int sampleCount)
real PCSS(real2 posTCAtlas, real3 posTCShadowmap, real maxSampleZDistance, real2 shadowmapInAtlasScale, real2 shadowmapInAtlasOffset, real2 sampleJitter, Texture2D shadowMap, SamplerComparisonState compSampler, int sampleCount)
{
real UMin = offset.x;
real UMax = offset.x + scale.x;
real UMin = shadowmapInAtlasOffset.x;
real UMax = shadowmapInAtlasOffset.x + shadowmapInAtlasScale.x;

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

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

real2 filterScalePos, filterScaleNeg;
real2 filterOffset;
FilterScaleOffset(posTCShadowmap, maxSampleZDistance, shadowmapInAtlasScale.x, filterScalePos, filterScaleNeg, filterOffset);

for (int i = 0; i < sampleCount && i < DISK_SAMPLE_COUNT; ++i)
{
real2 offset = ComputeFibonacciSpiralDiskSample(i, filterRadius, sampleCountInverse, sampleCountBias);
real sampleDistNorm;
real2 offset = ComputeFibonacciSpiralDiskSampleUniform(i, sampleCountInverse, sampleDistNorm);
offset = real2(offset.x * sampleJitter.y + offset.y * sampleJitter.x,
offset.x * -sampleJitter.x + offset.y * sampleJitter.y);

real U = coord.x + offset.x;
real V = coord.y + offset.y;
offset = offset * (offset > 0 ? filterScalePos : filterScaleNeg) + filterOffset * sampleDistNorm;

real U = posTCAtlas.x + offset.x;
real V = posTCAtlas.y + offset.y;

real zoffset = maxSampleZDistance * sampleDistNorm;

//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));
// coord.xy = clamp(posTCAtlas.xy, float2(UMin, VMin), float2(UMax, VMax));

// TODO: vectorize into two comparisons?
if (U <= UMin || U >= UMax || V <= VMin || V >= VMax)
sum += SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(coord.xy, coord.z)).r;
// TODO: why wasn't it just not sampling here? Investigate before removing
sum += 1;//SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(posTCAtlas, posTCShadowmap.z + zoffset)).r;
else
sum += SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(U, V, coord.z)).r;
sum += SAMPLE_TEXTURE2D_SHADOW(shadowMap, compSampler, real3(U, V, posTCShadowmap.z + zoffset)).r;
}

return sum / sampleCount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,24 +139,31 @@ float3 EvalShadow_NormalBias(float worldTexelSize, float normalBias, float3 norm
float normalBiasMult = normalBias * worldTexelSize;
return normalWS * normalBiasMult;
}
//
// Point shadows
//
float EvalShadow_PunctualDepth(HDShadowData sd, Texture2D tex, SamplerComparisonState samp, float2 positionSS, float3 positionWS, float3 normalWS, float3 L, float L_dist, bool perspective)

bool CalculatePosTC(HDShadowData sd, float2 texelSize, float3 positionWS, float3 normalWS, float L_dist, bool perspective, out float3 posTC)
{
float2 texelSize = sd.isInCachedAtlas ? _CachedShadowAtlasSize.zw : _ShadowAtlasSize.zw;
positionWS = positionWS + sd.cacheTranslationDelta.xyz;
/* bias the world position */
float worldTexelSize = EvalShadow_WorldTexelSize(sd.worldTexelSize, L_dist, true);
float3 normalBias = EvalShadow_NormalBias(worldTexelSize, sd.normalBias, normalWS);
positionWS += normalBias;
/* get shadowmap texcoords */
float3 posTC = EvalShadow_GetTexcoordsAtlas(sd, texelSize, positionWS, perspective);
posTC = EvalShadow_GetTexcoordsAtlas(sd, texelSize, positionWS, perspective);
/* sample the texture */
// We need to do the check on min/max coordinates because if the shadow spot angle is smaller than the actual cone, then we could have artifacts due to the clamp sampler.
float2 maxCoord = (sd.shadowMapSize.xy - 0.5f) * texelSize + sd.atlasOffset;
float2 minCoord = sd.atlasOffset + 0.5f * texelSize;
return any(posTC.xy > maxCoord || posTC.xy < minCoord) ? 1.0f : PUNCTUAL_FILTER_ALGORITHM(sd, positionSS, posTC, tex, samp, FIXED_UNIFORM_BIAS);
return !any(posTC.xy > maxCoord || posTC.xy < minCoord);
}

//
// Point shadows
//
float EvalShadow_PunctualDepth(HDShadowData sd, Texture2D tex, SamplerComparisonState samp, float2 positionSS, float3 positionWS, float3 normalWS, float3 L, float L_dist, bool perspective)
{
float2 texelSize = sd.isInCachedAtlas ? _CachedShadowAtlasSize.zw : _ShadowAtlasSize.zw;
float3 posTC;
return CalculatePosTC(sd, texelSize, positionWS, normalWS, L_dist, perspective, posTC) ? PUNCTUAL_FILTER_ALGORITHM(sd, positionSS, posTC, tex, samp, FIXED_UNIFORM_BIAS) : 1.0f;
}

//
Expand All @@ -179,6 +186,17 @@ float EvalShadow_AreaDepth(HDShadowData sd, Texture2D tex, float2 positionSS, fl
{
float2 texelSize = sd.isInCachedAtlas ? _CachedAreaShadowAtlasSize.zw : _AreaShadowAtlasSize.zw;

// TODO: refactor into AREA_FILTER_ALGORITHM
#ifdef SHADOW_VERY_HIGH // Do PCSS

float3 posTC;
if (CalculatePosTC(sd, texelSize, positionWS, normalWS, L_dist, perspective, posTC))
return SampleShadow_PCSS(posTC, positionSS, sd.shadowMapSize.xy * texelSize, sd.atlasOffset, sd.shadowFilterParams0.x, sd.shadowFilterParams0.w, asint(sd.shadowFilterParams0.y), asint(sd.shadowFilterParams0.z), tex, s_linear_clamp_compare_sampler, s_point_clamp_sampler, FIXED_UNIFORM_BIAS, sd.zBufferParam, true, (sd.isInCachedAtlas ? _CachedAreaShadowAtlasSize.xz : _AreaShadowAtlasSize.xz));
else
return 1.0f;

#else // Do EVSM

positionWS = positionWS + sd.cacheTranslationDelta.xyz;
float3 posTC = EvalShadow_GetTexcoordsAtlas(sd, texelSize, positionWS, perspective);

Expand All @@ -187,6 +205,8 @@ float EvalShadow_AreaDepth(HDShadowData sd, Texture2D tex, float2 positionSS, fl
EvalShadow_Area_GetMinMaxCoords(sd, texelSize, minCoord, maxCoord);

return any(posTC.xy > maxCoord || posTC.xy < minCoord) ? 1.0f : AREA_FILTER_ALGORITHM(sd, positionSS, posTC, tex, s_linear_clamp_compare_sampler, FIXED_UNIFORM_BIAS);

#endif
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public void InitShadowManager(HDRenderPipelineRuntimeResources renderPipelineRes
areaAtlasInitParams.width = initParams.areaLightShadowAtlas.shadowAtlasResolution;
areaAtlasInitParams.height = initParams.areaLightShadowAtlas.shadowAtlasResolution;
areaAtlasInitParams.atlasShaderID = HDShaderIDs._ShadowmapAreaAtlas;
areaAtlasInitParams.blurAlgorithm = HDShadowAtlas.BlurAlgorithm.EVSM;
areaAtlasInitParams.blurAlgorithm = GetAreaLightShadowBlurAlgorithm();
areaAtlasInitParams.depthBufferBits = initParams.areaLightShadowAtlas.shadowAtlasDepthBits;
areaAtlasInitParams.name = "Area Light Shadow Map Atlas";

Expand Down Expand Up @@ -453,6 +453,12 @@ public static DirectionalShadowAlgorithm GetDirectionalShadowAlgorithm()
return DirectionalShadowAlgorithm.PCF5x5;
}

public static HDShadowAtlas.BlurAlgorithm GetAreaLightShadowBlurAlgorithm()
{
return HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.shadowFilteringQuality == HDShadowFilteringQuality.VeryHigh ?
HDShadowAtlas.BlurAlgorithm.None : HDShadowAtlas.BlurAlgorithm.EVSM;
}

public void UpdateShaderVariablesGlobalCB(ref ShaderVariablesGlobal cb)
{
if (m_MaxShadowRequests == 0)
Expand Down
Loading