博客 / 詳情

返回

【渲染流水線】[應用階段]-[渲染命令隊列]以UnityURP為例

應用階段最後是CPU向GPU提交需要渲染的數據。通常數據會被複制到顯存中,然後設置渲染參數,最後調用渲染接口。PC中是這樣的,但是移動設備一般沒有單獨的顯存。使用內存為GPU服務。他們使用同一內存地址。除非要讀/寫這段內存內容才會複製出一份調整CPU和GPU之間協作。

【從UnityURP開始探索遊戲渲染】專欄-直達

渲染狀態

  • 一連串開關或方法,以及方法的地址指向(階段中的各種可配置的階段等都是在這裏)。SetPassCall。例如是否開啓混合、用哪個紋理、哪個頂點着色器、是否背面剔除等,在Unity中則是ShaderLab語法規則中規定的各種標籤。

渲染指令

  • 調用具體渲染的對象。drawcall是一個渲染指令,這個指令僅指向一連串圖元(點線面 網格拆分後的狀態),並不會包含任何其他材質信息。每個狀態前都伴隨着一連串渲染狀態設置,所以渲染命令隊列中,渲染狀態和渲染指令是交替出現。

渲染命令隊列

  • 其中包含渲染狀態、渲染指令的緩衝區。CPU向緩衝區放入指令,GPU執行指令。CPU發送渲染狀態後,CPU需要控制總線將數據從內存搬運到顯存,搬運過程耗費大量時間。drawcall多了後會導致大量內存搬運,運行速度下降。

打包數據

模型信息

模型數據主要從網格資源(Mesh)中獲取,包含以下核心屬性:

  1. 頂點座標‌描述模型局部空間的頂點位置座標(x, y, z)。
  2. 法線信息‌定義頂點朝向,用於光照計算和表面平滑度。
  3. UV信息‌二維紋理映射座標(u, v),範圍[0,1],控制貼圖在模型表面的分佈。
  4. 切線向量‌與法線配合構建切線空間,用於法線貼圖等高級渲染效果。
  5. 頂點顏色‌存儲逐頂點顏色值,可用於特殊着色效果。
  6. 索引列表‌定義頂點連接順序,優化繪製效率(減少重複頂點)
  • 數據來源‌:

    • 由建模工具(如Blender/Maya)導出時生成,隨模型文件(.fbx/.obj)導入Unity。
    • 程序化網格通過Mesh類API動態設置(如mesh.verticesmesh.uv
    • 變換矩陣

      矩陣數據由CPU計算並傳遞給GPU:

      • 模型矩陣 Model Matrix(M) ‌模型局部座標→世界座標,由物體的Transform組件(位置/旋轉/縮放)計算得出。

        • 計算順序:縮放 → 旋轉 → 平移(SRT)
      • 視圖矩陣 View Matrix(V) ‌世界座標→攝像機座標,基於Camera組件的位姿(位置/朝向/上方向)生成。

        • 計算原理:先逆平移(攝像機到原點),再逆旋轉(對齊座標軸)
      • 投影矩陣 Projection Matrix(P) ‌攝像機座標→齊次裁剪座標,通過相機參數計算:

        • 參數來源:FOV、近/遠裁剪面、寬高比
        • 透視投影(近大遠小)或正交投影(等比例縮放)
        • Field of View (FOV):視角範圍
        • Near/Far Clipping Planes:近遠裁剪平面
        • Aspect Ratio:屏幕寬高比。
      • MVP矩陣‌最終變換矩陣:MVP = P × V × M
      • 計算主體與存儲位置

        矩陣類型 計算者 存儲位置(GPU端) 訪問方式(Shader)
        模型矩陣 (M) Transform組件 (CPU計算) unity_ObjectToWorld UNITY_MATRIX_M
        視圖矩陣 (V) 攝像機組件 (CPU計算) unity_MatrixV UNITY_MATRIX_V
        投影矩陣 (P) 攝像機投影參數 (CPU計算) unity_MatrixP UNITY_MATRIX_P
        MVP矩陣 Shader運行時組合 無獨立存儲 mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, pos))
      • 計算時機

        • CPU端:每幀渲染前更新(物體Transform或攝像機移動時)。
        • GPU端:通過UNITY_MATRIX_VP(視圖投影矩陣)與UNITY_MATRIX_M(模型矩陣)在頂點着色器動態組合
      • 優化機制

        • URP預計算VP矩陣(視圖投影聯合矩陣),減少GPU計算量。
        • 使用UnityObjectToClipPos內置函數直接完成MVP變換:

          hlsl
          float4 clipPos = UnityObjectToClipPos(v.vertex); // 內部實現:mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, v.vertex))

燈光、材質參數

  • 燈光參數

    • 光源屬性‌:位置、顏色、強度、衰減等,源自場景中的Light組件。
    • 陰影參數‌:陰影強度、分辨率,通過URP光源設置(如UniversalAdditionalLightData)配置。
  • 材質數據

    • Shader與材質屬性‌:漫反射顏色、高光強度等,由Material實例定義。
    • 紋理貼圖‌:通過材質綁定(如_MainTex),從紋理資源加載。

數據傳遞流程‌:

應用階段通過SetPassCall設置渲染狀態(Shader/材質),並通過DrawCall提交圖元列表

Batch

  • 把數據加載到顯存,設置渲染狀態,CPU調用GPU渲染的過程稱之為一個Batch。

Unity URP渲染管線中的渲染狀態和渲染命令的實現

一、‌渲染狀態設置(SetPassCall)‌

  • ScriptableRenderer類

    • 位於UniversalRenderer.cs中,負責管理URP的默認渲染流程。
    • 調用EnqueuePass方法將渲染Pass(如DrawObjectsPass)加入隊列。
  • CommandBuffer類

    • 通過CommandBufferPool.Get獲取實例,錄製渲染指令。
    • 關鍵方法:

      csharp
      cmd.SetRenderTarget()// 綁定渲染目標
      cmd.SetGlobalTexture()// 設置全局紋理
      cmd.SetViewProjectionMatrices()// 設置VP矩陣
  • Material與Shader

    • 材質狀態通過Material.SetPass方法設置,觸發底層SetPassCall
    • URP通過ShaderData類管理着色器變體(Variant)的切換。

二、‌圖元提交(DrawCall)‌

  • ScriptableRenderContext類

    • 核心方法Submit提交所有錄製的CommandBuffer到GPU。
    • 調用鏈:

      csharp
      context.ExecuteCommandBuffer(cmd);// 執行指令
      context.DrawRenderers()// 觸發DrawCall
  • DrawingSettings與FilteringSettings

    • DrawObjectsPass.Execute中配置:

      csharp
      var drawSettings = new DrawingSettings(...);// 指定Shader Pass和排序var filterSettings = new FilteringSettings(...);// 設置渲染隊列和層級
      context.DrawRenderers(...);// 最終提交
  • Graphics.DrawMesh

    • 直接提交網格數據的備選API,繞過URP流程但效率較低。

三、關鍵腳本位置

功能 腳本文件 核心方法
渲染流程控制 UniversalRenderer.cs AddRenderPassesExecute
指令錄製 CommandBuffer.cs ClearDrawMeshBlit
材質狀態管理 Material.cs SetPassSetShaderPassEnabled
數據提交 ScriptableRenderContext.cs SubmitDrawRenderers

四、執行流程示例

csharp
// 在ScriptableRenderPass中實現
public override void Execute(ScriptableRenderContext context, ref RenderingData data) {
    CommandBuffer cmd = CommandBufferPool.Get("CustomPass");
    cmd.SetRenderTarget(...);// SetPassCall
    cmd.DrawMesh(...);// DrawCall
    context.ExecuteCommandBuffer(cmd);
    CommandBufferPool.Release(cmd);
}

Unity URP渲染管線中的應用階段渲染命令隊列及渲染隊列實現

在Unity URP渲染管線的應用階段,渲染命令隊列包含一系列圖形命令,主要用於調度和執⾏渲染操作,例如清除緩衝區、繪製幾何體、設置材質和着色器參數、處理光源陰影,以及執行後處理效果。

這些命令通過ScriptableRenderContext接口進行管理,該接口作為C#代碼與Unity底層圖形引擎的橋樑,確保命令按序列化順序提交GPU處理。隊列內容包括:

  • 緩衝區清除命令(如顏色緩衝和深度緩衝)。
  • 幾何體繪製命令(調用DrawMeshDrawProcedural)。
  • 狀態設置命令(如設置視口、混合模式)。
  • 陰影貼圖生成命令(針對動態光源)。
  • 後處理Pass(如抗鋸齒或景深應用)。這些命令在每幀的渲染循環中被動態生成和執行,以支持前向渲染策略和性能優化。

URP中的渲染隊列實現主要由ScriptableRenderPass類完成,它定義了Pass的執行順序和具體渲染邏輯。具體腳本流程如下:

渲染隊列管理‌:

  • 渲染隊列(如RenderQueueRange.opaqueRenderQueueRange.transparent)在ScriptableRenderPass的構造函數中指定,通過字段如renderPassEvent控制Pass的執行時機(例如在相機渲染前或後)。
  • 例如,一個基本的Pass腳本會繼承自ScriptableRenderPass,並在其Configure方法中設置隊列優先級:這裏,Execute方法包含具體命令隊列的實現,使用CommandBuffer來錄製命令(如cmd.ClearRenderTarget),並通過ScriptableRenderContext提交。

    csharp
    public class CustomRenderPass : ScriptableRenderPass
    {
        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
        {
    // 設置隊列範圍為不透明對象
            renderPassEvent = RenderPassEvent.BeforeRenderingOpaques;
        }
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        {
    // 執行命令,如繪製或清除
            CommandBuffer cmd = CommandBufferPool.Get();
            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }

腳本集成‌:

  • ScriptableRenderer(如UniversalRenderer)中,渲染隊列通過m_ActiveRenderPassQueue列表管理。
  • Setup階段調用AddRenderPasses方法收集所有關聯的ScriptableRenderPass實例(來自RendererFeature),並按事件順序排序;Execute階段遍歷列表執行每個Pass的Execute方法。
  • 例如,UniversalRenderPipeline.Render方法驅動整個流程:此腳本位於URP核心程序集(如UniversalRenderPipeline.cs),依賴於UniversalRenderPipelineAsset提供配置
csharp
protected override void Render(ScriptableRenderContext context, List<Camera> cameras)
{
// 排序相機並逐個處理foreach (var camera in cameras)
    {
        var renderer = cameraData.renderer;
        renderer.Execute(context, ref renderingData);// 執行Pass隊列
    }
}

在Unity URP中,ShaderLab配置的渲染狀態(如剔除、深度測試、混合模式等)的處理流程

一、狀態讀取與存儲機制

ShaderLab解析階段

  • URP通過ShaderCompiler解析ShaderLab代碼,將CullZTestBlend等指令轉換為底層渲染狀態標識符。
  • 解析結果存儲在ShaderData結構中,包含渲染狀態變體(Variant)和材質屬性。

    GPU狀態設置階段

  • 運行時由CommandBuffer錄製指令(如cmd.SetRenderTargetcmd.SetGlobalDepthBias),通過ScriptableRenderContext.Submit提交到GPU。
  • 關鍵存儲位置:

    • 剔除模式‌:存於RenderStateBlock.cullMode,通過DrawingSettings傳遞給DrawRenderers調用。
    • 深度測試/寫入‌:通過DepthState結構(含ZWriteZTest)配置,最終寫入GPU深度緩衝區。
    • 混合模式‌:由BlendState管理(含BlendOpSrcFactor等參數),綁定到渲染管線狀態。

    URP運行時管理

  • UniversalRendererAddRenderPasses階段收集所有Pass的渲染狀態,合併到RenderStateBlock
  • 通過MaterialPropertyBlock動態覆蓋材質屬性(如運行時修改_ZWrite)。

二、關鍵腳本與調用鏈

功能 腳本/類 核心方法 數據流向
Shader解析 ShaderCompiler CompileShader ShaderLab → ShaderData
狀態錄製 CommandBuffer SetRenderState CPU → GPU指令隊列
Pass執行 DrawObjectsPass Execute 通過DrawingSettings傳遞狀態
動態修改 MaterialPropertyBlock SetFloat/SetInt 運行時覆蓋Shader參數

三、使用示例(URP中動態修改深度測試)

hlsl
// ShaderLab中聲明深度測試
SubShader {
    Pass {
        ZWrite On
        ZTest LEqual
    }
}
  • 運行時讀取‌:通過Material.GetInt("_ZWrite")獲取狀態。
  • 動態修改‌:

    csharp
    var block = new MaterialPropertyBlock();
    block.SetInt("_ZWrite", 0);// 禁用深度寫入
    renderer.SetPropertyBlock(block);

    【從UnityURP開始探索遊戲渲染】專欄-直達

(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.