Unity的URP給了我們擴展渲染Pass的接口--RenderFeature,我們之前在講URP-ForwardRenderer的時候提到過RenderFeature,這個東西是可以用來擴展Pass的。RenderFeature是依附於ForwardRenderer的,如下圖所示:
現在我們會看到RendererFeatures的列表是空的,我們來添加一個,點擊加號,我們會發現只有一個RenderObjects可以選擇,我們可以先用這個RenderObjects的RenderFeature來熟悉一下一個Feature是怎么執行的。添加后點擊添加的條目,會有以下參數:
我們首先看這個Feature怎么用:創建一個Unlit材質,將Pass的Name修改為"TestPass",然后將ShaderPasses中的PassName設置為“TestPass“,如下圖:
這樣,我們就能正確的通過其他Pass來渲染這個物體了,這個Pass通過我們自己在Shader中的自定義可以實現各種效果,比如我們實現一個多Pass描邊,繼續剛才我們的例子,因為我們將原來的PassName改為了Feature的PassName(”TestPass“),所以URP就不會調用UniversalForwardPass了。如果我們把UniversalForwardPass加回來,同時有UniversalForwardPass和TestPass兩個Pass,就等於這個物體會在兩個Pass中被渲染,即我們以前內置管線的多Pass渲染,通過這種方式我們就可以在URP中制作很多功能了。比如舉個栗子,多Pass描邊效果:
一個PASS的RenderMode為UniversalForward,另一個為TestPass,第一個Pass為了方便演示,直接Unlit,第二個Pass描邊,於是有了這個效果。除了這個,這個RenderObjects的Feature還能實現很多效果,具體就由小伙伴們發揮自己的想象力啦!我們現在借助RenderObjects了解了如何使用一個Feature,那么現在我們看看這個Feature是怎么寫的。因為一個Feature不能滿足我們全部的需求,所以我們要學會擴展自己的Feature。
找到RenderObjects代碼,如下:
[MovedFrom("UnityEngine.Experimental.Rendering.LWRP")]public class RenderObjects : ScriptableRendererFeature
我們可以看到所有的Feature都要繼承ScriptableRendererFeature類。再往下我們可以看到里面定義了幾個類:
[System.Serializable] public class RenderObjectsSettings { public string passTag = "RenderObjectsFeature"; public RenderPassEvent Event = RenderPassEvent.AfterRenderingOpaques; public FilterSettings filterSettings = new FilterSettings(); public Material overrideMaterial = null; public int overrideMaterialPassIndex = 0; public bool overrideDepthState = false; public CompareFunction depthCompareFunction = CompareFunction.LessEqual; public bool enableWrite = true; public StencilStateData stencilSettings = new StencilStateData(); public CustomCameraSettings cameraSettings = new CustomCameraSettings(); } [System.Serializable] public class FilterSettings { // TODO: expose opaque, transparent, all ranges as drop down public RenderQueueType RenderQueueType; public LayerMask LayerMask; public string[] PassNames; public FilterSettings() { RenderQueueType = RenderQueueType.Opaque; LayerMask = 0; } } [System.Serializable] public class CustomCameraSettings { public bool overrideCamera = false; public bool restoreCamera = true; public Vector4 offset; public float cameraFieldOfView = 60.0f; }
這些結構就是我們看到的Renderer中Feature的參數界面,也就是說Feature的參數都是在這里定義的。然后需要實現基類的兩個方法:
public override void Create() { FilterSettings filter = settings.filterSettings; renderObjectsPass = new RenderObjectsPass(settings.passTag, settings.Event, filter.PassNames, filter.RenderQueueType, filter.LayerMask, settings.cameraSettings); renderObjectsPass.overrideMaterial = settings.overrideMaterial; renderObjectsPass.overrideMaterialPassIndex = settings.overrideMaterialPassIndex; if (settings.overrideDepthState) renderObjectsPass.SetDetphState(settings.enableWrite, settings.depthCompareFunction); if (settings.stencilSettings.overrideStencilState) renderObjectsPass.SetStencilState(settings.stencilSettings.stencilReference, settings.stencilSettings.stencilCompareFunction, settings.stencilSettings.passOperation, settings.stencilSettings.failOperation, settings.stencilSettings.zFailOperation); } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { renderer.EnqueuePass(renderObjectsPass); }
通過代碼我們可以看到這個Feature其實就是又執行了一遍RenderObjectsPass,只不過執行時機可以自己定義。我們需要找到這兩個方法在哪里調用,才能知道整個流程。
for (int i = 0; i < rendererFeatures.Count; ++i) rendererFeatures[i].AddRenderPasses(this, ref renderingData);
AddRenderPass在ForwardRenderer的SetUp方法里面執行,如上代碼。
public ScriptableRenderer(ScriptableRendererData data) { foreach (var feature in data.rendererFeatures) { if (feature == null) continue; feature.Create(); m_RendererFeatures.Add(feature); } Clear(); }
Create方法在ScriptableRenderer的構造函數中,如上代碼。
這樣,我們就可以總結出如何做自己的RenderFeature:
1.創建自己的Feature類
2.找到Feature類要執行的Pass和時機
3.如果Feature需要自定義Pass需要自己擴展URP的Pass。
擴展Feature三步走,當然,還有Feature編輯器界面,這個忽略(啊哈哈哈哈),這節主要學習了如何創建自己的Feature,具體在應用中小伙伴們要根據時機需求看是否需要擴展Feature和Pass。
博友們如果有意見或者建議,可以留言哦~