diff --git a/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs b/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs index 43b6572b396..b138d518686 100644 --- a/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs +++ b/com.unity.render-pipelines.core/Runtime/Volume/VolumeManager.cs @@ -25,7 +25,7 @@ public sealed class VolumeManager /// A reference to the main . /// /// - public VolumeStack stack { get; private set; } + public VolumeStack stack { get; set; } /// /// The current list of all available types that derive from . @@ -65,6 +65,11 @@ private set // Recycled list used for volume traversal readonly List m_TempColliders; + // The default stack the volume manager uses. + // We cache this as users able to change the stack through code and + // we want to be able to switch to the default one through the ResetMainStack() function. + VolumeStack m_DefaultStack = null; + VolumeManager() { m_SortedVolumes = new Dictionary>(); @@ -75,7 +80,8 @@ private set ReloadBaseTypes(); - stack = CreateStack(); + m_DefaultStack = CreateStack(); + stack = m_DefaultStack; } /// @@ -92,6 +98,15 @@ public VolumeStack CreateStack() return stack; } + /// + /// Resets the main stack to be the default one. + /// Call this function if you've assigned the main stack to something other than the default one. + /// + public void ResetMainStack() + { + stack = m_DefaultStack; + } + /// /// Destroy a Volume Stack /// diff --git a/com.unity.render-pipelines.universal/CHANGELOG.md b/com.unity.render-pipelines.universal/CHANGELOG.md index 4c7aa1660a4..1bfd440fccb 100644 --- a/com.unity.render-pipelines.universal/CHANGELOG.md +++ b/com.unity.render-pipelines.universal/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [10.7.0] - 2021-07-02 +### Added +- Added support for controlling Volume Framework Update Frequency in UI on Cameras and URP Asset as well as through scripting. + ### Fixed - Fixed terrain hole shadowing [case 1349305] - Fixed artifacts in Speed Tree 8 billboard LODs due to SpeedTree LOD smoothing/crossfading [case 1348407] diff --git a/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs b/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs index 78ce72eb77e..071bf820018 100644 --- a/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs +++ b/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineAssetEditor.cs @@ -68,6 +68,7 @@ internal class Styles public static GUIContent mixedLightingSupportLabel = EditorGUIUtility.TrTextContent("Mixed Lighting", "Makes the render pipeline include mixed-lighting Shader Variants in the build."); public static GUIContent debugLevel = EditorGUIUtility.TrTextContent("Debug Level", "Controls the level of debug information generated by the render pipeline. When Profiling is selected, the pipeline provides detailed profiling tags."); public static GUIContent shaderVariantLogLevel = EditorGUIUtility.TrTextContent("Shader Variant Log Level", "Controls the level logging in of shader variants information is outputted when a build is performed. Information will appear in the Unity console when the build finishes."); + public static GUIContent volumeFrameworkUpdateMode = EditorGUIUtility.TrTextContent("Volume Update Mode", "Select how Unity updates Volumes: every frame or when triggered via scripting. In the Editor, Unity updates Volumes every frame when not in the Play mode."); // Adaptive performance settings public static GUIContent useAdaptivePerformance = EditorGUIUtility.TrTextContent("Use adaptive performance", "Allows Adaptive Performance to adjust rendering quality during runtime"); @@ -86,6 +87,7 @@ internal class Styles // Dropdown menu options public static string[] mainLightOptions = { "Disabled", "Per Pixel" }; + public static string[] volumeFrameworkUpdateOptions = { "Every Frame", "Via Scripting" }; public static string[] opaqueDownsamplingOptions = {"None", "2x (Bilinear)", "4x (Box)", "4x (Bilinear)"}; } @@ -135,6 +137,7 @@ internal class Styles SerializedProperty m_DebugLevelProp; SerializedProperty m_ShaderVariantLogLevel; + SerializedProperty m_VolumeFrameworkUpdateModeProp; LightRenderingMode selectedLightRenderingMode; SerializedProperty m_ColorGradingMode; @@ -210,6 +213,7 @@ void OnEnable() m_DebugLevelProp = serializedObject.FindProperty("m_DebugLevel"); m_ShaderVariantLogLevel = serializedObject.FindProperty("m_ShaderVariantLogLevel"); + m_VolumeFrameworkUpdateModeProp = serializedObject.FindProperty("m_VolumeFrameworkUpdateMode"); m_ColorGradingMode = serializedObject.FindProperty("m_ColorGradingMode"); m_ColorGradingLutSize = serializedObject.FindProperty("m_ColorGradingLutSize"); @@ -413,6 +417,7 @@ void DrawAdvancedSettings() EditorGUILayout.PropertyField(m_MixedLightingSupportedProp, Styles.mixedLightingSupportLabel); EditorGUILayout.PropertyField(m_DebugLevelProp, Styles.debugLevel); EditorGUILayout.PropertyField(m_ShaderVariantLogLevel, Styles.shaderVariantLogLevel); + CoreEditorUtils.DrawPopup(Styles.volumeFrameworkUpdateMode, m_VolumeFrameworkUpdateModeProp, Styles.volumeFrameworkUpdateOptions); EditorGUI.indentLevel--; EditorGUILayout.Space(); EditorGUILayout.Space(); @@ -527,7 +532,7 @@ void DrawRendererListLayout(ReorderableList list, SerializedProperty prop) UpdateDefaultRendererValue(index, newIndex); }; } - + void UpdateDefaultRendererValue(int index) { // If the index that is being removed is lower than the default renderer value, diff --git a/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineCameraEditor.cs b/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineCameraEditor.cs index b5a8b52e2cb..17e068f6c03 100644 --- a/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineCameraEditor.cs +++ b/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineCameraEditor.cs @@ -40,11 +40,12 @@ static class Styles public static GUIContent allowHDR = EditorGUIUtility.TrTextContent("HDR", "High Dynamic Range gives you a wider range of light intensities, so your lighting looks more realistic. With it, you can still see details and experience less saturation even with bright light.", (Texture) null); public static GUIContent priority = EditorGUIUtility.TrTextContent("Priority", "A camera with a higher priority is drawn on top of a camera with a lower priority [ -100, 100 ]."); public static GUIContent clearDepth = EditorGUIUtility.TrTextContent("Clear Depth", "If enabled, depth from the previous camera will be cleared."); - public static GUIContent rendererType = EditorGUIUtility.TrTextContent("Renderer", "Controls which renderer this camera uses."); - public static GUIContent volumeLayerMask = EditorGUIUtility.TrTextContent("Volume Mask", "This camera will only be affected by volumes in the selected scene-layers."); - public static GUIContent volumeTrigger = EditorGUIUtility.TrTextContent("Volume Trigger", "A transform that will act as a trigger for volume blending. If none is set, the camera itself will act as a trigger."); + public static GUIContent volumesSettingsText = EditorGUIUtility.TrTextContent("Volumes", "These settings define how Volumes affect this Camera."); + public static GUIContent volumeLayerMask = EditorGUIUtility.TrTextContent("Mask", "This Camera is only affected by Volumes in the Layers that are assigned to the Camera."); + public static GUIContent volumeTrigger = EditorGUIUtility.TrTextContent("Trigger", "A Transform component that acts as a trigger for Volume blending. If none is set, the Camera itself acts as a trigger."); + public static GUIContent volumeUpdates = EditorGUIUtility.TrTextContent("Update Mode", "Select how Unity updates Volumes: every frame or when triggered via scripting. In the Editor, Unity updates Volumes every frame when not in the Play mode."); public static GUIContent renderPostProcessing = EditorGUIUtility.TrTextContent("Post Processing", "Enable this to make this camera render post-processing effects."); public static GUIContent antialiasing = EditorGUIUtility.TrTextContent("Anti-aliasing", "The anti-aliasing method to use."); @@ -138,6 +139,7 @@ static class Styles SerializedProperty m_AdditionalCameraDataCameras; SerializedProperty m_AdditionalCameraDataVolumeLayerMask; SerializedProperty m_AdditionalCameraDataVolumeTrigger; + SerializedProperty m_AdditionalCameraDataVolumeFrameworkUpdateMode; SerializedProperty m_AdditionalCameraDataRenderPostProcessing; SerializedProperty m_AdditionalCameraDataAntialiasing; SerializedProperty m_AdditionalCameraDataAntialiasingQuality; @@ -415,6 +417,7 @@ void init(List additionalCameraData) m_AdditionalCameraDataRendererProp = m_AdditionalCameraDataSO.FindProperty("m_RendererIndex"); m_AdditionalCameraDataVolumeLayerMask = m_AdditionalCameraDataSO.FindProperty("m_VolumeLayerMask"); m_AdditionalCameraDataVolumeTrigger = m_AdditionalCameraDataSO.FindProperty("m_VolumeTrigger"); + m_AdditionalCameraDataVolumeFrameworkUpdateMode = m_AdditionalCameraDataSO.FindProperty("m_VolumeFrameworkUpdateModeOption"); m_AdditionalCameraDataRenderPostProcessing = m_AdditionalCameraDataSO.FindProperty("m_RenderPostProcessing"); m_AdditionalCameraDataAntialiasing = m_AdditionalCameraDataSO.FindProperty("m_Antialiasing"); m_AdditionalCameraDataAntialiasingQuality = m_AdditionalCameraDataSO.FindProperty("m_AntialiasingQuality"); @@ -759,29 +762,30 @@ void DrawTargetTexture(UniversalRenderPipelineAsset rpAsset) void DrawVolumes() { - bool hasChanged = false; - LayerMask selectedVolumeLayerMask; - Transform selectedVolumeTrigger; - if (m_AdditionalCameraDataSO == null) - { - selectedVolumeLayerMask = 1; // "Default" - selectedVolumeTrigger = null; - } - else - { - selectedVolumeLayerMask = m_AdditionalCameraDataVolumeLayerMask.intValue; - selectedVolumeTrigger = (Transform)m_AdditionalCameraDataVolumeTrigger.objectReferenceValue; - } + // Display the Volume Update mode, LayerMask and Trigger + LayerMask selectedVolumeLayerMask = m_AdditionalCameraDataVolumeLayerMask.intValue; + Transform selectedVolumeTrigger = (Transform)m_AdditionalCameraDataVolumeTrigger.objectReferenceValue; - hasChanged |= DrawLayerMask(m_AdditionalCameraDataVolumeLayerMask, ref selectedVolumeLayerMask, Styles.volumeLayerMask); - hasChanged |= DrawObjectField(m_AdditionalCameraDataVolumeTrigger, ref selectedVolumeTrigger, Styles.volumeTrigger); + EditorGUILayout.LabelField(Styles.volumesSettingsText, EditorStyles.boldLabel); - if (hasChanged) + EditorGUI.indentLevel++; + + EditorGUI.BeginChangeCheck(); + DrawLayerMask(m_AdditionalCameraDataVolumeLayerMask, ref selectedVolumeLayerMask, Styles.volumeLayerMask); + DrawObjectField(m_AdditionalCameraDataVolumeTrigger, ref selectedVolumeTrigger, Styles.volumeTrigger); + EditorGUILayout.PropertyField(m_AdditionalCameraDataVolumeFrameworkUpdateMode, Styles.volumeUpdates); + + if (EditorGUI.EndChangeCheck()) { m_AdditionalCameraDataVolumeLayerMask.intValue = selectedVolumeLayerMask; m_AdditionalCameraDataVolumeTrigger.objectReferenceValue = selectedVolumeTrigger; + + VolumeFrameworkUpdateMode curVolumeUpdateMode = (VolumeFrameworkUpdateMode)m_AdditionalCameraDataVolumeFrameworkUpdateMode.intValue; + camera.SetVolumeFrameworkUpdateMode(curVolumeUpdateMode); + m_AdditionalCameraDataSO.ApplyModifiedProperties(); } + EditorGUI.indentLevel--; } void DrawRenderer(UniversalRenderPipelineAsset rpAsset) diff --git a/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs b/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs index 8442d616af9..f712a707324 100644 --- a/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.universal/Runtime/Data/UniversalRenderPipelineAsset.cs @@ -95,6 +95,19 @@ public enum ColorGradingMode HighDynamicRange } + /// + /// Defines the update frequency for the Volume Framework. + /// + public enum VolumeFrameworkUpdateMode + { + [InspectorName("Every Frame")] + EveryFrame = 0, + [InspectorName("Via Scripting")] + ViaScripting = 1, + [InspectorName("Use Pipeline Settings")] + UsePipelineSettings = 2, + } + [ExcludeFromPreset] public partial class UniversalRenderPipelineAsset : RenderPipelineAsset, ISerializationCallbackReceiver { @@ -168,6 +181,7 @@ public partial class UniversalRenderPipelineAsset : RenderPipelineAsset, ISerial [SerializeField] ShadowResolution m_ShadowAtlasResolution = ShadowResolution._256; [SerializeField] ShaderVariantLogLevel m_ShaderVariantLogLevel = ShaderVariantLogLevel.Disabled; + [SerializeField] VolumeFrameworkUpdateMode m_VolumeFrameworkUpdateMode = VolumeFrameworkUpdateMode.EveryFrame; // Note: A lut size of 16^3 is barely usable with the HDR grading mode. 32 should be the // minimum, the lut being encoded in log. Lower sizes would work better with an additional @@ -659,6 +673,11 @@ public ShaderVariantLogLevel shaderVariantLogLevel set { m_ShaderVariantLogLevel = value; } } + /// + /// Returns the selected update mode for volumes. + /// + public VolumeFrameworkUpdateMode volumeFrameworkUpdateMode => m_VolumeFrameworkUpdateMode; + [Obsolete("PipelineDebugLevel is deprecated. Calling debugLevel is not necessary.", false)] public PipelineDebugLevel debugLevel { diff --git a/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs b/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs index eede40c3737..af3aed96cd5 100644 --- a/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs +++ b/com.unity.render-pipelines.universal/Runtime/UniversalAdditionalCameraData.cs @@ -6,6 +6,7 @@ using UnityEngine.Serialization; using UnityEngine.Rendering; using System.ComponentModel; +using UnityEngine.Assertions; namespace UnityEngine.Rendering.LWRP { @@ -82,7 +83,7 @@ public static class CameraExtensions /// This method returns the additional data component for the given camera or create one if it doesn't exists yet. /// /// - /// The UniversalAdditinalCameraData for this camera. + /// The UniversalAdditionalCameraData for this camera. /// public static UniversalAdditionalCameraData GetUniversalAdditionalCameraData(this Camera camera) { @@ -93,6 +94,137 @@ public static UniversalAdditionalCameraData GetUniversalAdditionalCameraData(thi return cameraData; } + + /// + /// Returns the VolumeFrameworkUpdateMode set on the camera. + /// + /// + /// + public static VolumeFrameworkUpdateMode GetVolumeFrameworkUpdateMode(this Camera camera) + { + UniversalAdditionalCameraData cameraData = camera.GetUniversalAdditionalCameraData(); + return cameraData.volumeFrameworkUpdateMode; + } + + /// + /// Sets the VolumeFrameworkUpdateMode for the camera. + /// + /// + /// + public static void SetVolumeFrameworkUpdateMode(this Camera camera, VolumeFrameworkUpdateMode mode) + { + UniversalAdditionalCameraData cameraData = camera.GetUniversalAdditionalCameraData(); + if (cameraData.volumeFrameworkUpdateMode == mode) + { + return; + } + + bool requiredUpdatePreviously = cameraData.requiresVolumeFrameworkUpdate; + cameraData.volumeFrameworkUpdateMode = mode; + + // We only update the local volume stacks for cameras set to ViaScripting. + // Otherwise it will be updated in every frame. + // We also check the previous value to make sure we're not updating when + // switching between Camera ViaScripting and the URP Asset set to ViaScripting + if (requiredUpdatePreviously && !cameraData.requiresVolumeFrameworkUpdate) + { + camera.UpdateVolumeStack(cameraData); + } + } + + /// + /// Updates the volume stack for this camera. + /// This function will only update the stack when the camera has VolumeFrameworkUpdateMode set to ViaScripting + /// or when it set to UsePipelineSettings and the update mode on the Render Pipeline Asset is set to ViaScripting. + /// + /// + public static void UpdateVolumeStack(this Camera camera) + { + UniversalAdditionalCameraData cameraData = camera.GetUniversalAdditionalCameraData(); + camera.UpdateVolumeStack(cameraData); + } + + /// + /// Updates the volume stack for this camera. + /// This function will only update the stack when the camera has ViaScripting selected or if + /// the camera is set to UsePipelineSettings and the Render Pipeline Asset is set to ViaScripting. + /// + /// + /// + public static void UpdateVolumeStack(this Camera camera, UniversalAdditionalCameraData cameraData) + { + Assert.IsNotNull(cameraData, "cameraData can not be null when updating the volume stack."); + + // We only update the local volume stacks for cameras set to ViaScripting. + // Otherwise it will be updated in the frame. + if (cameraData.requiresVolumeFrameworkUpdate) + { + return; + } + + // Create stack for camera + if (cameraData.volumeStack == null) + { + cameraData.volumeStack = VolumeManager.instance.CreateStack(); + } + + camera.GetVolumeLayerMaskAndTrigger(cameraData, out LayerMask layerMask, out Transform trigger); + VolumeManager.instance.Update(cameraData.volumeStack, trigger, layerMask); + } + + /// + /// Destroys the volume stack for this camera. + /// + /// + public static void DestroyVolumeStack(this Camera camera) + { + UniversalAdditionalCameraData cameraData = camera.GetUniversalAdditionalCameraData(); + camera.DestroyVolumeStack(cameraData); + } + + /// + /// Destroys the volume stack for this camera. + /// + /// + /// + public static void DestroyVolumeStack(this Camera camera, UniversalAdditionalCameraData cameraData) + { + cameraData.volumeStack.Dispose(); + cameraData.volumeStack = null; + } + + /// + /// Returns the mask and trigger assigned for volumes on the camera. + /// + /// + /// + /// + /// + internal static void GetVolumeLayerMaskAndTrigger(this Camera camera, UniversalAdditionalCameraData cameraData, out LayerMask layerMask, out Transform trigger) + { + // Default values when there's no additional camera data available + layerMask = 1; // "Default" + trigger = camera.transform; + + if (cameraData != null) + { + layerMask = cameraData.volumeLayerMask; + trigger = (cameraData.volumeTrigger != null) ? cameraData.volumeTrigger : trigger; + } + else if (camera.cameraType == CameraType.SceneView) + { + // Try to mirror the MainCamera volume layer mask for the scene view - do not mirror the target + var mainCamera = Camera.main; + UniversalAdditionalCameraData mainAdditionalCameraData = null; + + if (mainCamera != null && mainCamera.TryGetComponent(out mainAdditionalCameraData)) + { + layerMask = mainAdditionalCameraData.volumeLayerMask; + } + + trigger = (mainAdditionalCameraData != null && mainAdditionalCameraData.volumeTrigger != null) ? mainAdditionalCameraData.volumeTrigger : trigger; + } + } } static class CameraTypeUtility @@ -128,6 +260,7 @@ public static string GetName(this CameraRenderType type) [SerializeField] LayerMask m_VolumeLayerMask = 1; // "Default" [SerializeField] Transform m_VolumeTrigger = null; + [SerializeField] VolumeFrameworkUpdateMode m_VolumeFrameworkUpdateModeOption = VolumeFrameworkUpdateMode.UsePipelineSettings; [SerializeField] bool m_RenderPostProcessing = false; [SerializeField] AntialiasingMode m_Antialiasing = AntialiasingMode.None; @@ -336,18 +469,59 @@ public void SetRenderer(int index) m_RendererIndex = index; } + /// + /// Returns the selected scene-layers affecting this camera. + /// public LayerMask volumeLayerMask { get => m_VolumeLayerMask; set => m_VolumeLayerMask = value; } + /// + /// Returns the Transform that acts as a trigger for Volume blending. + /// public Transform volumeTrigger { get => m_VolumeTrigger; set => m_VolumeTrigger = value; } + /// + /// Returns the selected mode for Volume Frame Updates. + /// + internal VolumeFrameworkUpdateMode volumeFrameworkUpdateMode + { + get => m_VolumeFrameworkUpdateModeOption; + set => m_VolumeFrameworkUpdateModeOption = value; + } + + /// + /// Returns true if this camera requires the volume framework to be updated every frame. + /// + public bool requiresVolumeFrameworkUpdate + { + get + { + if (m_VolumeFrameworkUpdateModeOption == VolumeFrameworkUpdateMode.UsePipelineSettings) + { + return UniversalRenderPipeline.asset.volumeFrameworkUpdateMode != VolumeFrameworkUpdateMode.ViaScripting; + } + + return m_VolumeFrameworkUpdateModeOption == VolumeFrameworkUpdateMode.EveryFrame; + } + } + + /// + /// Returns the current volume stack used by this camera. + /// + VolumeStack m_VolumeStack = null; + public VolumeStack volumeStack + { + get => m_VolumeStack; + set => m_VolumeStack = value; + } + /// /// Returns true if this camera should render post-processing. /// @@ -377,12 +551,18 @@ public AntialiasingQuality antialiasingQuality set => m_AntialiasingQuality = value; } + /// + /// Returns true if this camera should automatically replace NaN/Inf in shaders by a black pixel to avoid breaking some effects. + /// public bool stopNaN { get => m_StopNaN; set => m_StopNaN = value; } + /// + /// Returns true if this camera applies 8-bit dithering to the final render to reduce color banding + /// public bool dithering { get => m_Dithering; diff --git a/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs b/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs index 5c6101eb8b1..b3b89a37d0f 100644 --- a/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs +++ b/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs @@ -191,7 +191,7 @@ protected override void Dispose(bool disposing) } #if UNITY_2021_1_OR_NEWER - protected override void Render(ScriptableRenderContext renderContext, Camera[] cameras) + protected override void Render(ScriptableRenderContext renderContext, Camera[] cameras) { Render(renderContext, new List(cameras)); } @@ -595,29 +595,43 @@ static void UpdateVolumeFramework(Camera camera, UniversalAdditionalCameraData a { using var profScope = new ProfilingScope(null, ProfilingSampler.Get(URPProfileId.UpdateVolumeFramework)); - // Default values when there's no additional camera data available - LayerMask layerMask = 1; // "Default" - Transform trigger = camera.transform; + // We update the volume framework for: + // * All cameras in the editor when not in playmode + // * scene cameras + // * cameras with update mode set to EveryFrame + // * cameras with update mode set to UsePipelineSettings and the URP Asset set to EveryFrame + bool shouldUpdate = camera.cameraType == CameraType.SceneView; + shouldUpdate |= additionalCameraData != null && additionalCameraData.requiresVolumeFrameworkUpdate; + + #if UNITY_EDITOR + shouldUpdate |= Application.isPlaying == false; + #endif - if (additionalCameraData != null) + // When we have volume updates per-frame disabled... + if (!shouldUpdate && additionalCameraData) { - layerMask = additionalCameraData.volumeLayerMask; - trigger = additionalCameraData.volumeTrigger != null - ? additionalCameraData.volumeTrigger - : trigger; + // Create a local volume stack and cache the state if it's null + if (additionalCameraData.volumeStack == null) + { + camera.UpdateVolumeStack(additionalCameraData); + } + + VolumeManager.instance.stack = additionalCameraData.volumeStack; + return; } - else if (camera.cameraType == CameraType.SceneView) - { - // Try to mirror the MainCamera volume layer mask for the scene view - do not mirror the target - var mainCamera = Camera.main; - UniversalAdditionalCameraData mainAdditionalCameraData = null; - if (mainCamera != null && mainCamera.TryGetComponent(out mainAdditionalCameraData)) - layerMask = mainAdditionalCameraData.volumeLayerMask; + // When we want to update the volumes every frame... - trigger = mainAdditionalCameraData != null && mainAdditionalCameraData.volumeTrigger != null ? mainAdditionalCameraData.volumeTrigger : trigger; + // We destroy the volumeStack in the additional camera data, if present, to make sure + // it gets recreated and initialized if the update mode gets later changed to ViaScripting... + if (additionalCameraData && additionalCameraData.volumeStack != null) + { + camera.DestroyVolumeStack(additionalCameraData); } + // Get the mask + trigger and update the stack + camera.GetVolumeLayerMaskAndTrigger(additionalCameraData, out LayerMask layerMask, out Transform trigger); + VolumeManager.instance.ResetMainStack(); VolumeManager.instance.Update(trigger, layerMask); }