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官方的解决思路。

原文地址:https://www.cnblogs.com/shenyibo/p/12518017.html