URP(Universal Render Pipeline)渲染管線在使用中的一些分享


本篇文章整理了URP管線使用中的一些簡單的心得記述

1.使用ScriptableRendererFeature自定義渲染特性

在內建(Build-in)管線中可以使用CommandBuffer並添加到攝像機上來實現自定義的特性。在URP管線中,處理方法變成了RendererFeature

RendererFeature不需要綁定到相機;而是掛載到渲染器(如ForwardRenderer)的設置里。

在Project面板點擊右鍵Create/Rendering/Universal Render Pipeline/Renderer Feature可以創建Renderer Feature模板。

模板中Feature帶有一個CustomRenderPass的嵌套類;並且在AddRenderPasses函數中被添加進pass隊列。

 

ScriptableRenderPass可以指定需要的渲染步驟,如:

m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;

 

由於一個效果往往需要多個pass不同階段處理;這樣的方式顯然比較友好。

 

在之前內建的渲染管線中;CommandBuffer只能執行預先設定好的一些步驟,這樣多少有些不方便。在自定義管線中CommandBuffer變成了立即執行,

現在可以在ScriptableRenderPass中直接通過context來立即執行CommandBuffer:

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    CommandBuffer cmd = CommandBufferPool.Get("MyCommandBuffer");
    //CommandBuffer的操作
    context.ExecuteCommandBuffer(cmd);

    CommandBufferPool.Release(cmd);
}

 

此外,標記Profiling后,可在FrameDebugger中直接查看標記Profiling的對象:

{
    ProfilingSampler mProfilingSampler = new ProfilingSampler("Test1");
    CommandBuffer cmd = CommandBufferPool.Get("Test1 Cmd");
    using (new ProfilingScope(cmd, mProfilingSampler))
    {
        MeshRenderer meshRenderer = Resources.Load<MeshRenderer>("TestModel");
        cmd.DrawRenderer(meshRenderer, meshRenderer.sharedMaterial);
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
}

 

而打開了管線設置中的Debug Level后;可以通過這個參數看見更多的調試信息

 

如UniversalRenderPipeline.cs的RenderSingleCamera方法里:

static void RenderSingleCamera(...)
{
...
asset.debugLevel >= PipelineDebugLevel.Profiling ? ...

這段代碼在勾選這個設置后可以在FrameDebugger內顯示不同的相機名。

 

 

2.使用DrawRenderers進行大批量繪制

在內建管線中,通常使用CommandBuffer.DrawRenderer來繪制一些指定的對象,

不過繪制對象一多這樣做就不太方便。

 

在URP的自定義pass中可以使用ScriptableRenderContext上下文里的DrawRenderers接口進行批量繪制,

它可以拿到當前相機的剔除結果(CullingResults),通過FilteringSettings參數再進行一次過濾。

FilteringSettings里還可以設置renderingLayerMask,renderingLayerMask可在MeshRenderer、SkinnedMeshRenderer

等渲染器組件中設置,獨立於舊的Layer。

借助傳入的DrawingSettings,RenderStateBlock參數可指定是否寫入Stencil、是否寫深度等信息,最終完成繪制,如:

context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings,
    ref m_RenderStateBlock);

 

如果要繪制的內容第一次相機剔除時沒有,也可以再進行一次相機剔除:

context.Cull(...)

使用新的結果來繪制。

 

以前抓取uGUI的繪制內容較為困難,現在也可以用這種辦法把UI分成幾部分繪制,並且控制每一部分是否寫入指定RT了,

並且還可以通過自定義的Feature和context.DrawRenderers把UI繪制的步驟單獨挪出來自行控制(但是Stencil會丟掉,酌情使用)。

 

還可以先修改RenderTarget再執行context.DrawRenderers繪制,這樣就可以把內容批量繪制到指定RT上:

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    CommandBuffer cmd = CommandBufferPool.Get("tempRt");
    int tmpRt = Shader.PropertyToID("_TempRt");
    cmd.GetTemporaryRT(tmpRt, mDesc);
    cmd.SetRenderTarget(tmpRt);
    context.ExecuteCommandBuffer(cmd);
    
    context.DrawRenderers(...);
    
    CommandBufferPool.Release(cmd);
}

 

(這里的RenderTexture應該在Configure中綁定)

 

注意,內建管線中使用CommandBuffer時可以直接填寫-1、-2等寬高參數獲得1/2,1/3等大小的RenderTexture,在自定義管線中

不再可用。

 

更多的繪制方法可以參考Render Objects(Runtime/RendererFeatures/RenderObjects.cs)或

DrawObjectsPass.cs(Runtime/Passes/DrawObjectsPass.cs)的做法。

3.相較內建管線的優化

在URP中單個對象支持的最大燈光數量是8盞;光照處理的操作在一個pass中完成。

雖然有數量限制;但這樣整個場景的Batches數量得到了控制,這一點體現較為明顯。

 

而陰影方面目前只能支持主光源平行光的陰影和聚光燈的陰影(v7.3.1)。

其次就是SRP Batches等技術,這方面暫未深入了解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM