URP學習之四--各類Pass


上次我們了解了URP大致的框架,接下來看看每個Pass都是做什么的,先看DrawObjectPass:

 從截圖中我們可以看到這個Pass主要用於渲染不透明物體和半透明物體(ForwardPath)。

首先我們看一下這個Pass的構造:

public DrawObjectsPass(
      string profilerTag,
      bool opaque,
      RenderPassEvent evt,
      RenderQueueRange renderQueueRange,
      LayerMask layerMask,
      StencilState stencilState,
      int stencilReference)
    {
      this.m_ProfilerTag = profilerTag;
      this.m_ShaderTagIdList.Add(new ShaderTagId("UniversalForward"));
      this.m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));
      this.m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
      this.renderPassEvent = evt;
      this.m_FilteringSettings = new FilteringSettings(new RenderQueueRange?(renderQueueRange), (int) layerMask, uint.MaxValue, 0);
      this.m_RenderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
      this.m_IsOpaque = opaque;
      if (!stencilState.enabled)
        return;
      this.m_RenderStateBlock.stencilReference = stencilReference;
      this.m_RenderStateBlock.mask = RenderStateMask.Stencil;
      this.m_RenderStateBlock.stencilState = stencilState;
    }

這個Pass會執行標有以上三個tag(UniversalForward、LightweightForward、SRPDefaultUnlit)的shaderPass。通過是否是Opaque決定這個Pass是用來渲染不透明物體還是半透明物體,最后初始化了模板測試相關數據。

接下來是執行(Execute)方法:

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
      CommandBuffer commandBuffer = CommandBufferPool.Get(this.m_ProfilerTag);
      using (new ProfilingSample(commandBuffer, this.m_ProfilerTag, (CustomSampler) null))
      {
        context.ExecuteCommandBuffer(commandBuffer);
        commandBuffer.Clear();
        Camera camera = renderingData.cameraData.camera;
        SortingCriteria sortingCriteria = this.m_IsOpaque ? renderingData.cameraData.defaultOpaqueSortFlags : SortingCriteria.CommonTransparent;
        DrawingSettings drawingSettings = this.CreateDrawingSettings(this.m_ShaderTagIdList, ref renderingData, sortingCriteria);
        context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref this.m_FilteringSettings, ref this.m_RenderStateBlock);
        RenderingUtils.RenderObjectsWithError(context, ref renderingData.cullResults, camera, this.m_FilteringSettings, SortingCriteria.None);
      }
      context.ExecuteCommandBuffer(commandBuffer);
      CommandBufferPool.Release(commandBuffer);
    }

這個方法和我們寫SRP時基本一樣,排序設置是根據Opaque字段決定,DrawSettings通過CreateDrawingSettings方法生成:

public DrawingSettings CreateDrawingSettings(
      List<ShaderTagId> shaderTagIdList,
      ref RenderingData renderingData,
      SortingCriteria sortingCriteria)
    {
      if (shaderTagIdList == null || shaderTagIdList.Count == 0)
      {
        Debug.LogWarning((object) "ShaderTagId list is invalid. DrawingSettings is created with default pipeline ShaderTagId");
        return this.CreateDrawingSettings(new ShaderTagId("UniversalPipeline"), ref renderingData, sortingCriteria);
      }
      DrawingSettings drawingSettings = this.CreateDrawingSettings(shaderTagIdList[0], ref renderingData, sortingCriteria);
      for (int index = 1; index < shaderTagIdList.Count; ++index)
        drawingSettings.SetShaderPassName(index, shaderTagIdList[index]);
      return drawingSettings;
    }

最后DrawRenderers,但是我們發現后面還有個RenderObjects方法,這個方法是對以前一些TagId做的兼容,有以下Tag:

private static List<ShaderTagId> m_LegacyShaderPassNames = new List<ShaderTagId>()
    {
      new ShaderTagId("Always"),
      new ShaderTagId("ForwardBase"),
      new ShaderTagId("PrepassBase"),
      new ShaderTagId("Vertex"),
      new ShaderTagId("VertexLMRGBM"),
      new ShaderTagId("VertexLM")
    };

我們會發現非常簡短的代碼,一個Pass就完成了,可見我們如果要擴展Pass也是方便的很(其實最關鍵是核心方法都被封裝了,不需要我們操心,哈哈哈~)

接下來我們看一下DepthOnlyPass,構造函數確定了FilterSettings和RenderEvent(過於簡單,就不貼代碼了),Setup函數如下:

public void Setup(
      RenderTextureDescriptor baseDescriptor,
      RenderTargetHandle depthAttachmentHandle)
    {
      this.depthAttachmentHandle = depthAttachmentHandle;
      baseDescriptor.colorFormat = RenderTextureFormat.Depth;
      baseDescriptor.depthBufferBits = this.kDepthBufferBits;
      baseDescriptor.msaaSamples = 1;
      this.descriptor = baseDescriptor;
    }

這里不了解RenderTextureDescriptor 結構的小伙伴可以去官方api查一下,里面記錄的是對於RT的一些描述信息,depthBufferBits默認給的32bit。RenderTargetHandle結構主要記錄了一個shader property id。

接下來是一個Configure方法:

    public override void Configure(
      CommandBuffer cmd,
      RenderTextureDescriptor cameraTextureDescriptor)
    {
      cmd.GetTemporaryRT(this.depthAttachmentHandle.id, this.descriptor, FilterMode.Point);
      this.ConfigureTarget(this.depthAttachmentHandle.Identifier());
      this.ConfigureClear(ClearFlag.All, Color.black);
    }

這個方法是獲取RT,所有Pass的Configure方法都是在Pass的Execute方法之前執行,說到這里,筆者忽然發現這些Pass過於簡單,沒有什么好說的,於是大概看了看所有的Pass,挑筆者覺得重要的東西說一下吧:

首先我們看一下Pass的執行順序:

MainLightShadowCasterPass、AdditionalLightsShadowCasterPass、DepthOnlyPass、ScreenSpaceShadowResolvePass、ColorGradingLutPass、OpaqueForwardPass、CopyDepthPass、DrawSkyboxPass、CopyColorPass、TransparentForwardPass、InvokeOnRenderObjectCallbackPass、PostProcessPass、CapturePass、FinalBlitPass。

需要注意的是比默認管線多了CopyColor和CopyDepth兩個步驟,這兩個步驟對於我們做水面需要抓取color做折射的效果很有幫助,但是缺陷是無法多重折射,因為Color只有Opaque信息。

ShadowCasterPass和ScreenSpaceShadowResolvePass熟悉屏幕空間陰影的實現的伙伴都很熟悉了,在這里就不贅述了。

DepthOnlyPass主要繪制了有“DepthOnly” Tag的Pass,需要注意的是DepthOnly是可以AlphaClip的。

CapturePass時所有渲染行為結束時的Pass,目前還不知道可以用來干什么。

其他pass基本上見名知意。接下來的幾節筆者會挑URP的幾個shader一起學習一下,通過學習官方提供的shader,增加對URP渲染代碼編寫的熟練度,避免踩一些坑,也可以學習到不同問題下Unity官方的解決思路。


免責聲明!

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



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