Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Toggle RenderFeatures or Change Renderers from script

Discussion in 'Universal Render Pipeline' started by Sarkahn, Jan 6, 2020.

  1. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Hi, I want to be able to toggle a render feature on my URP Renderer from inside a script, or to switch which renderer a camera is currently using from script, so I can control which effects are happening at runtime.

    I saw we have UniversalAdditionalCameraData.SetRenderer(int). This would work great except I can't see an easy way to get a list of the current renderers being used by the pipeline, so if I change my renderers on the pipline asset then SetRenderer() might be referencing a different renderer then I intended or one that doesn't exist.

    Is there a way to get a list of the renderers in the active pipeline so I can make sensible use of CameraData.SetRenderer or is there an easier way to do what I'm trying to do?
     
  2. phil_lira

    phil_lira

    Unity Technologies

    Joined:
    Dec 17, 2014
    Posts:
    584
    There's no exposed way to do this atm, but it has been something a few users have asked already and we plan to add support to this considering the feedback received.

    Another request has been to inject render passes by script.
    I can't give an ETA for this just yet but we plan to improve this.
     
  3. daverinnadesan

    daverinnadesan

    Joined:
    Mar 13, 2018
    Posts:
    4
    Hi phil_lira

    Are there any updates on this?
     
  4. melos_han_tani

    melos_han_tani

    Joined:
    Jan 11, 2018
    Posts:
    77
    Is there a way to do this now?

    Right now what I want to do is have the artist set the ScriptableRendererData in the inspector of a script

    public ScriptableRendererData rendererData;

    Then when entering the scene, I want to set the camera's "Renderer" property to rendererData.
     
  5. StaggartCreations

    StaggartCreations

    Joined:
    Feb 18, 2015
    Posts:
    2,133
    The SetRenderer function isn't very useful at the moment, since there's no way to get the index from the pipeline asset you're looking for. This is all required for automatic setup of renderers, or specific cameras. Currently, you can get around all this by using reflection.

    Checking if a ScriptableRenderPass is already in the render data list (requires a reference to the ScriptableRendererData in question somewhere)
    Code (CSharp):
    1. BindingFlags bindings = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
    2.  
    3.             ScriptableRendererData[] m_rendererDataList = (ScriptableRendererData[])typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", bindings).GetValue(UniversalRenderPipeline.asset);
    4.  
    5.             ScriptableRendererData pass = <Reference to it here>;
    6.  
    7.            bool isPresent = false;
    8. for (int i = 0; i < m_rendererDataList.Length; i++)
    9.             {
    10.                 if (m_rendererDataList[i] == pass) isPresent = true;
    11.             }
    12.  
    13. return isPresent;
    14.  
    Adding it to the render pipeline:

    Code (CSharp):
    1. private static void AddRendererToPipeline(ScriptableRendererData pass)
    2.         {
    3.             if (pass == null) return;
    4.  
    5.             BindingFlags bindings = System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance;
    6.  
    7.             ScriptableRendererData[] m_rendererDataList = (ScriptableRendererData[])typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", bindings).GetValue(UniversalRenderPipeline.asset);
    8.             List<ScriptableRendererData> rendererDataList = new List<ScriptableRendererData>();
    9.  
    10.             for (int i = 0; i < m_rendererDataList.Length; i++)
    11.             {
    12.                 rendererDataList.Add(m_rendererDataList[i]);
    13.             }
    14.             rendererDataList.Add(pass);
    15.  
    16.             typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", bindings).SetValue(UniversalRenderPipeline.asset, rendererDataList.ToArray());
    17.         }
    Applying it to a camera (also requires a reference to the ScriptableRendererData in question)
    Code (CSharp):
    1.                     ScriptableRendererData[] rendererDataList = (ScriptableRendererData[])typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(UniversalRenderPipeline.asset);
    2.  
    3.                     for (int i = 0; i < rendererDataList.Length; i++)
    4.                     {
    5.                         if (rendererDataList[i] == <your renderer>) universalAdditionalCameraData.SetRenderer(i);
    6.                     }
     
    melos_han_tani likes this.
  6. weiping-toh

    weiping-toh

    Joined:
    Sep 8, 2015
    Posts:
    186
    The easiest approach for now, personally, is to implement my own renderer that includes all the desired passes and is configurable from script to include and exclude passes on the fly.
     
  7. tjmaul

    tjmaul

    Joined:
    Aug 29, 2018
    Posts:
    464
    I was also looking for this. I don't know since when this works, but I created a behaviour like this:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Rendering.Universal;
    4.  
    5. public class SwitchRendererFeature : MonoBehaviour
    6. {
    7.     public ScriptableRendererFeature feature;
    8.  
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.         StartCoroutine(Blink());
    13.     }
    14.  
    15.     IEnumerator Blink()
    16.     {
    17.         while(true) {
    18.             feature.SetActive(!feature.isActive);
    19.             yield return new WaitForSecondsRealtime(1);
    20.         }
    21.     }
    22. }
    23.  
    I added it to a GameObject and dragged the renderer feature from the project (you can open the ForwardRenderer, see attached image) to the slot in the MonoBehaviour. Works like a charm.

    Bildschirmfoto 2021-01-17 um 09.54.29.png
     
  8. HajiyevEl

    HajiyevEl

    Joined:
    Feb 19, 2020
    Posts:
    41
    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.             }