0%

【Real-Time Rendering】遮挡剔除总结

本篇对常见的遮挡剔除技术进行总结概括,主要包括:

  • Precomputed Visibility
  • Portal-Culling
  • Software Occlusion
  • Occlusion Query
  • Hierarchical Z-Buffer

1 Precomputed Visibility

预计算可见性是比较简单的遮挡剔除方案,UE 中内置了这一方法。官方文档:预计算可视性体积 | 虚幻引擎文档 (unrealengine.com)

其基本思路是就是先将场景划分成一个个 Cell,让后对于每个 Cell 区域,预计算出摄影机在这个 Cell 范围内时,所有可能看到的物体,并将可见信息保存下来。这样在运行时就可以直接查表来得到所有静态物体的可见信息,运行时开销几乎为 0。

PVis_VisualizationEnabled

当然这种方式的缺点也很明显,完全无法剔除动态物体,并且静态物体可见性全部都是不可变的。并且对于比较自由的大型场景,计算量和存储量都非常大,因此只适用于线性流程关卡等相机移动范围有限的场景中。

如果我们想要实现对动态物体的剔除,可以对该算法进行改进:在每个 Cell 中,同时保存其他 Cell 的可见性。对于小型的动态物体,我们先计算出动态物体所在的 Cell 坐标,然后根据 Cell 之间的可见性信息,判断可见性。这样做会额外消耗内存,如果动态的小型物体较多时,可以考虑配合使用。

2 Portal-Culling

这种方式也是将场景划分成 Cell,不同的是,烘焙时保存的是每两个相邻 Cell 之间的连通性。这样,在运行时,根据摄影机所在的位置的 Cell 和观察方向,就可以根据 Cell 间的连通性信息,快速计算出目标物体是否处于可见范围内。

相对上面完全的预计算,这种方式的优点就是可以剔除动态物体,同时提供了些许的静态遮挡物体变化的灵活性。比如有扇可以开关的门,当门被打开后,就可以将门两侧的 Cell 的连通打开。Unity 自带的遮挡剔除使用这种方案。

3 Software Occlusion

软光栅遮挡查询是 UE 中面向移动端的一种遮挡查询方案,官方文档:面向移动平台的软件遮挡查询 | 虚幻引擎文档 (unrealengine.com)

这种方式需要手动标记好大型的用来遮挡的物体,在运行时,将遮挡物的包围盒(或最高 LOD 级别的模型)软光栅到 CPU 内存中的 z-buffer 上,然后根据 z-buffer 中的深度信息,根据需要剔除物体的包围盒,实时计算遮挡信息。

soq_sceneOccludersHighlighted

这种方式缺点是对 CPU 端压力很大,优点是相对前面两种方案,软光栅剔除提供了非常大的灵活性,支持完全可变或任意大小的场景,适用于流式关卡或者大世界中的遮挡剔除。并且相对 GPU 实现的遮挡剔除,这种方案完全不用担心硬件兼容问题。但是由于 CPU 的软光栅计算压力非常大,因此我们需要注意,不能在光栅化时计算太多的物体,不能使用精细的模型计算。

4 Occlusion Query

硬件遮挡查询利用 GPU 进行遮挡剔除,其思想也非常简单,首先使用一个简单的 depth-only 的 pass 将深度写入到 z-buffer 中,然后使用物体的包围盒传入到 GPU 进行遮挡测试,也就是判断深度,如果测试发现所有像素都被遮挡,说明这个物体是被遮挡的物体,否则的话认为是可见的。

由于从 GPU 回读数据到 CPU 通常很慢,因此通常会将得到的数据放在下一帧中作为剔除数据来使用,这样遮挡剔除其实是延迟一帧(移动端延迟两帧)生效的。不过一般来说,延迟一帧的剔除对实际的渲染影响并不大。

几乎所有的图形 API 都提供硬件遮挡查询,UE 默认也采用这种方式进行遮挡剔除。

当然硬件遮挡查询也存在一定的问题,比如:

  • 虽然基于 GPU 的判断效率高,但涉及数据传输,在大规模场景下会造成 CPU 一直等待 GPU 查询结果返回造成 GPU 性能饥饿的情况
  • 虽然基于 GPU 判断效率高,不过在复杂场景下仍有大量渲染目标需要被测试,仍有提升空间

因此有人提出了改进的 Coherent Occlusion Culling(CHC) 算法,其核心思想是:

  • 利用 BVH(Bounding Volume Hirachical)管理场景,并利用 Spatial Coherence(空间相关性)减少每一帧需要进行遮挡查询的次数。
  • 重用上一帧的查询结果,利用 Time Coherence(时间相关性)进一步减少查询次数。
  • 维护一个查询队列,延迟进行查询的时间,并利用渲染部分场景的时间来填充 CPU 等待 GPU 查询结果返回的时间,减少 GPU 的饥饿。

具体可以查看Coherent Occlusion Culling(CHC)算法的原理与实现一文。

5 Hierarchical Z-Buffer

HZB 是多 Mip 层级的 z-buffer,每个更高级别 Mip 的 buffer 记录上一级别中周围四点中最远处的深度值。

image-20220807102055112

将 HZB 生成后,就可以将待剔除物体的包围盒信息传入到 Computer Shader 中进行计算,计算时会选择最适合的 Mip 级别进行遮挡测试。在屏幕中占比更大的物体会选择更高级别 Mip 的深度进行测试,因为更大的物体更容易被看到,就可以用更高级别的 Mip 中的深度,而不必取过于精细的深度来判断。

具体来说,要测试对象是否被遮挡,可以将其包围体投射到屏幕空间,并估计在 z-pyramid 中的 Mip 级别。将对象的包围体投影到屏幕空间。使用最长的边(像素)计算 Mip 等级:

image-20220807102419175

然后根据选定的 Mip 测试遮挡。如果结果不明确,可以继续使用更细的 Mip 级别进行测试。

---- 本文结束 知识又增加了亿点点!----

文章版权声明 1、博客名称:LycTechStack
2、博客网址:https://lz328.github.io/LycTechStack.github.io/
3、本博客的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主进行删除处理。
4、本博客所有文章版权归博主所有,如需转载请标明出处。