遮挡剔除:原理、实现与性能优化
什么是遮挡剔除
遮挡剔除(Occlusion Culling)是一种渲染优化技术,在渲染前判断物体是否被其他不透明物体完全遮挡,如果不可见则跳过渲染,从而减少 Draw Call 和 GPU 负载。与视锥剔除(Frustum Culling)不同,视锥剔除仅剔除视野外的物体,而遮挡剔除处理被遮挡的物体。
遮挡剔除的原理
遮挡剔除通常基于深度缓冲或空间数据结构。常见方法包括:
- **硬件遮挡查询**:使用 GPU 查询(如 D3D 的 ID3D11Query)测试物体的包围盒是否通过深度测试,如果未通过则说明被遮挡。
- **软件光栅化**:CPU 光栅化遮挡体到低分辨率深度缓冲,然后测试物体包围盒。
- **层次 Z 缓冲**:维护一个金字塔形深度缓冲,快速测试包围盒可见性。
- **门户剔除**:适用于室内场景,通过门洞传播可见性。
在游戏引擎中,通常使用保守的包围盒(如 AABB)进行测试,以减少计算量。
在引擎中的应用
- **Unity**:使用 Umbra 中间件提供遮挡剔除。需要在 Window > Rendering > Occlusion Culling 中烘焙遮挡数据(设置遮挡区域、静态物体等)。运行时自动执行。
- **Unreal Engine**:默认启用遮挡剔除,使用硬件查询和软件光栅化结合。可以通过 `r.EnableOcclusionCulling` 控制。
遮挡剔除的注意事项
- **动态物体**:遮挡剔除对动态物体效果有限,通常仅对静态物体高效。
- **烘焙**:Unity 的遮挡剔除需要烘焙场景,修改场景后需重新烘焙。
- **粒度**:通常以物体或组件为单位,过大或过小都会影响效果。
- **移动端**:移动端 GPU 查询可能开销大,可使用简化的 PVS(潜在可见集)预计算。
与其他剔除技术的比较
- **视锥剔除**:剔除视野外物体,是最基本的剔除。
- **背面剔除**:剔除背向摄像机的三角形,硬件自动完成。
- **遮挡剔除**:剔除被遮挡物体,进一步减少渲染负载。
实际渲染中,三种剔除技术通常结合使用。
常见问题
遮挡剔除与视锥剔除有什么区别?
视锥剔除剔除视野外的物体,遮挡剔除剔除被其他物体遮挡的物体。
Unity 中如何使用遮挡剔除?
需要将物体标记为 Occluder Static 或 Occludee Static,然后在 Occlusion Culling 窗口中烘焙。
遮挡剔除对移动端性能有帮助吗?
有帮助,但移动端可能使用简化方法,如预计算可见性(PVS)。
动态物体能被遮挡剔除吗?
可以,但通常使用硬件查询,性能开销可能较大。有些引擎对动态物体使用保守剔除。
遮挡剔除会不会产生错误剔除?
如果算法过于激进,可能错误剔除可见物体。因此通常使用保守测试,如使用包围盒代替精确网格。
常见问题
遮挡剔除与视锥剔除有什么区别?
视锥剔除剔除视野外物体,遮挡剔除剔除被其他物体遮挡的物体。
Unity中如何使用遮挡剔除?
将物体标记为Occluder Static或Occludee Static,然后在Occlusion Culling窗口中烘焙。
遮挡剔除对移动端性能有帮助吗?
有帮助,但移动端可能使用简化方法,如预计算可见性(PVS)。
动态物体能被遮挡剔除吗?
可以,但通常使用硬件查询,性能开销可能较大。有些引擎对动态物体使用保守剔除。
遮挡剔除会不会产生错误剔除?
如果算法过于激进,可能错误剔除可见物体。因此通常使用保守测试,如包围盒代替精确网格。