Change HDRP settings (Shadows, realtime lights) at runtime

I’m trying to add some functionality where major rendering functionality is toggled dynamically at runtime. Two examples of this are rendering shadows, and rendering realtime lighting.

I’ve found some working examples of how to override the settings in individual camera to enable or disable shadows, but so far I haven’t found a way to turn on/off shadows in HDRP as a whole. I would have imagined it would be something like this:

var renderPipelineAsset = Instantiate(GraphicsSettings.renderPipelineAsset) as HDRenderPipelineAsset;
var renderPipelineFrameSettings = renderPipelineAsset.GetDefaultFrameSettings(FrameSettingsRenderType.Camera);
renderPipelineFrameSettings.SetEnabled(FrameSettingsField.Shadow, false);
GraphicsSettings.renderPipelineAsset = renderPipelineAsset;

That just produces an error in UnityEngine.Experimental.Rendering.HDPipeline.FrameSettingsHistory.AggregateFrameSettings.

Is it possible to turn shadows on/off as a whole, at runtime? Ideally I could do this in order to improve performance by not having shadows running in HDRP at all under certain conditions.

The other question is whether it’s possible to instruct HDRP not to render realtime lighting? There are cases where I only want the baked lighting contribution to be applied, without any realtime lighting being rendered. It’s pretty cumbersome to have to find all lights in a scene, and turn then on/off depending on whether I want realtime lights rendering, as it means I need to keep track of whether the light was turned on/off by something else in the process. I was hoping there was just some setting/override to disable realtime lighting entirely runtime.

Thanks.

1 Like

I didn’t get anywhere trying to change the HDRP settings themselves, but it seems that overriding the settings on each camera is simple enough, and has the same performance characteristics.

As for turning off realtime lights at runtime, I tried that setting their Light Layer to Nothing, to see if it was similar in performance to actually turning off the light. But it’s still much more performant to turn off the light itself. So, unless I find some way to disable realtime lights globally, I’ll probably end up going with some process where I manually enable/disable all lights.

2 Likes

ever work this out? i just want to turn on and off effects during runtime

Yeah. I’m still on HDRP 7, so not sure how different it is in newer versions. But I change all sorts of HDRP settings at runtime based on user options.

There are two main parameters: a VolumeProfile (which contains all of the post-processing and effects) and the HDAdditionalCameraData from the camera you’re using (probably Camera.main), as some settings are applied to the camera itself. Hopefully this gives you a general sense of how you can do this kind of stuff.

All the references you see to “GraphicsPlayerOptions” in this code is just the class I save all the player’s graphics choices into.

        public void ApplyGraphicsSettings(VolumeProfile sceneSettingsProfile, HDAdditionalCameraData hdCameraData, bool shouldAdjustHDCameraOverrides = true)
        {
            // Used for diagnostics.
            var startTime = DateTime.Now;

            // Apply screen resolution change
            if (Screen.currentResolution.height != GraphicsPlayerOptions.ScreenResolutionHeight
                || Screen.currentResolution.width != GraphicsPlayerOptions.ScreenResolutionWidth
                || Screen.currentResolution.refreshRate != GraphicsPlayerOptions.ScreenRefreshRate
                || Screen.fullScreenMode != GraphicsPlayerOptions.FullScreenMode)
            {
                //Debug.Log($"Changing Screen Resolution to {GraphicsSettings.ScreenResolution.Width} x {GraphicsSettings.ScreenResolution.Height} {(GraphicsPlayerOptions.FullScreen ? "FullScreen" : "Windowed")}");
                ScreenUtil.SetScreenResolution(GameSettingsDirector.Instance.GraphicsPlayerOptions);
            }


            // Apply quality change
            if (QualitySettings.GetQualityLevel() != GraphicsPlayerOptions.GraphicsQualityIndex)
            {
                // Use the lower of the two. This is done in case the quality is set to a very high number
                // that isn't available on the target system.
                var qualityIndex = Mathf.Min(GraphicsPlayerOptions.GraphicsQualityIndex, QualitySettings.names.Length - 1);

                //Debug.Log($"Changing quality level to {GraphicsSettings.GraphicsQualityIndex}");
                QualitySettings.SetQualityLevel(qualityIndex, true);
            }

            // V-Sync.
            QualitySettings.vSyncCount = GraphicsPlayerOptions.EnableVSync ? 1 : 0;

            // When not using VSync, set target framerate to 60 to avoid inefficient rendering.
            Application.targetFrameRate = GraphicsPlayerOptions.TargetFrameRate == 0 ? -1 : GraphicsPlayerOptions.TargetFrameRate;

            if (hdCameraData != null && hdCameraData.gameObject.GetComponent<SupportsCustomFOV>() != null)
            {
                hdCameraData.gameObject.GetComponent<Camera>().fieldOfView = Mathf.Clamp(GraphicsPlayerOptions.FieldOfView, GraphicsConstants.MinFOV, GraphicsConstants.MaxFOV);
            }

            // SRP Batching
            GraphicsSettings.useScriptableRenderPipelineBatching = GraphicsPlayerOptions.EnableSRPBatching;

            if (sceneSettingsProfile != null)
            {
                var ambientOcclusionComponent = sceneSettingsProfile.GetComponent<AmbientOcclusion>();
                if (ambientOcclusionComponent != null)
                {
                    //Debug.Log($"Setting Use Ambient Occlusion to {GraphicsSettings.UsePostProcessingAmbientOcclusion}");
                    if (GraphicsPlayerOptions.AmbientOcclusionQuality == LowMediumHighOff.Off)
                    {
                        ambientOcclusionComponent.active = false;
                    }
                    else
                    {
                        ambientOcclusionComponent.active = true;
                        // Accepted values are 0, 1, 2, but our enum's values are 1, 2, 3 respectively.
                        ambientOcclusionComponent.quality.Override((int)GraphicsPlayerOptions.AmbientOcclusionQuality - 1);
                    }

                }

                var bloomComponent = sceneSettingsProfile.GetComponent<Bloom>();
                if (bloomComponent != null)
                {
                    //Debug.Log($"Setting Use Ambient Occlusion to {GraphicsSettings.UsePostProcessingAmbientOcclusion}");
                    bloomComponent.active = GraphicsPlayerOptions.EnableBloom;
                }

                var motionBlurComponent = sceneSettingsProfile.GetComponent<MotionBlur>();
                if (motionBlurComponent != null)
                {
                    if (GraphicsPlayerOptions.MotionBlurQuality == LowMediumHighOff.Off)
                    {
                        motionBlurComponent.active = false;
                    }
                    else
                    {
                        motionBlurComponent.active = true;
                        // Accepted values are 0, 1, 2, but our enum's values are 1, 2, 3 respectively.
                        motionBlurComponent.quality.Override((int)GraphicsPlayerOptions.MotionBlurQuality - 1);
                    }

                }

                var tonemappingComponent = sceneSettingsProfile.GetComponent<Tonemapping>();
                if (tonemappingComponent != null)
                {
                    tonemappingComponent.active = GraphicsPlayerOptions.EnableTonemappping;
                }

                var liftGammaGainComponent = sceneSettingsProfile.GetComponent<LiftGammaGain>();
                if (liftGammaGainComponent != null)
                {
                    // The gamma value we receive is normalized, where 0 represents darkest and 1 is brightest.
                    // 0.5 represents "normal", or a value of "1" in PPS2. So, we denormalize the value here
                    // to give it a suitable range.
                    //Debug.Log(liftGammaGainComponent.gamma.value);
                    liftGammaGainComponent.gamma.Override(new Vector4(1, 1, 1, DenormalizedGamma(Mathf.Clamp(GraphicsPlayerOptions.NormalizedGamma, 0, 1))));
                }


                SetShadowDistance(sceneSettingsProfile, GraphicsPlayerOptions.ShadowDistance);


                //Debug.Log($"AO: {ambientOcclusionComponent.quality.value}; MB: {motionBlurComponent.quality.value}");
            }
            else
            {
                // This is the case where no settings have been provided, which means we should look in the
                // scene for volume profiles to adjust settings
                // foreach (var volumeKeeper in GameObject.FindObjectsOfType<VolumeKeeper>())
                // {
                //     var volumeProfile = volumeKeeper.Volume.profile;
                //
                //     var exposure = volumeProfile.GetComponent<Exposure>();
                //     if (exposure != null)
                //     {
                //         exposure.mode.Override(GraphicsPlayerOptions.EnableDynamicExposure ? ExposureMode.Automatic : ExposureMode.Fixed);
                //     }
                // }
            }



            if (hdCameraData != null && shouldAdjustHDCameraOverrides)
            {
                if (hdCameraData.antialiasing != GraphicsPlayerOptions.Antialiasing)
                {
                    //Debug.Log($"Setting Anti-aliasing to to {GraphicsSettings.Antialiasing}");
                    hdCameraData.antialiasing = GraphicsPlayerOptions.Antialiasing;

                    // If using SMAA, make sure quality is set to High.
                    if (GraphicsPlayerOptions.Antialiasing == HDAdditionalCameraData.AntialiasingMode.SubpixelMorphologicalAntiAliasing)
                    {
                        hdCameraData.SMAAQuality = HDAdditionalCameraData.SMAAQualityLevel.High;
                    }
                }



                // This should probably already be enabled, but just to be safe. This is the "left" checkbox in the
                // camera settings, which controls whether to consider the override value. This is always true, even
                // when disable shadows, as it controls whether we're allowed to enable/disable shadows.
                var frameSettingsOverrideMask = hdCameraData.renderingPathCustomFrameSettingsOverrideMask;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.ShadowMaps] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.Distortion] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.AtmosphericScattering] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.Volumetrics] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.LightLayers] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.ReflectionProbe] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.SSAO] = true;
                frameSettingsOverrideMask.mask[(uint)FrameSettingsField.ReplaceDiffuseForIndirect] = true; // See below


                // It's in the frame settings that we actually enable or disable the shadows.
                var frameSettings = hdCameraData.renderingPathCustomFrameSettings;
                frameSettings.SetEnabled(FrameSettingsField.ShadowMaps, CamerasShouldRenderShadows());
                frameSettings.SetEnabled(FrameSettingsField.Distortion, GraphicsPlayerOptions.EnableDistortion);
                // Atmospheric Scatter (Fog) and Volumetrics are controlled by the same option.
                frameSettings.SetEnabled(FrameSettingsField.AtmosphericScattering, GraphicsPlayerOptions.EnableVolumetrics);
                frameSettings.SetEnabled(FrameSettingsField.Volumetrics, GraphicsPlayerOptions.EnableVolumetrics);
                frameSettings.SetEnabled(FrameSettingsField.LightLayers, GraphicsPlayerOptions.EnableLightLayers);
                frameSettings.SetEnabled(FrameSettingsField.ReflectionProbe, GraphicsPlayerOptions.EnableReflectionProbes);
                frameSettings.SetEnabled(FrameSettingsField.SSAO, GraphicsPlayerOptions.AmbientOcclusionQuality != LowMediumHighOff.Off);
                frameSettings.SetEnabled(FrameSettingsField.MotionBlur, GraphicsPlayerOptions.MotionBlurQuality != LowMediumHighOff.Off);
                // This setting causes metal objects to look less black when reflections are disabled. It looks much better.
                frameSettings.SetEnabled(FrameSettingsField.ReplaceDiffuseForIndirect, !GraphicsPlayerOptions.EnableReflectionProbes);


                // Applying the frame setting mask back to the camera
                hdCameraData.renderingPathCustomFrameSettingsOverrideMask = frameSettingsOverrideMask;
                hdCameraData.renderingPathCustomFrameSettings = frameSettings;

            }
        }
2 Likes

thank you!! I could turn them on but not change their variables. I needed “Override()” as shown in your code, rather than just setting the variable. AWESOME.

1 Like