最近遇到了一些比较奇怪的问题。
在Unity的渲染管线中,需要给URP的RenderPipeline Asset中增加一些RenderererData,这也是自定义Render Feature并且渲染的方式。具体的实现方法也很简单,准备好RendererData后,只需要再Unity的UI上点击加号就行。如下图所示:
但是实际上总是有这样那样的需求。此次需要通过脚本来动态添加这个Renderer List。 我们通过URP的源码中可以看到,这个变量不可访问,也没有对应的方法。
讲道理这样的接口应该由URP自己暴露出来,但是实际上并没有。不过既然是可序列化的变量,大概率是能够通过合法的方式操作的,但是并不打算让你访问,所以这边只能够通过反射的方式来添加了。
直接上代码:
var proInfo = typeof(UniversalRenderPipelineAsset).GetField("m_RendererDataList",
BindingFlags.NonPublic | BindingFlags.Instance);
if (proInfo != null)
{
rendererDataList = (ScriptableRendererData[])proInfo.GetValue(UniversalRenderPipeline.asset);
var newList = new ScriptableRendererData[rendererDataList.Length+1];
for (int i = 0; i < rendererDataList.Length; i++)
{
newList[i] = rendererDataList[i];
newList[rendererDataList.Length] = newRendererData;
}
proInfo.SetValue(GraphicsSettings.currentRenderPipeline, newList);
}
首先先通过反射获取到对应的Field,然后强制转化为对应的rendererDataList,这时候就能够获取整个列表了。
但是这里有个问题,如果我们直接修改了List,实际上是不会生效的,因为此时的rendererDataList只是我们的一个变量,指向的位置才是真正的列表,如果我们直接:
rendererDataList = new ScriptableRendererData[10];
这样的话相当于是重新new了一个变量,是无法改变PipeLine Asset里面的列表。因此,此处还需要使用SetValue方法把新的值放回才能生效。
于是,在代码里的方法就是new一个ScriptableRendererData数组,先把获取到的列表内容塞进去,再把自定义的RendererData放到最后。再用SetValue方法来更新对应的asset。
实测在Editor和Runtime中都能够生效。