diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index a807afb001c..eb3d3bf57b7 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -116,6 +116,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added fabric materials and textures
- Added information for fabric materials in fabric scene
- Added a DisplayInfo attribute to specify a name override and a display order for Volume Component fields (used only in default inspector for now).
+- Added Min distance to contact shadows.
### Fixed
- Fix when rescale probe all direction below zero (1219246)
@@ -557,6 +558,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fix MaterialBalls having same guid issue
- Fix spelling and grammatical errors in material samples
- Fixed unneeded cookie texture allocation for cone stop lights.
+- Fixed scalarization code for contact shadows.
### Changed
- Improve MIP selection for decals on Transparents
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Images/Override-ContactShadows1.png b/com.unity.render-pipelines.high-definition/Documentation~/Images/Override-ContactShadows1.png
index 471cef78b6e..f99a790234f 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Images/Override-ContactShadows1.png
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Images/Override-ContactShadows1.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:504ed4dc738c16bf4bbc227d0a30438c05fabe2847f3278dfbac74bcee8a8e87
-size 20392
+oid sha256:1a422374528d2c7b1aa36a22bef66d6b1c08938da684a8f40d8f3e92a41c8f1b
+size 17389
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Override-Contact-Shadows.md b/com.unity.render-pipelines.high-definition/Documentation~/Override-Contact-Shadows.md
index 6b22dddb8c1..00de0cfcf4f 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Override-Contact-Shadows.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Override-Contact-Shadows.md
@@ -25,8 +25,10 @@ Only one Light can cast Contact Shadows at a time. This means that, if you have
| __Enable__ | Enable the checkbox to make HDRP process Contact Shadows for this [Volume](Volumes.html). |
| __Length__ | Use the slider to set the length of the rays, in meters, that HDRP uses for tracing. It also functions as the maximum distance at which the rays can captures details. |
| __Distance Scale Factor__ | HDRP scales Contact Shadows up with distance. Use the slider to set the value that HDRP uses to dampen the scale to avoid biasing artifacts with distance. |
+| __Min Distance__ | The distance from the Camera, in meters, at which HDRP begins to fade in Contact Shadows. |
| __Max Distance__ | The distance from the Camera, in meters, at which HDRP begins to fade Contact Shadows out to zero. |
-| __Fade Distance__ | The distance, in meters, over which HDRP fades Contact Shadows out when at the __Max Distance__. |
+| __Fade In Distance__ | The distance, in meters, over which HDRP fades Contact Shadows in when past the **Min Distance**. |
+| __Fade Out Distance__ | The distance, in meters, over which HDRP fades Contact Shadows out when at the __Max Distance__. |
| __Sample Count__ | Use the slider to set the number of samples HDRP uses for ray casting. Increasing this increases quality at the cost of performance. |
| __Opacity__ | Use the slider to set the opacity of the Contact Shadows. Lower values result in softer, less prominent shadows. |
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/Shadow/ContactShadowsEditor.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/Shadow/ContactShadowsEditor.cs
index 3e49aee4062..8f365d80abc 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/Shadow/ContactShadowsEditor.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/Shadow/ContactShadowsEditor.cs
@@ -11,11 +11,12 @@ class ContactShadowsEditor : VolumeComponentWithQualityEditor
SerializedDataParameter m_Length;
SerializedDataParameter m_DistanceScaleFactor;
SerializedDataParameter m_MaxDistance;
+ SerializedDataParameter m_MinDistance;
SerializedDataParameter m_FadeDistance;
+ SerializedDataParameter m_FadeInDistance;
SerializedDataParameter m_SampleCount;
SerializedDataParameter m_Opacity;
-
public override void OnEnable()
{
base.OnEnable();
@@ -26,7 +27,9 @@ public override void OnEnable()
m_Length = Unpack(o.Find(x => x.length));
m_DistanceScaleFactor = Unpack(o.Find(x => x.distanceScaleFactor));
m_MaxDistance = Unpack(o.Find(x => x.maxDistance));
+ m_MinDistance = Unpack(o.Find(x => x.minDistance));
m_FadeDistance = Unpack(o.Find(x => x.fadeDistance));
+ m_FadeInDistance = Unpack(o.Find(x => x.fadeInDistance));
m_SampleCount = Unpack(o.Find(x => x.sampleCount));
m_Opacity = Unpack(o.Find(x => x.opacity));
}
@@ -41,8 +44,12 @@ public override void OnInspectorGUI()
{
PropertyField(m_Length, EditorGUIUtility.TrTextContent("Length", "Controls the length of the rays HDRP uses to calculate Contact Shadows. Uses meters."));
PropertyField(m_DistanceScaleFactor, EditorGUIUtility.TrTextContent("Distance Scale Factor", "Dampens the scale up effect HDRP process with distance from the Camera."));
- PropertyField(m_MaxDistance, EditorGUIUtility.TrTextContent("Max Distance", "Sets The distance from the Camera at which HDRP begins to fade out Contact Shadows. Uses meters."));
- PropertyField(m_FadeDistance, EditorGUIUtility.TrTextContent("Fade Distance", "Sets the distance over which HDRP fades Contact Shadows out when at the Max Distance. Uses meters."));
+ m_MinDistance.value.floatValue = Mathf.Clamp(m_MinDistance.value.floatValue, 0.0f, m_MaxDistance.value.floatValue);
+ PropertyField(m_MinDistance, EditorGUIUtility.TrTextContent("Min Distance", "Sets the distance from the camera at which HDRP begins to fade in Contact Shadows. Uses meters."));
+ PropertyField(m_MaxDistance, EditorGUIUtility.TrTextContent("Max Distance", "Sets the distance from the Camera at which HDRP begins to fade out Contact Shadows. Uses meters."));
+ m_FadeInDistance.value.floatValue = Mathf.Clamp(m_FadeInDistance.value.floatValue, 0.0f, m_MaxDistance.value.floatValue);
+ PropertyField(m_FadeInDistance, EditorGUIUtility.TrTextContent("Fade In Distance", "Sets the distance over which HDRP fades Contact Shadows in when past the Min Distance. Uses meters."));
+ PropertyField(m_FadeDistance, EditorGUIUtility.TrTextContent("Fade Out Distance", "Sets the distance over which HDRP fades Contact Shadows out when at the Max Distance. Uses meters."));
PropertyField(m_Opacity, EditorGUIUtility.TrTextContent("Opacity", "Controls the opacity of the Contact Shadow."));
base.OnInspectorGUI();
GUI.enabled = useCustomValue;
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
index 52c56df0510..243396d315c 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs
@@ -3626,8 +3626,12 @@ ContactShadowsParameters PrepareContactShadowsParameters(HDCamera hdCamera, floa
float contactShadowRange = Mathf.Clamp(m_ContactShadows.fadeDistance.value, 0.0f, m_ContactShadows.maxDistance.value);
float contactShadowFadeEnd = m_ContactShadows.maxDistance.value;
float contactShadowOneOverFadeRange = 1.0f / Math.Max(1e-6f, contactShadowRange);
+
+ float contactShadowMinDist = Mathf.Min(m_ContactShadows.minDistance.value, contactShadowFadeEnd);
+ float contactShadowFadeIn = Mathf.Clamp(m_ContactShadows.fadeInDistance.value, 1e-6f, contactShadowFadeEnd);
+
parameters.params1 = new Vector4(m_ContactShadows.length.value, m_ContactShadows.distanceScaleFactor.value, contactShadowFadeEnd, contactShadowOneOverFadeRange);
- parameters.params2 = new Vector4(firstMipOffsetY, 0.0f, 0.0f, 0.0f);
+ parameters.params2 = new Vector4(firstMipOffsetY, contactShadowMinDist, contactShadowFadeIn, 0.0f);
parameters.sampleCount = m_ContactShadows.sampleCount;
int deferredShadowTileSize = 16; // Must match DeferreDirectionalShadow.compute
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.compute b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.compute
index 75bf516f616..049c9f96981 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.compute
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.compute
@@ -15,9 +15,9 @@
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.hlsl"
-// We perform scalarization only for forward rendering as for deferred loads will already be scalar since tiles will match waves and therefore all threads will read from the same tile.
+// We perform scalarization all the time here as we don't know if we have clustered data structure or not at this point.
// More info on scalarization: https://flashypixels.wordpress.com/2018/11/10/intro-to-gpu-scalarization-part-2-scalarize-all-the-lights/
-#define SCALARIZE_LIGHT_LOOP (defined(PLATFORM_SUPPORTS_WAVE_INTRINSICS) && !defined(LIGHTLOOP_DISABLE_TILE_AND_CLUSTER) && SHADERPASS == SHADERPASS_FORWARD)
+#define SCALARIZE_LIGHT_LOOP (defined(PLATFORM_SUPPORTS_WAVE_INTRINSICS) && !defined(LIGHTLOOP_DISABLE_TILE_AND_CLUSTER))
#pragma only_renderers d3d11 playstation xboxone vulkan metal switch
@@ -147,6 +147,9 @@ bool ComputeContactShadow(PositionInputs posInput, float3 direction, inout float
//Here LightDirection is not the light direction but the light position
float rayLength = _ContactShadowLength * max(0.5, posInput.linearDepth * _ContactShadowDistanceScaleFactor);
occluded = ScreenSpaceShadowRayCast(posInput.positionWS, direction, rayLength, posInput.positionSS, fade);
+ // Fade in
+ fade *= saturate((posInput.linearDepth - _ContactShadowMinDistance) * rcp(_ContactShadowFadeInEnd));
+ // Fade out
fade *= saturate((_ContactShadowFadeEnd - posInput.linearDepth) * _ContactShadowFadeOneOverRange);
globalFade = max(globalFade, fade);
@@ -172,7 +175,7 @@ void DeferredContactShadow(uint2 groupThreadId : SV_GroupThreadID, uint2 groupId
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V, tileCoord);
// discard the shadow if we're on the sky or outside of the contact shadow range
- if (depth == UNITY_RAW_FAR_CLIP_VALUE || posInput.linearDepth - _ContactShadowFadeEnd > 1)
+ if (depth == UNITY_RAW_FAR_CLIP_VALUE || posInput.linearDepth - _ContactShadowFadeEnd > 1 || posInput.linearDepth < _ContactShadowMinDistance)
{
_ContactShadowTextureUAV[COORD_TEXTURE2D_X(pixelCoord)] = 0;
@@ -228,26 +231,35 @@ void DeferredContactShadow(uint2 groupThreadId : SV_GroupThreadID, uint2 groupId
lightStart = startFirstLane;
}
- for (uint lightListOffset = 0; lightListOffset < lightCount; lightListOffset++)
+ uint v_lightIdx = lightStart;
+ uint v_lightListOffset = 0;
+ while (v_lightListOffset < lightCount)
{
- uint v_lightIdx = FetchIndex(lightStart, lightListOffset);
+ v_lightIdx = FetchIndex(lightStart, v_lightListOffset);
uint s_lightIdx = ScalarizeElementIndex(v_lightIdx, fastPath);
if (s_lightIdx == -1)
break;
- LightData light = FetchLight(s_lightIdx); // Scalar load
+ LightData s_lightData = FetchLight(s_lightIdx);
- if (light.contactShadowMask != 0 && light.isRayTracedContactShadow == 0.0)
+ // If current scalar and vector light index match, we process the light. The v_lightListOffset for current thread is increased.
+ // Note that the following should really be ==, however, since helper lanes are not considered by WaveActiveMin, such helper lanes could
+ // end up with a unique v_lightIdx value that is smaller than s_lightIdx hence being stuck in a loop. All the active lanes will not have this problem.
+ if (s_lightIdx >= v_lightIdx)
{
- // Compute light ray direction:
- float3 direction = normalize(light.positionRWS.xyz - posInput.positionWS);
-
- bool occluded = ComputeContactShadow(posInput, direction, globalFade);
-
- // light.contactShadowMask contains one bit at the position of the contact shadow index that will
- // be tested in the lightloop, so it insert 1 at the index of the contact shadow if there is a contact shadow
- // we take full bits at one multiplied by contact shadow and filter the bit at the contact shadow index.
- contactShadowMask |= light.contactShadowMask * occluded;
+ v_lightListOffset++;
+ if (s_lightData.contactShadowMask != 0 && s_lightData.isRayTracedContactShadow == 0.0)
+ {
+ // Compute light ray direction:
+ float3 direction = normalize(s_lightData.positionRWS.xyz - posInput.positionWS);
+
+ bool occluded = ComputeContactShadow(posInput, direction, globalFade);
+
+ // light.contactShadowMask contains one bit at the position of the contact shadow index that will
+ // be tested in the lightloop, so it insert 1 at the index of the contact shadow if there is a contact shadow
+ // we take full bits at one multiplied by contact shadow and filter the bit at the contact shadow index.
+ contactShadowMask |= s_lightData.contactShadowMask * occluded;
+ }
}
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.cs
index a17d4e18af0..f2da6428bbe 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.cs
@@ -31,10 +31,18 @@ public class ContactShadows : VolumeComponentWithQuality
///
public MinFloatParameter maxDistance = new MinFloatParameter(50.0f, 0.0f);
///
+ /// The distance from the camera, in meters, at which HDRP begins to fade in Contact Shadows.
+ ///
+ public MinFloatParameter minDistance = new MinFloatParameter(0.0f, 0.0f);
+ ///
/// The distance, in meters, over which HDRP fades Contact Shadows out when past the Max Distance.
///
public MinFloatParameter fadeDistance = new MinFloatParameter(5.0f, 0.0f);
///
+ /// The distance, in meters, over which HDRP fades Contact Shadows in when past the Min Distance.
+ ///
+ public MinFloatParameter fadeInDistance = new MinFloatParameter(0.0f, 0.0f);
+ ///
/// Controls the number of samples HDRP takes along each contact shadow ray. Increasing this value can lead to higher quality.
///
public int sampleCount
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.hlsl
index 272c246e6c5..f5f01cb67a9 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.hlsl
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/ContactShadows.hlsl
@@ -11,3 +11,5 @@ CBUFFER_END
#define _ContactShadowFadeEnd _ContactShadowParamsParameters.z
#define _ContactShadowFadeOneOverRange _ContactShadowParamsParameters.w
#define _RenderTargetHeight _ContactShadowParamsParameters2.x
+#define _ContactShadowMinDistance _ContactShadowParamsParameters2.y
+#define _ContactShadowFadeInEnd _ContactShadowParamsParameters2.z