Unity URP UniversalRenderer 细瞧

2024-02-01  本文已影响0人  暴走TA

简介: 看过了 UniversalRenderPipeline 后,我们会发现,剩下的渲染入口就到了 UniversalRenderer,捋完 UniversalRenderer,我们大抵也就明白了,从引擎的一次绘制调用,到我们的最终绘制命令发出是怎么一个流程了,明白了这些, 想改管线还不是轻而易举的事。我们开始吧!!
软件: unity 2022.3.14f1c1
管线:com.unity.render-pipelines.universal@14.0.9

背景

我们显示 梳理了 主要类之间的关系 ,又扒开UniversalRenderPipeline看了一遍知晓了:

  1. pipeline 和 renderer 都是通过对应的 data 创建的,
  2. pipeline 内使用的 renderer 是通过 相机的 UniversalAdditionalCamera 组件获得的
  3. pipeline 内将所有的数据封装到 CameraData ,然后又将 CameraData 封装到 RenderingData 进行后续的数据传递和使用
  4. pipeline 调用 render 的 Execute 之前会调用 render 的 Setup 进行设置

开扒

UniversalRenderer 的父子关系

  1. UniversalRenderer 继承自 ScriptableRenderer
  2. UniversalRenderer 重写了 ScriptableRenderer 的几个方法
    • Dispose
    • ReleaseRenderTargets
    • Setup
    • SetupLights
    • SetupCullingParameters
    • FinishRendering
    • SwapColorBuffer
    • GetCameraColorFrontBuffer
    • GetCameraColorBackBuffer
    • EnableSwapBufferMSAA
  3. ScriptableRenderer 的 Execute 并不是一个 virtual 型的,可以看出 ScriptableRenderer 的设计初衷就是,让我们在子类里面做一些设置,和处理一些回掉,实际的渲染运行逻辑应该是一致的。
  4. UniversalRenderer 声明了一个 RenderPassInputSummary 结构体,用来存储一些功能的开光状态、
  5. UniversalRenderer 包含了大量的 ScriptableRenderPass
RenderPassInputSummary 包含的属性

UniversalRenderer 流程 (Setup)

通过 UniversalRenderer 的继承覆写,我们可以得到一个结果,那就是具体的派生类只要负责设置和处理一些回调即可。那对我们普通渲染最重要的一个方法就是 Setup 方法了。其它的覆写函数比较短,看名字也比较容易理解。我们主要看 Setup
我这一版的 UniversalRenderer 的 Setup 函数有 780+ 行,看来真的很重要, 接下来就看看 Setup 具体都设置了什么

  1. 灯光设置
  2. renderingData 获取后面代码要经常用到的 CameraData、Camera、RenderTextureDescriptor,cmd 对象
  3. 设置 Debug 相关,我直接跳过了
  4. 获取一些渲染状态,如 相机类型、isOffscreenDepthTexture、
    • 是否需要创建 createColorTexture
    • 是否需要 requiresRenderingLayer
    • 是不是GL 设备
    • 是否需要 DepthNormal
  5. 处理 延迟灯光设置
  6. 检查是否有后处理开启,是否有抗锯齿等最终后处理开启
    • 默认情况下最终后处理是在UI绘制之后使用的,例如 抗锯齿
    • 是否需要创创建 LUT ,generateColorGradingLUT
    • 是否开启了 isGizmosEnabled
  7. 根据前面获取的条件,判断是否需要创建对应的纹理
  8. 进行 base 相机和 overlay 相机的设置
    • base 设置时有可能需要重新创建 attachment
    • overlay 默认状态下是使用 base 的 attachment
  9. 检查是否需要加入 m_MainLightShadowCasterPass
  10. 检查是否需要加入 m_AdditionalLightsShadowCasterPass
  11. 又是一个debug 设置
  12. 设置相机的 useDepthPriming
  13. Deferred 延迟渲染的一部分相关, 我跳过
  14. requiresRenderingLayer 相关设置,我跳过
  15. 检查是否需要加入 depthnormal 相关pass
  16. 检查是否需要加入 generateColorGradingLUT
  17. 一个 XR 的pass
  18. 判断延迟渲染的 pass 还是 renderOpaqueForwardPass
  19. 天空盒的 pass
  20. m_CopyDepthPass
  21. m_CopyColorPass
  22. m_MotionVectorPass
  23. m_TransparentSettingsPass
  24. m_RenderTransparentForwardPass
  25. m_OnRenderObjectCallbackPass
  26. 根据 (shouldRenderUI && outputToHDR) 判断是否添加 m_DrawOffscreenUIPass
  27. 判断 applyFinalPostProcessing 的值,是否需要为true
  28. 判断 needsColorEncoding 是否需要进行色彩编码
  29. 如果需要后处理,则处理一些 rt
  30. 根据相机是否是堆栈的最后一个来决定渲染,
    • 如果不是,但是有后处理开启,则添加 postProcessPass
    • 如果是堆栈最后一个则会有更多的处理
  31. 堆栈的最后一个相机渲染设置比较多
    • 设置一个 SetupFinalPassDebug
    • 若果开启了后处理,则检查是否需要 Gamma 矫正,然后添加postProcessPass
    • 应用最终后处理 applyFinalPostProcessing //Do FXAA or any other final post-processing effect that might need to run after AA.
    • 根据是否需要截屏 加入 m_CapturePass
    • 根据是否需要最终绘制到屏幕上 加入 cameraTargetResolved
    • 判断都是需要绘制 overlayUI 加入 m_DrawOverlayUIPass

总结

UniversalRenderer 看上去很长,其实大部分都是为了确定哪些 pass 是真正需要绘制的,然后通过 EnqueuePass 将需要的 pass 加入到队列中。
所以 UniversalRenderer 中没有什么实际的 blit 操作,大部分的操作都是 EnqueuePass 方法将 ScriptableRenderPass 添加到基类的 m_ActiveRenderPassQueue ,然后通过遍历的形式进行渲染调用的

上一篇 下一篇

猜你喜欢

热点阅读