Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mixed cached shadow maps (Cached static + dynamic rendered every frame) #1559

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
840c954
UI for mixed cached shadows
FrancescoC-unity Jul 30, 2020
2b256fb
Baby steps (# 1)
FrancescoC-unity Aug 3, 2020
c5fb40c
Baby steps (# 2)
FrancescoC-unity Aug 3, 2020
1929450
Extrapolate the update request data into a function
FrancescoC-unity Aug 3, 2020
a6ba1cd
Commit before blit code
FrancescoC-unity Aug 3, 2020
44c347e
Need to switch branch
FrancescoC-unity Aug 4, 2020
fb1a74a
Need to switch branch
FrancescoC-unity Aug 4, 2020
f0bf347
Working as long the light does not move.
FrancescoC-unity Aug 7, 2020
3a70423
Fixed area light case
FrancescoC-unity Aug 7, 2020
ea84332
Make it render graph ready
FrancescoC-unity Aug 7, 2020
6fe07a8
Make sure we correctly update the freshly updated cached shadows
FrancescoC-unity Aug 7, 2020
b99be9d
Raw update upon movement option (Missing API for threshold)
FrancescoC-unity Aug 7, 2020
e09e735
Threshold API
FrancescoC-unity Aug 10, 2020
b6626b0
Add unity binary tag
FrancescoC-unity Aug 10, 2020
93f1a32
New docs
FrancescoC-unity Aug 10, 2020
56340b7
Shader name change
FrancescoC-unity Aug 10, 2020
de8888a
Merge branch 'HDRP/staging' into HDRP/cached-shadows-with-dynamic-cas…
FrancescoC-unity Aug 10, 2020
d3c8be5
Update docs
FrancescoC-unity Aug 10, 2020
e5164e4
Fix bad merge
FrancescoC-unity Aug 11, 2020
a8612ba
Update Shadows-in-HDRP.md
JordanL8 Aug 12, 2020
da7a5a9
For now disable the directional light case.
FrancescoC-unity Aug 25, 2020
94f559e
Merge branch 'HDRP/staging' into HDRP/cached-shadows-with-dynamic-cas…
FrancescoC-unity Aug 25, 2020
9f5d479
Disable directional mixed.
FrancescoC-unity Aug 26, 2020
23aee85
Make it disabled under define
FrancescoC-unity Oct 2, 2020
37f2c40
Remove docs
FrancescoC-unity Oct 2, 2020
a735c24
Merge branch 'HDRP/staging' into HDRP/cached-shadows-with-dynamic-cas…
FrancescoC-unity Oct 6, 2020
62b598f
Implement rendergraph version
FrancescoC-unity Oct 6, 2020
1f013ca
Remove superflous blit
FrancescoC-unity Oct 6, 2020
f7ee31a
Tentative fix for yamato.
FrancescoC-unity Oct 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -108,6 +108,10 @@ When a Light that caches its shadows renders its shadow map for the first time,
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.
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. This option can be selected in the Shadow settings section on the Light as **Update on light movement**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 and, in the Shadow section of its Inspector, enable Update on light movement.

The threshold that are used to determine how much a light needs to move or rotate to trigger an update can be customized per light with the properties
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can customize the threshold that HDRP uses to determine how much a light needs to move or rotate to trigger an update. To do this, use the:

`cachedShadowTranslationUpdateThreshold` and `cachedShadowAngleUpdateThreshold` on the **HDAdditionalLightData** component. Note that point lights ignore the angle differences when determining if an update is needed with this mode.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cachedShadowTranslationUpdateThreshold and cachedShadowAngleUpdateThreshold properties on the Light's HDAdditionalLightData component. Note that point lights ignore the angle differences when determining if they need to perform an update in this mode.


### Customising shadow caching
HDRP caches shadow maps for punctual Lights into one atlas, area Lights into another, and directional Lights into the same atlas as non-cached Directional Lights. You can change the resolution of the first two cached shadow atlases independently of one another. To do this:

Expand All @@ -131,6 +135,16 @@ Note that this causes HDRP to mark all the shadow maps in the atlas as dirty whi
If you disable the Light or change its **Update Mode** to **Every Frame**, the cached shadow manager unreserves the Light's shadow map's space in the cached shadow atlas and HDRP begins to render the Light's shadow map to the normal shadow atlases every frame. If the cached shadow manager needs to allocate space on the atlas for another Light, it can overwrite the space currently taken up by the original Light's shadow map.
If you plan to only temporarily set a Light's **Update Mode** to **Every Frame** and want to set it back to **On Enable** or **On Demand** later, you can preserve the Light's shadow map placement in its atlas. This is useful, for example, if you want HDRP to cache a far away Light's shadow map, but update it every frame when it gets close to the [Camera](HDRP-Camera.md). To do this, access the Light's **HDAdditionalLightData** component and enable the **preserveCachedShadow** property. If this property is set to `true`, HDRP preserves the Light's shadow map's space in its shadow atlas. Note that even if this property is enabled, if you destroy the Light, it loses its placement in the shadow atlas.

### Mixed Cached Shadow Maps

It is possible to cache only a portion of the shadow map. In order to do so, you must check the **Always draw dynamic** option in the shadow settings of the light and then tick the **Static Shadow Caster** checkbox all renderers that will be cached in shadows (in the Renderer component).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to cache only a portion of the shadow map. To do this, enable the Always draw dynamic option in the Light's shadow settings and then enable the Static Shadow Caster option for all Renderers to cache shadows for.

With such setup, all static shadow casters are rendered in the shadow map only whenever an explicit update is requested (or only on light enable in case of **OnEnable** update mode), while the other casters (dynamic shadow casters) are drawn each frame.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this setup, HDRP only renders static shadow casters into the shadow map when an explicit update is requested (or, if the Light uses the OnEnable update mode, only when the Light enables) whereas, for dynamic shadow casters, HDRP renders them into their respective shadow maps each frame.

This setup is particularly useful if for example your environment is mostly static and the light doesn't move, but there are few dynamic objects that will need shadows to be cast by such lights. In such scenarios, setting the light as having a mixed cached shadow map will greatly improve performance both on CPU and GPU.
Copy link
Contributor

@JordanL8 JordanL8 Aug 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setup is particularly useful if your environment consists of mostly static GameObjects and the lights do not move, but there are few dynamic GameObjects that you want the static lights to cast shadows for. In such scenarios, setting the light to have a mixed cached shadow map greatly improves performance both on the CPU and GPU.


Please note that as part of implementation details, if a shadow is set up as mixed cached, every frame a blit from the cached shadow map to the dynamic atlas is performed. This is important to keep in mind both for the extra runtime cost of the blit in itself, but also to understand that in terms of memory a single shadow map will require space in both atlases.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that, due to implementation details, if you set up a shadow to be mixed cached, HDRP performs a blit from the cached shadow map to the dynamic atlas. This is important to keep in mind both for the extra runtime cost of the blit in itself, but also to understand that, in terms of memory, a single shadow map requires space in both atlases.


Another important note, is due to implementation details, if a light with mixed cached shadows moves and the cached counterpart is not updated, the result will look wrong. In such cases either select the **Update on light movement** or the update mode to **OnDemand** and make sure an update is triggered when desired.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another important note, also due to implementation details, if a Light with mixed cached shadows moves and you do not update the cached counterpart, the result looks wrong. In such cases either enable the Light's Update on light movement option or set the Light's update mode to OnDemand and make sure to trigger an update when you move the Light.


### Notes

While you are in the Unity Editor, HDRP updates shadow maps whenever you modify the Light that casts them. In a built application, HDRP refreshes cached shadow maps when you change different properties on the Light or when you call one of the following functions:
Expand Down
Expand Up @@ -116,6 +116,8 @@ sealed class Styles
public readonly GUIContent contactShadows = new GUIContent("Enable", "Enable support for Contact Shadows on this Light. This is better for lights with a lot of visible shadows.");
public readonly GUIContent rayTracedContactShadow = new GUIContent("Ray Tracing (Preview)", "Uses ray tracing to compute the contact shadow for a light.");
public readonly GUIContent shadowUpdateMode = new GUIContent("Update Mode", "Specifies when HDRP updates the shadow map.");
public readonly GUIContent shadowAlwaysDrawDynamic = new GUIContent("Always draw dynamic", "Specifies whether HDRP renders dynamic shadow caster every frame regardless of the update mode.");
public readonly GUIContent shadowUpdateOnLightTransformChange = new GUIContent("Update on light movement", "Whether a cached shadow map will be automatically updated when the light transform changes.");
public readonly GUIContent useCustomSpotLightShadowCone = new GUIContent("Custom Spot Angle", "When enabled, this Spot Light uses the custom angle for shadow map rendering.");
public readonly GUIContent customSpotLightShadowCone = new GUIContent("Shadow Angle", "Controls the custom angle this Spot Light uses for shadow map rendering.");

Expand Down
Expand Up @@ -973,6 +973,15 @@ static void DrawShadowMapContent(SerializedHDLight serialized, Editor owner)
{
EditorGUILayout.PropertyField(serialized.shadowUpdateMode, s_Styles.shadowUpdateMode);

if(serialized.shadowUpdateMode.intValue > 0)
{
#if UNITY_2020_2_OR_NEWER
EditorGUILayout.PropertyField(serialized.shadowAlwaysDrawDynamic, s_Styles.shadowAlwaysDrawDynamic);
#endif
EditorGUILayout.PropertyField(serialized.shadowUpdateUponTransformChange, s_Styles.shadowUpdateOnLightTransformChange);

}

HDLightType lightType = serialized.type;

using (var change = new EditorGUI.ChangeCheckScope())
Expand Down
Expand Up @@ -94,6 +94,8 @@ internal class SerializedHDLight
public SerializedProperty shadowTint;
public SerializedProperty penumbraTint;
public SerializedProperty shadowUpdateMode;
public SerializedProperty shadowAlwaysDrawDynamic;
public SerializedProperty shadowUpdateUponTransformChange;
public SerializedScalableSettingValue shadowResolution;

// Bias control
Expand Down Expand Up @@ -408,6 +410,8 @@ public SerializedHDLight(HDAdditionalLightData[] lightDatas, LightEditor.Setting
shadowTint = o.Find("m_ShadowTint");
penumbraTint = o.Find("m_PenumbraTint");
shadowUpdateMode = o.Find("m_ShadowUpdateMode");
shadowAlwaysDrawDynamic = o.Find("m_AlwaysDrawDynamicShadows");
shadowUpdateUponTransformChange = o.Find("m_UpdateShadowOnLightMovement");
shadowResolution = new SerializedScalableSettingValue(o.Find((HDAdditionalLightData l) => l.shadowResolution));

slopeBias = o.Find("m_SlopeBias");
Expand Down