I have a URP renderer feature that I’d like to toggle on and off during runtime using it’s SetActive function.
To get the reference to the feature I expose it as a public variable in the monobehaviour that does it (testcase: when pressing the b-button) and assign the scriptable object of the feature which is a sub asset of the renderer.
This works flawlessly in the editor and in a build which does not use Addressables.
But obviously the actual project is way larger and uses addressables.
The prefab which has the monobehaviour referencing the renderer feature is in the “UI” group. To avoid duplicate dependencies / asset duplication I assigned the entire renderer and urp pipeline asset to their own addressable group (“Rendering”). The game still works, great. But toggling the renderering feature does not work anymore. I suspect it gets duplicated in some way, but the duplicate dependency check does not show this and I don’t have any other idea how to figure out why that simple switch does not work anymore.
Is there anything special I have to keep in mind when using addressables with scriptable render pipeline stuff?
Maybe Unity itself is not using Addressables when referencing the renderer, so it gets its own built-in copy while everything else is getting another copy through Addressables.
You could try to assign the render pipeline from Addressables on startup to override the version that was built-in.
Or don’t use Addressables, instead go through GraphicsSettings.currentRenderPipeline, get the render data from the pipeline and then the render feature form the render data. This should always get you the render feature instance that’s currently used.
While that probably works it to get any feature in general I would still not have the specific reference to the one feature that I want to toggle and would need to do some kind of name.equals() comparision. That does not scale well code wise but is in fact my current solution (except that I get the renderer from the camera).
That sounds somewhat likely but maaaan Unity, why -.-
I could try to do that but somehow I dislike re-assigning the renderer asset at startup. Currently we only have a single urp asset in use, but doing this with multiple feels just as odd as the string based solution (although less hacky I suppose). The additional instances of the urp asset and renderers would probably be cleaned up and disposed of as well?
Thanks for the suggestions.
Is this not a problem others have faced before in like… every second shipped urp project?
You should have the type of the render feature you want to toggle? Then you could iterate ScriptableRendererData.rendererFeatures until you find the matching type, similar to using GetComponent<>().
And how do you go from the renderer to the feature? ScriptableRenderer.rendererFeatures is protected and I don’t see a way to get the ScriptableRendererData from a renderer?
Oh wait rendererfeatures is protected, oops… interesting.
This doesn’t change anything about the initial question. I tested referencing the features directly in a clean, new project and I still think that should work with addressables nonetheless.
My project uses a customized version of URP with a CustomRenderer class which has a GetFeatures() function which returns that protected list.
If you wanted to have that function it would be quite easy to make though as UniversalRenderer is a partial class, you can add function to that class using the partial keyword and an assembly definition reference which points to the urp assembly (the reference compiles your code into the urp assembly giving you internal access without modifying the read-only package, it’s kind of a super power). You can extend UniversalRenderPipelineAsset the same way to get a public function that returns m_RendererDataList without reflection. But obviously this was never really intended by Unity… but in the end what is.
The renderer feature I need to toggle is a RenderObjects… and there are multiple of those unfortunately so type checking only gets me so far.
namespace UnityEngine.Rendering.Universal
{
public partial class UniversalRenderer
{
public List<ScriptableRendererFeature> GetFeatures()
{
return rendererFeatures;
}
}
}
A couple times in my project I’ve wanted a gameobject to communicate with a render feature to change it’s behavior in some direct way and have never been able to find a nice, clean, and simple way to get a hold of the active feature in a pipeline. We’re also using Addressables.
In the end, I always do something more on the hacky-but-easy-to-understand side, like a static field on the feature’s class. This works well for custom render features. Haven’t tried it with any of the built-in ones, but were I to need to, I’d probably create another custom feature and just re-implement the needed behavior.
Which is all to say, I’ve had the same problem, have been equally confused by it, and have also not found a reasonable solution.
One note: I have the vague impression that setting a feature active/inactive does more than just toggle it’s execution. Seems like it might also cause the pipeline itself to rebuild/reinit itself, or maybe just the feature to reinit itself. Overall, I operate under the assuming that unity doesn’t want me fiddling with a pipelines feature set at runtime. As a result, I’ve added another flag to the features I want to disable to just prevent their execution without causing any pipeline/feature lifecycle stuff from being called. I might be totally wrong about this.
@najati good to know I am not the only one confused about this.
Reference / accessing the renderer feature aside, do you have the renderer / pipeline asset in an addressable bundle at all? Probably not right? because in the end you could never know which instance is actually being used in all cases?
From my understanding so far, yes, correct and with good reasons. When disabling render features Unity wants to try to free resources that won’t be used at all and sometimes might need to make some drastic changes to the renderpipline resulting in re-compiling a completely different set of shader variants.
My prime examples for this would be the decal render feature which adds Dbuffer textures and sets keywords which make basically any shader that support them recompile or SSAO which configures the renderpipeline to generate a DepthNormals buffer. Those really do need to restructure the entire pipeline.
Render Objects isn’t as complicated as it basically only adds draw calls. Though the enable/disable mechansim is the same toggling render-objects shouldn’t change that much, but I very much do see the value of not triggering any kind of rebuilding at all using a flag like najati described and just avoid setting up the draw calls.