diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md
index 3e7f83cc890..0110e8e7c3f 100644
--- a/com.unity.render-pipelines.high-definition/CHANGELOG.md
+++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md
@@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added new API in CachedShadowManager
- Added an additional check in the "check scene for ray tracing" (case 1314963).
- Added shader graph unit test for IsFrontFace node
+- API to allow OnDemand shadows to not render upon placement in the Cached Shadow Atlas.
+- Exposed update upon light movement for directional light shadows in UI.
### Fixed
- Fixed an exception when opening the color picker in the material UI (case 1307143).
@@ -58,6 +60,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fix crash on VolumeComponentWithQualityEditor when the current Pipeline is not HDRP
- Fixed WouldFitInAtlas that would previously return wrong results if any one face of a point light would fit (it used to return true even though the light in entirety wouldn't fit).
- Fixed issue with NaNs in Volumetric Clouds on some platforms.
+- Fixed update upon light movement for directional light rotation.
### Changed
- Changed Window/Render Pipeline/HD Render Pipeline Wizard to Window/Rendering/HDRP Wizard
diff --git a/com.unity.render-pipelines.high-definition/Documentation~/Shadows-in-HDRP.md b/com.unity.render-pipelines.high-definition/Documentation~/Shadows-in-HDRP.md
index 321c282079f..9b5a3e13b44 100644
--- a/com.unity.render-pipelines.high-definition/Documentation~/Shadows-in-HDRP.md
+++ b/com.unity.render-pipelines.high-definition/Documentation~/Shadows-in-HDRP.md
@@ -109,6 +109,9 @@ A Light's **Update Mode** determines whether or not HDRP caches its shadow map:I
When a Light that caches its shadows renders its shadow map for the first time, HDRP registers it with the cached shadow manager which assigns the shadow map to a cached shadow atlas. In the case of directional Lights, HDRP uses the same shadow atlas for cached and non-cached directional Lights.
If the Light's **Update Mode** is set to **OnDemand**, you can manually request HDRP to update the Light's shadow map. To do this, access the Light's **HDAdditionalLightData** component and call the `RequestShadowMapRendering` function. Also, if the Light has multiple shadows (e.g. multiple cascades of a directional light), you can request the update of a specific sub-shadow. To do this, use the `RequestSubShadowMapRendering(shadowIndex)` function.
+By default when **Update Mode** is set to **OnDemand** the shadow maps will be rendered OnEnable the first time or when first registered with the system, however it is possible to change this behaviour by changing the property `onDomandShadowRenderOnPlacement`. If this property is set to false, the shadows won't be rendered until explicitly calling `RequestShadowMapRendering` or `RequestSubShadowMapRendering(shadowIndex)` .
+
+
For a Light that does cache its shadows, if you disable it or set its **Update Mode** to **Every Frame**, you can tell HDRP to preserve the Light's shadow map's place in the cached shadow atlas. This means that, if you enable the Light again, HDRP does not need to re-render the shadow map or place it into a shadow atlas. For information on how to make a Light preserve its shadow map's place in the cached shadow atlas, see [Preserving shadow atlas placement](#preserving-shadow-atlas-placement).
As a shortcut for a common case, HDRP offers an option to automatically trigger an update when either the position or rotation of a light changes above a certain threshold. To enable this option, select a [Light](https://github.com/Unity-Technologies/Graphics/pull/Light-Component.md) and, in the **Shadow** section of its Inspector, enable **Update on light movement**.
diff --git a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
index c1c7f62c63c..b37f3e2f203 100644
--- a/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
+++ b/com.unity.render-pipelines.high-definition/Editor/Lighting/HDLightUI.cs
@@ -1048,8 +1048,8 @@ static void DrawShadowMapContent(SerializedHDLight serialized, Editor owner)
#if UNITY_2021_1_OR_NEWER
EditorGUILayout.PropertyField(serialized.shadowAlwaysDrawDynamic, s_Styles.shadowAlwaysDrawDynamic);
#endif
- EditorGUILayout.PropertyField(serialized.shadowUpdateUponTransformChange, s_Styles.shadowUpdateOnLightTransformChange);
}
+ EditorGUILayout.PropertyField(serialized.shadowUpdateUponTransformChange, s_Styles.shadowUpdateOnLightTransformChange);
HDLightType lightType = serialized.type;
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
index 8b90e606003..c94c13629c2 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Light/HDAdditionalLightData.cs
@@ -1586,6 +1586,27 @@ public bool preserveCachedShadow
}
}
+ [SerializeField]
+ bool m_OnDemandShadowRenderOnPlacement = true;
+ ///
+ /// If the shadow update mode is set to OnDemand, this parameter controls whether the shadows are rendered the first time without needing an explicit render request. If this properties is false,
+ /// the OnDemand shadows will never be rendered unless a render request is performed explicitly.
+ ///
+ public bool onDomandShadowRenderOnPlacement
+ {
+ get => m_OnDemandShadowRenderOnPlacement;
+ set
+ {
+ if (m_OnDemandShadowRenderOnPlacement == value)
+ return;
+
+ m_OnDemandShadowRenderOnPlacement = value;
+ }
+ }
+
+ // This is a bit confusing, but it is an override to ignore the onDomandShadowRenderOnPlacement field when a light is registered for the first time as a consequence of a request for shadow update.
+ internal bool forceRenderOnPlacement = false;
+
///
/// True if the light affects volumetric fog, false otherwise
///
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowAtlas.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowAtlas.cs
index f34fec4d4fc..5c968626fd5 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowAtlas.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowAtlas.cs
@@ -20,6 +20,7 @@ struct CachedShadowRecord
internal int shadowIndex;
internal int viewportSize; // We assume only square shadows maps.
internal Vector4 offsetInAtlas; // When is registered xy is the offset in the texture atlas, in UVs, the zw is the entry offset in the C# representation.
+ internal bool rendersOnPlacement;
}
// We need an extra struct to track differences in the light transform
@@ -349,7 +350,9 @@ private void AddLightListToRecordList(Dictionary lig
record.shadowIndex = currentLightData.lightIdxForCachedShadows + i;
record.viewportSize = resolution;
record.offsetInAtlas = new Vector4(-1, -1, -1, -1); // Will be set later.
-
+ // Only situation in which we allow not to render on placement if it is OnDemand and onDomandShadowRenderOnPlacement is false
+ record.rendersOnPlacement = (currentLightData.shadowUpdateMode == ShadowUpdateMode.OnDemand) ? (currentLightData.forceRenderOnPlacement || currentLightData.onDomandShadowRenderOnPlacement) : true;
+ currentLightData.forceRenderOnPlacement = false; // reset the force flag as we scheduled the rendering forcefully already.
recordList.Add(record);
}
}
@@ -389,7 +392,10 @@ private bool PlaceMultipleShadows(int startIdx, int numberOfShadows)
record.offsetInAtlas = new Vector4(placements[j].x * m_MinSlotSize, placements[j].y * m_MinSlotSize, placements[j].x, placements[j].y);
- m_ShadowsPendingRendering.Add(record.shadowIndex, record);
+ if (record.rendersOnPlacement)
+ {
+ m_ShadowsPendingRendering.Add(record.shadowIndex, record);
+ }
m_PlacedShadows.Add(record.shadowIndex, record);
}
@@ -440,7 +446,10 @@ private void PerformPlacement()
// Convert offset to atlas offset.
record.offsetInAtlas = new Vector4(x * m_MinSlotSize, y * m_MinSlotSize, x, y);
- m_ShadowsPendingRendering.Add(record.shadowIndex, record);
+ if (record.rendersOnPlacement)
+ {
+ m_ShadowsPendingRendering.Add(record.shadowIndex, record);
+ }
m_PlacedShadows.Add(record.shadowIndex, record);
m_RegisteredLightDataPendingPlacement.Remove(record.shadowIndex);
m_RecordsPendingPlacement.Remove(record.shadowIndex);
@@ -573,6 +582,7 @@ internal void ScheduleShadowUpdate(HDAdditionalLightData lightData)
if (m_RegisteredLightDataPendingPlacement.ContainsKey(lightIdx))
return;
+ lightData.forceRenderOnPlacement = true;
RegisterLight(lightData);
}
else
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowManager.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowManager.cs
index 29fea17419d..056a964877d 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowManager.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDCachedShadowManager.cs
@@ -367,7 +367,12 @@ internal bool NeedRenderingDueToTransformChange(HDAdditionalLightData lightData,
{
float angleDiffThreshold = lightData.cachedShadowAngleUpdateThreshold;
Vector3 angleDiff = m_CachedDirectionalAngles - lightData.transform.eulerAngles;
- return (Mathf.Abs(angleDiff.x) > angleDiffThreshold || Mathf.Abs(angleDiff.y) > angleDiffThreshold || Mathf.Abs(angleDiff.z) > angleDiffThreshold);
+ bool needsUpdate = (Mathf.Abs(angleDiff.x) > angleDiffThreshold || Mathf.Abs(angleDiff.y) > angleDiffThreshold || Mathf.Abs(angleDiff.z) > angleDiffThreshold);
+ if (needsUpdate)
+ {
+ m_CachedDirectionalAngles = lightData.transform.eulerAngles;
+ }
+ return needsUpdate;
}
else if (lightType == HDLightType.Area)
{