Search Unity

Question Access Renderer Feature settings at runtime

Discussion in 'Shader Graph' started by tasticad, Nov 2, 2019.

  1. tasticad

    tasticad

    Joined:
    Dec 4, 2017
    Posts:
    10
    Hello everyone,

    Please can someone help me with that? How can I access the renderer setting of a Custom Renderer in Unity 2019.2?

    I would like for instance to switch the Comp value from Equal to Always at runtime:

    Unity_renderer_feature_settings.png
     
  2. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Some thing like this
    but works only in LWRP in URP not work anymore :(


    foreach ( var renderObjSetting in _scriptableRendererData.rendererFeatures.OfType<RenderObjects>( ) )
    {
    renderObjSetting.settings.cameraSettings.cameraFieldOfView = _currentFPSFov;
    renderObjSetting.settings.cameraSettings.offset = _currentFPSOffset;
    }

    Link to _scriptableRendererData store in [SerializedField]
     
  3. qwert024

    qwert024

    Joined:
    Oct 21, 2015
    Posts:
    43
    I was also wondering how I can access and modify renderer feature settings at runtime.
    I am trying to achieve that with the below code in 2019.3.3f1.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Rendering.Universal;
    5. using UnityEngine.Experimental.Rendering.Universal;
    6.  
    7. public class TestChangeRPValues : MonoBehaviour
    8. {
    9.     // Reference to the ForwardRendererData asset
    10.     public ForwardRendererData forwardRendererData;
    11.  
    12.     List<ScriptableRendererFeature> features;
    13.  
    14.     Pixelate pixelate;
    15.     [Range(1, 128)]
    16.     public int testPixelSize = 10;
    17.  
    18.     RenderObjects renderObjects;
    19.     public LayerMask testLayerMask;
    20.  
    21.     void Start()
    22.     {
    23.         // Reference to the render features on the ForwardRendererData
    24.         features = forwardRendererData.rendererFeatures;
    25.  
    26.         pixelate = (Pixelate)features[0];
    27.         renderObjects = (RenderObjects)features[1];
    28.     }
    29.  
    30.     void Update()
    31.     {
    32.         pixelate.settings.pixelSize = testPixelSize;
    33.         renderObjects.settings.filterSettings.LayerMask = testLayerMask;
    34.     }
    35. }
    36.  
    1st_Moment.jpg

    I want to modify "Pixel Size" and "Layer Mask" in the right inspector with my script. (Above image)
    The parameters seem to change only when my mouse hover on to the right inspector.
    Although the parameters in the right inspector did change, those settings were not applied to game view and scene view. (Below Video)

    If I directly modify the right inspector, those settings are applied successfully. (Below Video) However I need to modify them at runtime with scripts.


    What is the correct way to access and modify renderer feature settings at runtime?
    It would be so great if someone could shed some light on this!
     
    qsleonard likes this.
  4. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Currently in out project:

    Code (CSharp):
    1. private        void    ExtractScriptableRendererData()
    2. {
    3.     var pipeline = ((UniversalRenderPipelineAsset)GraphicsSettings.renderPipelineAsset);
    4.     FieldInfo propertyInfo = pipeline.GetType(  ).GetField( "m_RendererDataList", BindingFlags.Instance | BindingFlags.NonPublic );
    5.     _scriptableRendererData = ((ScriptableRendererData[]) propertyInfo?.GetValue( pipeline ))?[0];
    6. }

    Code (CSharp):
    1. foreach ( var renderObjSetting in _scriptableRendererData.rendererFeatures.OfType<UnityEngine.Experimental.Rendering.Universal.RenderObjects>( ) )
    2. {
    3.     renderObjSetting.settings.cameraSettings.cameraFieldOfView    = _currentFPSFov;
    4.     renderObjSetting.settings.cameraSettings.offset                = _currentFPSOffset;
    5. }
    Without this it dont work in builds at all.

    May be Last URP have some more direct way to access RenderObjects I dont know about.
    For now this code make us happy :)
     
    facundoponce, lang_fox and Pawciu like this.
  5. qwert024

    qwert024

    Joined:
    Oct 21, 2015
    Posts:
    43
    Thanks a lot! :)
     
  6. taynaTinoco

    taynaTinoco

    Joined:
    Jul 31, 2018
    Posts:
    6
    I'm doing the same thing, the values on my RenderObjects change, but it doesn't update my view.
    Here is my code:

    Code (CSharp):
    1.  void Start()
    2.     {
    3.         ExtractScriptableRendererData();
    4.     }
    5.  
    6.     private void LateUpdate()
    7.     {
    8.         if (Input.GetKeyDown(KeyCode.Space))
    9.             ChangeStencil();
    10.     }
    11.  
    12.     private void ExtractScriptableRendererData()
    13.     {
    14.         var pipeline = ((UniversalRenderPipelineAsset)GraphicsSettings.renderPipelineAsset);
    15.         FieldInfo propertyInfo = pipeline.GetType().GetField("m_RendererDataList", BindingFlags.Instance | BindingFlags.NonPublic);
    16.         _scriptableRendererData = ((ScriptableRendererData[])propertyInfo?.GetValue(pipeline))?[0];
    17.         renderObjects = (RenderObjects)_scriptableRendererData.rendererFeatures[0];
    18.         renderObjects.settings.stencilSettings.stencilCompareFunction = CompareFunction.Equal;
    19.        
    20.  
    21.     }
    22.  
    23.     private void ChangeStencil()
    24.     {
    25.          renderObjects.settings.stencilSettings.stencilCompareFunction = CompareFunction.NotEqual;      
    26.      
    27.     }
     
    AndyKorth and PatHightreeXVR like this.
  7. IggyZuk

    IggyZuk

    Joined:
    Jan 17, 2015
    Posts:
    43
    When you modify a value inside of a ScriptableRendererFeature you have to call ScriptableRendererData.SetDirty(); to indicate that something was changed.

    Example:
    Code (CSharp):
    1. [SerializeField] ForwardRendererData rendererData;
    2.  
    3. var blurFeature = rendererData.rendererFeatures.OfType<MobileBlurUrp>().FirstOrDefault();
    4.  
    5. if (blurFeature == null) return;
    6.      
    7. blurFeature.settings.BlurAmount = value;
    8.  
    9. rendererData.SetDirty();
     
  8. marcosroque

    marcosroque

    Joined:
    Oct 31, 2016
    Posts:
    2
    Short and precise, worked perfectly. Thank you!
     
  9. tomekkie2

    tomekkie2

    Joined:
    Jul 6, 2012
    Posts:
    973
    How would you code stencil facing?
    If you need to get an equivalent of CompFront or CompBack instead of Comp.
     
  10. Liderangel

    Liderangel

    Joined:
    Jul 8, 2018
    Posts:
    101

    While this works it also means that you are modifying the assets in your hard drive. The idea would be to modify them as instances, so that when you stop play mode they go back to how they were. I'm still figuring out how to.
     
  11. akilar1002

    akilar1002

    Joined:
    Jul 18, 2016
    Posts:
    70
  12. Mashimaro7

    Mashimaro7

    Joined:
    Apr 10, 2020
    Posts:
    727
    For anyone that finds this, i'm not sure if Unity made this easier recently or what, but you can just add the render feature's scriptable object as a class, and access it's variables directly, it's surprisingly more simple than i thought it would be lol
     
  13. HajiyevEl

    HajiyevEl

    Joined:
    Feb 19, 2020
    Posts:
    47
    Code (CSharp):
    1.             var renderer = (GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset).GetRenderer(0);
    2.             var property = typeof(ScriptableRenderer).GetProperty("rendererFeatures", BindingFlags.NonPublic | BindingFlags.Instance);
    3.  
    4.             List<ScriptableRendererFeature> features = property.GetValue(renderer) as List<ScriptableRendererFeature>;
    5.  
    6.             foreach (var feature in features)
    7.             {
    8.                 if (feature.GetType() == typeof(BlurKawaseURP))
    9.                 {
    10.                     (feature as BlurKawaseURP).Settings.downsample = 4;
    11.                 }
    12.             }
     
  14. Hellfim

    Hellfim

    Joined:
    Sep 11, 2014
    Posts:
    123
    In the recent versions (I've cheked this in Unity 2023.2.0b4) you actually can access ScriptableRendererData of current renderer without reflection:
    Code (C#):
    1.  
    2. public static class CameraExtensions
    3. {
    4.     public static ScriptableRendererData GetCurrentRendererData(this Camera camera)
    5.     {
    6.         var selectedRenderer = camera.GetUniversalAdditionalCameraData().scriptableRenderer;
    7.        
    8.         var currentRenderPipeline = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline;
    9.         for (var i = 0; i < currentRenderPipeline.renderers.Length; ++i)
    10.         {
    11.             if (currentRenderPipeline.renderers[i] == selectedRenderer)
    12.             {
    13.                 return currentRenderPipeline.rendererDataList[i];
    14.             }
    15.         }
    16.        
    17.         return null;
    18.     }
    19. }
    20.  
     
    Fep310, Propagant, zhuhaiyia1 and 2 others like this.
  15. ATMLVE

    ATMLVE

    Joined:
    Jun 11, 2023
    Posts:
    75
    Is there more documentation on this process? There seems to be multiple ways to go about it and I'm also trying to add new renderer features at runtime which nothing seems to cover.

    Update - I did figure it out for the most part. As others above said, you can just add it to a monobehavior and then drag them in in the editor:

    Code (CSharp):
    1. [SerializeField] UniversalRendererData rendererData;
    2. [SerializeField] FullScreenPassRendererFeature postProcessEffect;
    and then modify those as you want. To add a new one, create a new feature as you would any class and add it to this list:

    Code (CSharp):
    1. [SerializeField] UniversalRendererData rendererData;
    2. FullScreenPassRendererFeature newPostProcessEffect;
    3.  
    4.     void Awake()
    5.     {
    6.        newPostProcessEffect = new();
    7.        rendererData.rendererFeatures.Add(newPostProcessEffect);
    8.     }
    You also need to be sure you destroy it manually, otherwise it will stick around as a missing feature and you'll just keep stacking them up.

    Code (CSharp):
    1.     void OnDestroy()
    2.     {
    3.         rendererData.rendererFeatures.Remove(newPostProcessEffect);
    4.     }
    I haven't figured out yet how to get the UniversalRendererData only through code, but it's not a big deal I suppose.
     
    Last edited: Nov 15, 2023
  16. kro11

    kro11

    Joined:
    Sep 23, 2019
    Posts:
    105
    I am changing RenderObjects > Override > Material in runtime through code, but it is changing only after relaunching a game.

    Code (CSharp):
    1. renderObjects.settings.overrideMaterial = rendererMaterials[rendererIndex];
    Is it possible to change it without relaunching the game in Unity 2021?
     
  17. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    You need to get renderObject feature using reflection because in runtime it is another instance than in editor
    after that everything will work as expected
     
  18. kro11

    kro11

    Joined:
    Sep 23, 2019
    Posts:
    105
    The same result - it doesn't works in build and in editor. I need to press stop/play buttons to make it works.