博客 / 詳情

返回

【URP】Unity[RendererFeatures]渲染對象RenderObjects

【從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通過繼承ScriptableRendererFeatureScriptableRenderPass實現管線擴展,核心邏輯在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開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.