【從UnityURP開始探索遊戲渲染】專欄-直達
RenderObjects的定義與作用
RenderObjects是URP提供的RendererFeature之一,允許開發者在不編寫代碼的情況下對渲染管線進行定製。它通過配置參數實現選擇性渲染特定層級的物體、控制渲染順序、重載材質或渲染狀態等功能57。其核心用途包括:
- 層級過濾:僅渲染指定LayerMask的物體
- 渲染時機控制:通過Event參數插入到渲染管線的不同階段(如AfterRenderingOpaques)
- 材質替換:使用Override Material覆蓋原有材質
- 多Pass渲染:配合Shader的LightMode標籤實現描邊等效果
發展歷史
- 初始版本(2020年前)作為LWRP實驗性功能引入
- 2020年URP 7.x版本正式集成,提供基礎層過濾和材質替換
- 2021年後增強深度/模板控制,支持透明物體處理
- 2022年優化API結構,明確ScriptableRendererFeature與RenderPass的分離
原理
底層原理
-
架構層級
RenderObjects通過繼承
ScriptableRendererFeature和ScriptableRenderPass實現管線擴展,核心邏輯在Execute()方法中通過CommandBuffer提交繪製指令。其本質是通過URP的ScriptableRenderContext調度GPU渲染命令,與內置管線不同之處在於採用可編程的輕量級渲染管線架構。 -
渲染流程控制
通過
RenderPassEvent枚舉插入到URP的固定管線階段(如AfterRenderingOpaques),底層會觸發以下操作:- 調用
ConfigureTarget()設置渲染目標 - 使用
FilteringSettings過濾指定Layer的物體 - 通過
DrawingSettings配置Shader Pass和排序規則
- 調用
-
材質替換機制
當啓用Override Material時,URP會臨時替換原始材質的Shader,但保留物體的頂點數據。該過程通過
MaterialPropertyBlock實現動態參數傳遞,避免材質實例化開銷。
實現示例
-
OutlineFeature.cs
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class OutlineFeature : ScriptableRendererFeature { class OutlinePass : ScriptableRenderPass { private Material _outlineMat; private LayerMask _layerMask; private FilteringSettings _filteringSettings; public OutlinePass(Material mat, LayerMask mask) { _outlineMat = mat; _layerMask = mask; _filteringSettings = new FilteringSettings(RenderQueueRange.opaque, _layerMask); renderPassEvent = RenderPassEvent.AfterRenderingOpaques; } public override void Execute(ScriptableRenderContext context, ref RenderingData data) { var drawingSettings = CreateDrawingSettings( new ShaderTagId("UniversalForward"), ref data, SortingCriteria.CommonOpaque ); drawingSettings.overrideMaterial = _outlineMat; context.DrawRenderers(data.cullResults, ref drawingSettings, ref _filteringSettings); } } [SerializeField] private Material _outlineMaterial; [SerializeField] private LayerMask _outlineLayers = 1; private OutlinePass _pass; public override void Create() => _pass = new OutlinePass(_outlineMaterial, _outlineLayers); public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData data) => renderer.EnqueuePass(_pass); } -
Outline.shader
Shader "Custom/Outline" { Properties { _OutlineColor("Color", Color) = (1,0,0,1) _OutlineWidth("Width", Range(0,0.1)) = 0.03 } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+100" } Pass { Cull Front ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" float _OutlineWidth; fixed4 _OutlineColor; struct appdata { float4 vertex : POSITION; float3 normal : NORMAL; }; v2f vert(appdata v) { v2f o; v.vertex.xyz += v.normal * _OutlineWidth; o.pos = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag(v2f i) : SV_Target { return _OutlineColor; } ENDCG } } }
關鍵流程解析
-
渲染指令提交
DrawRenderers方法內部會構建BatchRendererGroup,將CPU側的渲染數據批量提交至GPU,相比直接使用CommandBuffer更高效。 -
深度測試控制
示例中
ZWrite Off禁用深度寫入,使描邊始終顯示在原始物體表面,該技術也常用於解決透明物體渲染順序問題。 -
多Pass協作
URP會先執行默認的Forward渲染Pass,再執行RenderObjects插入的Pass,通過
RenderPassEvent控制執行順序
完整實現流程示例
-
OutlineFeature.cs
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class OutlineFeature : ScriptableRendererFeature { class OutlinePass : ScriptableRenderPass { private Material outlineMat; private LayerMask layerMask; private RenderTargetIdentifier source; public OutlinePass(Material mat, LayerMask mask) { outlineMat = mat; layerMask = mask; renderPassEvent = RenderPassEvent.AfterRenderingOpaques; } public override void Execute(ScriptableRenderContext context, ref RenderingData data) { CommandBuffer cmd = CommandBufferPool.Get("OutlinePass"); var drawSettings = CreateDrawingSettings( new ShaderTagId("UniversalForward"), ref data, SortingCriteria.CommonOpaque); var filterSettings = new FilteringSettings(RenderQueueRange.opaque, layerMask); context.DrawRenderers(data.cullResults, ref drawSettings, ref filterSettings); CommandBufferPool.Release(cmd); } } [SerializeField] private Material outlineMaterial; [SerializeField] private LayerMask outlineLayers; private OutlinePass pass; public override void Create() { pass = new OutlinePass(outlineMaterial, outlineLayers); } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData data) { renderer.EnqueuePass(pass); } } -
Outline.shader
Shader "Custom/Outline" { Properties { _OutlineColor("Color", Color) = (1,1,1,1) _OutlineWidth("Width", Range(0,0.1)) = 0.05 } SubShader { Tags { "RenderType"="Opaque" "LightMode"="UniversalForward" } Pass { CGPROGRAM // Vertex expansion logic... ENDCG } } }
參數詳解與用例
| 參數 | 説明 | 應用場景 |
|---|---|---|
| Event | 渲染時機(如BeforeRenderingPostProcessing) | 控制特效疊加順序 |
| LayerMask | 目標渲染層級 | 僅對敵人/UI層描邊 |
| Override Material | 替換材質 | 角色進入陰影區切換材質 |
| Depth Test | 深度測試模式 | 解決透明物體遮擋問題 |
| Shader Passes | 匹配的Shader LightMode標籤 | 多Pass渲染(如"UniversalForward") |
配置步驟
- 創建URP Asset並啓用Renderer Features
- 添加RenderObjects Feature到Forward Renderer
- 配置Event為AfterRenderingOpaques(不透明物體)或AfterRenderingTransparents(透明物體)
- 指定目標Layer和替換材質
- 調整Depth/Stencil參數解決遮擋問題
典型應用包括:角色描邊、場景分塊渲染、特殊效果疊加(如受傷高亮)等。通過組合不同Event和LayerMask可實現複雜的渲染管線控制
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)