Unity URP UniversalRenderer 细瞧
2024-02-01 本文已影响0人
暴走TA
简介: 看过了 UniversalRenderPipeline 后,我们会发现,剩下的渲染入口就到了 UniversalRenderer,捋完 UniversalRenderer,我们大抵也就明白了,从引擎的一次绘制调用,到我们的最终绘制命令发出是怎么一个流程了,明白了这些, 想改管线还不是轻而易举的事。我们开始吧!!
软件: unity 2022.3.14f1c1
管线:com.unity.render-pipelines.universal@14.0.9
背景
我们显示 梳理了 主要类之间的关系 ,又扒开UniversalRenderPipeline看了一遍知晓了:
- pipeline 和 renderer 都是通过对应的 data 创建的,
- pipeline 内使用的 renderer 是通过 相机的 UniversalAdditionalCamera 组件获得的
- pipeline 内将所有的数据封装到 CameraData ,然后又将 CameraData 封装到 RenderingData 进行后续的数据传递和使用
- pipeline 调用 render 的 Execute 之前会调用 render 的 Setup 进行设置
开扒
UniversalRenderer 的父子关系
- UniversalRenderer 继承自 ScriptableRenderer
- UniversalRenderer 重写了 ScriptableRenderer 的几个方法
- Dispose
- ReleaseRenderTargets
- Setup
- SetupLights
- SetupCullingParameters
- FinishRendering
- SwapColorBuffer
- GetCameraColorFrontBuffer
- GetCameraColorBackBuffer
- EnableSwapBufferMSAA
- ScriptableRenderer 的 Execute 并不是一个 virtual 型的,可以看出 ScriptableRenderer 的设计初衷就是,让我们在子类里面做一些设置,和处理一些回掉,实际的渲染运行逻辑应该是一致的。
- UniversalRenderer 声明了一个 RenderPassInputSummary 结构体,用来存储一些功能的开光状态、
- UniversalRenderer 包含了大量的 ScriptableRenderPass
UniversalRenderer 流程 (Setup)
通过 UniversalRenderer 的继承覆写,我们可以得到一个结果,那就是具体的派生类只要负责设置和处理一些回调即可。那对我们普通渲染最重要的一个方法就是 Setup 方法了。其它的覆写函数比较短,看名字也比较容易理解。我们主要看 Setup
我这一版的 UniversalRenderer 的 Setup 函数有 780+ 行,看来真的很重要, 接下来就看看 Setup 具体都设置了什么
- 灯光设置
- 从 renderingData 获取后面代码要经常用到的 CameraData、Camera、RenderTextureDescriptor,cmd 对象
- 设置 Debug 相关,我直接跳过了
- 获取一些渲染状态,如 相机类型、isOffscreenDepthTexture、
- 是否需要创建 createColorTexture
- 是否需要 requiresRenderingLayer
- 是不是GL 设备
- 是否需要 DepthNormal
- 处理 延迟灯光设置
- 检查是否有后处理开启,是否有抗锯齿等最终后处理开启
- 默认情况下最终后处理是在UI绘制之后使用的,例如 抗锯齿
- 是否需要创创建 LUT ,generateColorGradingLUT
- 是否开启了 isGizmosEnabled
- 根据前面获取的条件,判断是否需要创建对应的纹理
- 进行 base 相机和 overlay 相机的设置
- base 设置时有可能需要重新创建 attachment
- overlay 默认状态下是使用 base 的 attachment
- 检查是否需要加入 m_MainLightShadowCasterPass
- 检查是否需要加入 m_AdditionalLightsShadowCasterPass
- 又是一个debug 设置
- 设置相机的 useDepthPriming
- Deferred 延迟渲染的一部分相关, 我跳过
- requiresRenderingLayer 相关设置,我跳过
- 检查是否需要加入 depth 和 normal 相关pass
- 检查是否需要加入 generateColorGradingLUT
- 一个 XR 的pass
- 判断延迟渲染的 pass 还是 renderOpaqueForwardPass
- 天空盒的 pass
- m_CopyDepthPass
- m_CopyColorPass
- m_MotionVectorPass
- m_TransparentSettingsPass
- m_RenderTransparentForwardPass
- m_OnRenderObjectCallbackPass
- 根据 (shouldRenderUI && outputToHDR) 判断是否添加 m_DrawOffscreenUIPass
- 判断 applyFinalPostProcessing 的值,是否需要为true
- 判断 needsColorEncoding 是否需要进行色彩编码
- 如果需要后处理,则处理一些 rt
- 根据相机是否是堆栈的最后一个来决定渲染,
- 如果不是,但是有后处理开启,则添加 postProcessPass
- 如果是堆栈最后一个则会有更多的处理
- 堆栈的最后一个相机渲染设置比较多
- 设置一个 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 ,然后通过遍历的形式进行渲染调用的