2018年7月23日 星期一

初探Unity的SRP

基本上,SRP的流程架構,還算蠻清楚的,步驟大概如下:
RenderPipeline Render()
==ProcessPerCamera(迴圈)
==CullResults.Cull()
====ProcessPerPass(迴圈)
在大都數的狀況下,cameras.Length大都多是1(本來以為EditorView的Camera也會進來…)
,而要做的事,基本上都是context通溝(下CommandBuffer指令,Submit畫完之類的)。

這裡並沒有把繪圖流程包成一個Pass物件,因為相關代碼只會有一個Pass,其中DrawRendererSettings需要的第二個參數ShaderPassName相當重要,它指的是在ShaderCode裡有指定相關的Tag才畫挑出來畫,比方"LightMode" = "ForwardBase",而你的ShaderPassName也是設成"ForwardBase"時,才會被挑出來。

相關代碼如下:

private void ExecuteCommandBuffers(ref ScriptableRenderContext context, Camera targetCamera, CameraEvent evt)
{
        CommandBuffer[] commandBuffers = targetCamera.GetCommandBuffers(evt);
        for (int index = 0; index < commandBuffers.Length; ++index)
            context.ExecuteCommandBuffer(commandBuffers[index]);
 }

 public override void Render(ScriptableRenderContext context, Camera[] cameras)
 { 
        base.Render(context, cameras);

        Camera targetCamera;     
        for (int cameraIndex = 0; cameraIndex < cameras.Length; ++cameraIndex)
        {
            targetCamera = cameras[cameraIndex];

            //取得Camera culling參數
            ScriptableCullingParameters cullingParams;
            if (!CullResults.GetCullingParameters(targetCamera, out cullingParams))
                continue;

            //依culling參數取得culling的結果
            CullResults cull = CullResults.Cull(ref cullingParams, context);

            // Setup camera for rendering (sets render target, view/projection matrices and other
            // per-camera built-in shader variables).
            //設定矩陣相關資訊
            context.SetupCameraProperties(targetCamera);

            //清除深度buffer
            context.ExecuteCommandBuffer(_clearCommandBuffer);

            //設定Shader Pass相關資訊(指定Pass Name及Camera)
            var settings = new DrawRendererSettings(targetCamera, _forwardBasePassName);

            //設定畫opaque物件的相關旗標並將其畫出
            settings.sorting.flags = SortFlags.CommonOpaque;         
            var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
            context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);

            //執行AfterForwardOpaque的CommandBuffers
            ExecuteCommandBuffers(ref context, targetCamera, CameraEvent.AfterForwardOpaque);

            // Draw skybox
            context.DrawSkybox(targetCamera);

            //執行AfterSkybox的CommandBuffers
            ExecuteCommandBuffers(ref context, targetCamera, CameraEvent.AfterSkybox);

            //設定畫alpha物件的相關旗標並將其畫出
            settings.sorting.flags = SortFlags.CommonTransparent;
            filterSettings.renderQueueRange = RenderQueueRange.transparent;
            context.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);

            //執行AfterForwardAlpha的CommandBuffers
            ExecuteCommandBuffers(ref context, targetCamera, CameraEvent.AfterForwardAlpha);

            context.Submit();
      }
 }

其中比較特別的是ExecuteCommandBuffers,如果之前有接觸過CommandBuffers的人就會比
較清楚,由於目前整個繪圖管線是自己實作的,當然CommandBuffers也是要自己執行,以
下是有關CommandBuffers和自訂繪圖管線執行的狀況:

  1. 染紅色執行的順序是AfterForwardOpaque(只染Opaque物件)
  2. 染綠色執行的順序是AfterSkybox(染Opaque及SkyBox物件)
  3. 染藍色執行的順序是AfterForwardAlpha(染Opaque,SkyBox及Alpha物件)
相關影片如下:



相關參考與原始碼:Scriptable Render Pipeline Overview

Dream continues in...

沒有留言:

張貼留言