[toc]
# URP 的渲染流程小析
- renderingData 设置
- Unity Cull
- Enqueue RenderFeature 的 Pass
- UniversalRenderer 的 Setup
- 灯光 PreSetup
- 设置 RenderingData
- 分配需要的贴图等数据并执行 (ExecuteCommandeBuffer)
- 将主要的 Pass 推入 RenderQueue (但不执行)
- Execute
- SetupRenderfeature 的 pass
- 执行每个 Pass 的 OnCameraSetup (同时 ExecuteCommandBuffer)
- 设置 Shader 的 Time 变量
- pass 排序
- 调用 Pass 的 Configure (同时 ExecuteCommandBuffer)
- SetupNativeRenderPassFrameData
- SetupLights
- Execute 实际渲染阶段
- 先执行被标记为 BeforeRendering 的 Pass
- 再次设置 TimeValue
- 执行 MainRenderingOpaque 的 Pass
- 执行 MainRendringTransparent 的 Pass
- 绘制被标记为 PreImageEffects 的 Gizmos
- 绘制 AfterRendering 的 Pass
- 绘制 WireOverlay
- 绘制被标记为 PostImageEffects 的 Gizmos
- 调用一次 FinishRendering
- scriptableRenderContext.Submit()
# UniversalRenderer 的 Setup 阶段
如果只需要渲染深度图
1 | bool isOffscreenDepthTexture = cameraData.targetTexture != null && cameraData.targetTexture.format == RenderTextureFormat.Depth; |
先设置 RenderingLayer
,比如如果是 OpenGL 的设备,则禁止获取 RenderingLayer 然后根据渲染模式是否是延迟渲染模式以及渲染事件 (?) 是否是 Opaque 之类的 如果支持主光源阴影,则加入 m_MainLightShadowCasterPass
pass
如果支持 Addtional 光源阴影,则加入 m_AdditionalLightsShadowCasterPass
如果需要分配深度图,则直接分配深度图,这点实际上是通过 cmd.SetGlobalTexture
来进行的
1 | var depthDescriptor = cameraTargetDescriptor; |
分配法线贴图,这里聊一下 Unity 的贴图重新分配 ReAllocateIfNeed
和 ReAllocateGBufferIfNeed
ReallocateGBufferIfNeed,首先会先对比 gbuffer 存的贴图 instanceId 和 RTHandles 里的 instanceId 是否一致,不一致则不进行分配。然后它的下一级函数也会调用
ReAllocateIfNeed
,这个函数里会进行两个事情
- 检查新 RT 和旧 RT 设置是否相同,如果相同没必要重新分配
- 不相同则重新分配
其中检查两个 RT 是否相同的方法是对比 RTDescriptor 中的每一个参数 分配贴图时会先 Release 掉旧的贴图,然后 Alloc 一个新的贴图
1 | handle?.Release(); |
在法线贴图分配的最后,会设置一下全局贴图,而且如果是延迟管线的话,会同时将 handle 设置到 _CameraNormalsTexture
上
1 | cmd.SetGlobalTexture(normalsTexture.name, normalsTexture.nameID); |
# DepthNormalPrepass
在这个阶段进行深度与法线贴图的渲染,其中 DepthNormalPrepass 可以设置三个 handler,即 depth,normal,decal
1 | public void Setup(RTHandle depthHandle, RTHandle normalHandle, RTHandle decalLayerHandle) |
对于延迟渲染而言,在这个阶段和其他管线是有差别的,它在这一阶段并没有将深度和法线渲染进 m_DepthTexture
和 m_NormalsTexture
中,而是在后面的延迟渲染 Pass 才将其加入进去
# 级联阴影 Pass
通过主要贡献光源的 Light 的 shadowMap 配置和级联数量来计算 CascadeShadow 的贴图大小
1 | int shadowResolution = ShadowUtils.GetMaxTileResolutionInAtlas(renderingData.shadowData.mainLightShadowmapWidth,renderingData.shadowData.mainLightShadowmapHeight, m_ShadowCasterCascadesCount); |