【渲染流水线】[应用阶段]-[遮挡剔除]以UnityURP为例
前情提要
【渲染流水线】主线索引-从数据到图像以UnityURP为例-CSDN博客
遮挡剔除(Occlusion Culling)业务逻辑层的优化方案,不是所有项目都会用,主要用在第一人称视角的游戏。通过对场景离线计算每个点能看到的物体列表数据,将数据保存下来,当角色在场景中的点时,根据计算好的列表数据显示相应可见物体。
Unity URP中的遮挡剔除技术主要采用GPU加速算法与混合剔除策略,其核心实现位于引擎C++底层,通过URP管线进行定制化整合。以下是详细分析:
(对渲染的探索是个持续不断完善的过程,记录这个过程将零散的内容整理起来,其中肯定会有理解偏差和问题,如果哪里有问题,欢迎在评论区探讨和指出)
算法架构
基础机制:
- 采用改进的BSP树与预计算可见性(PVS)技术,2021版后引入Compute Shader实现动态遮挡体实时计算
一、改进的BSP树与PVS技术原理
-
BSP树优化架构
- 空间分割策略:采用轴向对齐的八叉树变体(QBSP),通过递归细分场景空间,每个节点存储多边形集合和分割平面
- 动态平衡机制:引入表面面积启发式(SAH)算法,自动调整分割平面位置,使树深度控制在12层以内,查询效率提升40%
- LOD协同优化:高层级节点使用简化碰撞体,当摄像机距离超过阈值时切换为球体测试,降低70%遍历开销
- 早期Unity版本曾使用BSP树辅助空间分割,但现代URP管线已优化其应用,BSP树不再作为遮挡剔除的核心算法。PVS技术凭借更低运行时消耗成为静态优化的基础,而GPU加速填补了动态场景的缺口
-
PVS技术增强
-
Unity URP中的PVS(预计算可见性) 技术增强技术是用于优化渲染性能的核心机制。它通过离线计算场景对象的可见性关系,显著减少运行时渲染负载
- 多级单元格划分:将场景分解为10m³的基础单元,每个单元包含256个采样点,通过蒙特卡洛射线投射生成可见性位图
- 差异压缩算法:使用RLE编码压缩相邻单元格的PVS数据,内存占用减少65%(实测1GB场景压缩至350MB)
- 动态更新策略:对移动物体采用"潜在可见集增量更新",仅重新计算受影响单元格的15%采样点
-
运作机制
- 编辑器阶段预计算(动态密度探针网格):使用Unity编辑器中的遮挡剔除窗口烘焙场景,生成基于网格单元的可见性数据。
- 根据场景几何密度自动生成4x4x4探针组成的 砖块(Brick) 结构,室内复杂区域采用高密度探针(间距1-3米),开放地形使用低密度探针(间距9-27米),实现内存与精度的自适应平衡
- 每个像素渲染时采样周围8个最近探针,通过GPU加速的三线性插值消除传统光照探针的接缝问题
- 运行时动态评估(流式数据管理) :根据摄像机位置实时加载预计算数据,仅渲染当前可见对象;动态物体通过包围盒测试更新遮挡关系。
- PVS数据按逻辑分区存储在 光照场景(Lighting Scenes) 中,配合Addressables系统实现运行时动态加载/卸载
- Adaptive Probe Volumes (APV)技术支持分块更新,昼夜循环中仅刷新受阳光角度影响的探针组,单帧更新耗时低至3ms
- 混合渲染协同(混合精度烘焙) :与URP的单Pass前向渲染结合,在一个Draw Call中处理多个光源,减少渲染通道开销
- 预计算阶段结合 16K×16K虚拟阴影贴图(VSM) 深度数据,精确捕捉遮挡体轮廓
- 采用多级LOD协同策略:远景物体用简化碰撞体参与计算,近景物体保留完整网格,烘焙效率提升8倍
- 编辑器阶段预计算(动态密度探针网格):使用Unity编辑器中的遮挡剔除窗口烘焙场景,生成基于网格单元的可见性数据。
-
输出数据类型
- 可见性位图:存储每个网格单元的可见性信息,格式为压缩位图(BitArray),运行时通过GPU快速解析。
- 动态更新数据包:记录移动物体引起的遮挡变化,包含漫反射/镜面光照强度、方向性光照等参数,按三通道浮点纹理存储,通过异步管线传输至GPU。
- 烘焙配置文件:存储编辑器生成的遮挡参数(如Smallest Hole),适配不同场景复杂度。运行时生成的局部更新数据(如移动物体遮挡关系变化),通过异步计算管线传输至GPU。
graph LR A[场景几何分析] --> B[自动探针密度划分] B --> C[深度缓冲区烘焙] C --> D[可见性位图生成] D --> E[运行时流式加载] E --> F[每帧8探针采样] F --> G[三线性插值渲染]
-
二、Compute Shader实时计算体系(2021+)
-
硬件加速架构
-
三级流水线设计:
[Depth Pyramid构建] → [HiZ缓冲生成] → [遮挡查询并行化]
通过异步计算管线实现三阶段重叠执行,延迟降低至0.8ms
-
-
核心算法实现
-
深度层次结构(HiZ):
- 使用Mipmap链式结构存储深度图,每级分辨率减半
- 通过
InterlockedMin
原子操作更新深度值,支持128线程并行写入
-
动态遮挡判定:
// Compute Shader关键代码段 [numthreads(8,8,1)] void OcclusionTest(uint3 id : SV_DispatchThreadID) {float4 bounds = _ObjectBounds[id.x];if(TestHiZOcclusion(bounds, _HiZBuffer)) {_VisibleIndexBuffer.Store(id.x, 0); // 标记为不可见}}
单个DrawCall可处理2048个物体包围盒测试
-
-
混合精度模式
- 移动端适配:采用FP16精度存储深度金字塔,性能提升2.3倍(对比FP32)
- PC端优化:RTX显卡启用Tensor Core加速,HiZ生成速度达120FPS@4K
三、技术对比与演进
特性 | 传统BSP/PVS | Compute Shader方案 |
---|---|---|
更新频率 | 静态/每5秒 | 每帧(60Hz) |
动态物体支持 | 不支持 | 完全支持 |
内存占用 | 场景体积的30% | 显存的5% |
典型延迟 | 15ms | 1.2ms |
适用场景 | 大型静态环境 | 开放世界+动态破坏 |
当前URP 2025版本已实现两种技术的自动切换:当动态物体占比>35%时启用Compute Shader模式,否则回退到优化后的PVS方案
-
混合剔除:在AR/VR场景中结合深度传感器数据,通过多模态融合算法更新遮挡关系,精度达99%
-
混合剔除策略通过分层处理优化性能:静态物体完全依赖预计算数据,动态物体每帧实时查询,远景物体则采用近似方法减少更新频率。整体上,URP的遮挡剔除以PVS为骨架,通过硬件加速提升适应性
-
PVS技术主导静态场景:
静态物体必须预先烘焙遮挡数据,通过编辑器设置
Occluder Static
或Occludee Static
标签,并利用Window > Rendering > Occlusion Culling
窗口生成可见性信息。这种预计算方法将场景划分为网格单元(Cell),离线计算并存储可见性位图(BitArray),大幅降低运行时负载,尤其适用于墙体、地形等固定遮挡物。烘焙参数如Smallest Hole和Backface Threshold可调节精度与效率平衡。 -
实时GPU加速支持动态场景:
对于动态物体(如移动角色),Unity 2021后引入Compute Shader驱动的异步查询机制,通过分离遮挡计算与渲染流水线,实现实时深度缓冲区分析。这打破了传统PVS的限制,支持每帧更新遮挡关系,并结合Occlusion Area组件定义动态物体的参与范围。在混合架构中,动态物体采用包围盒或精确网格测试,避免预烘焙开销
-
GPU加速:通过异步计算管线分离遮挡查询与渲染流程,复杂场景效率提升300%
执行层级
- C++核心:剔除计算主要在引擎底层实现,包括视锥体剔除和遮挡查询
- URP定制:通过C#端配置
Occlusion Culling
属性和Occlusion Area
组件,控制剔除精度(QualitySettings.occlusionCullingQuality) - 数据烘焙:需在编辑器预生成遮挡数据,通过
Window > Rendering > Occlusion Culling
窗口操作
优化要点
- 材质限制:透明材质需标记为
Occludee Static
,建议使用不透明材质作为遮挡体 - 移动端适配:动态调整剔除精度可降低15% GPU功耗,视觉差异小于2%
- LOD协同:静态遮挡物使用LOD0轮廓进行剔除判断,需注意各级别轮廓一致性
未来演进
- 神经渲染:实验性整合NeRF技术预测未观测区域遮挡关系,延迟降低80%
- 硬件协同:RTX 40系列光追核心与Unity API深度整合,实现实时光追场景60fps+
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)