游戏中遮挡剔除方案总结

2020/08/03 08:05
阅读数 1.2K


遮挡剔除是当一个物体被其他物体遮挡住而不在摄像机的可视范围内时不对其进行渲染。在3D图形计算中并不是一个自动进行的过程,因为在绝大多数情况下离相机最远的物体首先被渲染,靠近摄像机的物体后渲染并覆盖先前渲染的物体(这种重复渲染又叫做"OverDraw"), 它不同于视锥剪裁,视锥剪裁只是不渲染摄像机视角范围外的物体,而对于那些被其他物体遮挡,但是依然在镜头范围内的物体,则不会被视锥剔除。当然当你使用遮挡剔除时,视锥裁剪还是会生效的。我们在游戏中主流的Occlusion Culling 方案基本上是以下几种方式:

CPU端:

预计算的原始的PVS

Umbra的dPVS

SoftWare Occlsion

GPU端:

GPU-Driven

Hierarchical Z-Buffering

其他硬件层面:

Eary-Z Culling

1. 预计算原始的PVS(UE4自带)

首先划分好格子,然后离线计算每个格子内的所有物体的可见性状态,这里的话格子是用Cell来描述的,格子一般是10M*10M,对于格子内的每个物体都会生成OCID,通过存一个BitArray记录可见性,这样做的好处内存可以占用尽可能的小,我们用Unity实现了一遍。

优点:

运行时消耗极低,能有效的降低OverDraw的开销,比较适合开阔的场景,个人认为非常适合目前的手游场景,而且实现比较容易

缺点:

可见性计算算法一般偏于保守,无法处理动态模型的剔除,可见性烘培的时间较长,需要额外的占用内存,调试工具需要自己开发。

几个注意点:

1)Cell划分和布置:看了下UE4的算法看平面上Cell尽可能进行等分,高度上的面片是动态计算,在实际操作时候可以平面上也可以按照密度自适应合并Cell大小采取用四叉树进行管理划分,高度上也可以分层然后考虑是否进行合并。

2) 可视计算烘培:Cell内的可见性物体这个就看自己的算法如何来弄了一般做法都比较保守,具体可以参照UE4的实现,蒙特卡洛随机选取,细节在这里就不赘述了。

3) Streaming:如果是大世界需要考虑到内存的占用和IO的换入换出,看过UE4它是随着关卡的加载全部加载的,对于unity中的实现因为大世界一般Streaming方案所以可以随着Chunk加载卸载去管理,Obect ID就得按Chunk去给,Visible BitArray也一样,保证只有局部的可见性数据,内存比较好控制。

4) 所有参数记得按照实际项目进行调优。

UE4中的具体过程参考,这种做法在UE中默认是关闭的,大家可以参考:

https://docs.unrealengine.com/en-us/Engine/Rendering/VisibilityCulling/PrecomputedVisibilityVolume

2. Umbra的dPVS(Unity自带)

这种方式是Unity目前通过Umbra内建的OC方案,虽然也叫PVS,看了下Umbra创始人的Timo Aila毕业论文发现和纯离线的原理有很大的区别。它的离线下是不计算所有可见性的,而只是生成一个空间数据结构,也就是一个BSP描述的节点信息,用于之后的空间位置查询。因此它在离线计算的时候速度可以提升很多,但是在线消耗会提升,因为它还是会多很多,比如跟踪可见物体的标记点,提取轮廓生成HOM等步骤。

优点:

引擎内建使用方便,烘培速度很快,简单易用,调试工具方便。

缺点:

可见性计算算法同样偏于保守,手游上实测运行时CPU消耗不稳定,有时候一帧2-3MS是常事,不支持Streaming大世界内存可观。

UNITY中的具体过程参考,大家可以参考:

https://docs.unity3d.com/Manual/OcclusionCulling.html

3.SoftWare Occlsion

直接参考Intel 的文章吧:

https://software.intel.com/en-us/articles/software-occlusion-culling

4.GPU-Driven

后面的趋势趋势,可以全部采用Compute Shader来做OC,后面对于IB/VB进行合并处理。

优点:

可以用来结合Virtual Texturing和DrawInstanceIndirect基本可以做到花1-2个DP搞定整个场景

缺点:

定制整个自己的Rending PipeLine,不过后面肯定是趋势

具体参考鲍鹏对于Siggraph15和GDC16的相关翻译:

Ragnarok:[Siggraph15] GPU-Driven Rendering Pipelines zhuanlan.zhihu.comRagnarok:[GDC16] Optimizing the Graphics Pipeline with Compute zhuanlan.zhihu.com

5.Eary-Z Culling

传统Z-Test其实是发生在PS之后的,因此仅仅依靠Z-Test并不能加快多少渲染速度。而Eary-Z Culling则发生在光栅化之后,调用PS之前,这样能提前对深度进行比较,如果测试通过则执行PS,否则跳过此片段/像素(Fragment/Pixel)。注意的是,在PS中不能修改深度值,否则Eary-Z Culling会被禁用。这个方式是基于硬件的,因此一旦在硬件不支持这个特性的显卡上使用此技术,反而会导致效率下降,查了下Geforce 6系列上目前是支持这个特性的。

总结:

如果是手游不是大世界且原先CPU的负载就不高那么第二种方案是可以接受的,如果是大世界且对于CPU耗时比较扣那么第一种方案适合,Unity的话就简单粗暴先照着UE撸一遍很快能出来。至于如果自己能定制管线那么CPU的OC方案就别去用了直接上GPU-Driven好了,对于优化这件事在通用引擎上还是需要很多自己更细粒度的定制化方案的

More:【微信公众号】 u3dnotes 

本文分享自微信公众号 - Unity3D游戏开发精华教程干货(u3dnotes)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部