Change shadow resolution from script

Dear community and unity team,

I’m trying to build a settings screen for our game and would like to have individual settings for anti aliasing and shadow resolution that would need to be set from a script class.

I tried to achieve this using the UniversalRenderPipelineAsset provided by GraphicsSettings.renderPipelineAsset, but it does not have a setter for the mainLightShadowmapResolution. My guess is that this would also not be the intended way of doing this.

One the other side, having custom UniversalRenderPipelineAsset for the different shadow resolutions would also override all the other settings provided by the asset (e.g. the anti aliasing).

Is there another (intended) way to change the shadow map resolution?

2 Likes

We have the same question. What is the correct way to change Quality settings using URP?
We know that we can prepare Quality Levels with different assets and change Levels at runtime, but what about specific Quality settings? How can we change them, e.g. enable/disable shadows? UniversalRenderPipelineAsset.supportsMainLightShadows also has only getter.

You always can change the shadow resolution for each light component individually. Just create a script with an array and list all light components of thescene in it and change the desired parameters.

@Bordeaux_Fox Tried it, but does not work.
The Light.shadowResolution param does not seem to be used by the Universal Render Pipeline.

The SRP lights have their own additional parameters. For example, in HDRP for every light component there is a HDAdditionalLightData script with the new parameters inside. They also have their own shadowManager method. But this stuff is not so documented.

Hm… Looks like the light only comes with an UniversalAdditionalLightData object and this does not have any properties related to shadows or something similar.

3 Likes

Hi Unity team,

any suggestions on how to deal with this? How can we allow our users to independently configure shadow quality and anti aliasing quality?

3 Likes

Yeah, encapsulation is most terrible paradigm in OOP.

I would like to know how to change shadow resolution from script as well.

UniversalRenderPipelineAsset.mainLightShadowmapResolution seems like the obvious solution, but that property has no setter.

Same goes for UniversalRenderPipelineAsset.supportsMainLightShadows for toggling shadows on and off entirely.

3 Likes

We should enable setter for main light shadow resolution. Will add that to our backlog.

About the support for main light shadow we prevent that to be changed at runtime as we use that at build time to strip shader variants.

The way to configure quality is to configure pipeline assets per quality tier / platform and swap them at runtime.

5 Likes

Do you have an ETA for changing shadow resolution at runtime?

I find it frankly ridiculous that URP does not allow you to toggle shadows globally at runtime. This is a regression from Built-In, where you could do the following:

QualitySettings.shadows = ShadowQuality.Disable;

Shadow enable/disable is a very important graphics setting to have for low-end users, as shadows are quite expensive to render. I would be 10000% comfortable with giving up automatic shader variant stripping if it meant I got this feature back.

Swapping pipeline assets is not a solution, because that requires changing all the settings at once. You’d have me make thousands of pipeline assets for each individual configuration a user might choose?

7 Likes

Another URP option that really should be changeable from script, but isn’t: Shadow Cascade splits (cascade2Split and cascade4Split)

2 Likes

We have to do a pass on this API to review what we can expose. For now, to disable shadows you can set the shadowDistance to 0.

4 Likes

And what about the per-light shadow quality that is no longer there?

1 Like

Would just like to add:

Most SRP settings probably are fine being bundled together, but it makes no sense that shadow quality and anti-aliasing quality are coupled like that. Any serious game/application would let the user configure them individually. To support that with the current setup would require 9 different pipeline assets just to have 3 shadow quality levels and 3 anti-aliasing levels, and exponentially more if you want to tweak other settings.
Fingers crossed this can be exposed to script!

5 Likes

@phil_lira How does swapping the pipeline assets at runtime work in regards to stripping shader variants?
Example:

  • In Graphics Settings, set the “main pipeline asset”.
  • For a lower end platform, create a custom Quality tier and override the pipeline asset in the quality tier.
    → How does the stripping work here? From what I can see, stripping will be done based on the “main pipeline asset”.
    If this is true, there is no way right now to strip variants per platform.
    Second example:
  • In Graphics Settings, set the “default pipeline asset” but it doesn’t have all features. (no shadows from additional lights for example)
  • In Quality Settings, create an “Ultra” tier with shadows from additional lights. If we now go from default to ultra, the shader variants for shadows from additional lights will have been stripped. How will that behave?

Thanks

4 Likes

We used to consider only the main pipeline asset in graphics settings. In 2020.1 it collects all features from all pipeline assets in quality settings + graphics settings and strip based on that.

I think this behaviour is to be backported to 2019 LTS, I have to confirm it though if it has landed or not.

Thank you @phil_lira .
To maximize stripping, Should we then put the pipeline asset with the least amount of features in the graphics settings?
For example if you target both PC and mobile and you have a different pipeline asset per platform, you probably want to put the mobile one, otherwise you will include the PC features in your mobile build?

In general, why is there a main pipeline asset in graphics settings? What is the advantage of that over using the pipeline asset from the current quality setting?

Thanks

1 Like

Until a setter is implemented for mainLightShadowmapResolution, you can use reflection to set the value. I’m doing this in Editor and on Android; it works fine.

using System.Reflection;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using ShadowResolution = UnityEngine.Rendering.Universal.ShadowResolution;

public partial class SROptions
{
    private System.Type universalRenderPipelineAssetType;
    private FieldInfo mainLightShadowmapResolutionFieldInfo;

    private void InitializeShadowMapFieldInfo()
    {
        universalRenderPipelineAssetType = (GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset).GetType();
        mainLightShadowmapResolutionFieldInfo = universalRenderPipelineAssetType.GetField("m_MainLightShadowmapResolution", BindingFlags.Instance | BindingFlags.NonPublic);
    }
   
    public ShadowResolution MainLightShadowResolution
    {
        get
        {
            if (mainLightShadowmapResolutionFieldInfo == null)
            {
                InitializeShadowMapFieldInfo();
            }
            return (ShadowResolution) mainLightShadowmapResolutionFieldInfo.GetValue(GraphicsSettings.currentRenderPipeline);
        }
        set
        {
            if (mainLightShadowmapResolutionFieldInfo == null)
            {
                InitializeShadowMapFieldInfo();
            }
            mainLightShadowmapResolutionFieldInfo.SetValue(GraphicsSettings.currentRenderPipeline, value);
        }
    }
}
12 Likes