走近遮挡剔除
遮挡剔除是一个十分复杂的功能,很容易被错误地使用。通过这篇指南,我希望能让用户更好地理解应当什么时候以及在什么地方使用遮挡剔除。
该教程基于此文档重新撰写:
https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Occlusion-Culling
作者:Silent
校对:RyuraQWQ
文章原址:Occlusion Culling and You | VRCLibrary
1. 遮挡剔除的基本原理
在 Unity 场景中,遮挡剔除通过将世界划分为许多个越来越小的空间区块来实现的。在这些数据中,系统会记录每个区块中的哪些物体是可见的,哪些是不可见的。Unity 正是利用这些数据来“隐藏”那些被其他物体遮挡的游戏对象。
需要明确的是,遮挡剔除只会在视觉上隐藏物体。即使物体被隐藏,它们的状态也不会改变,大部分功能仍然会继续运行,因此遮挡剔除主要用于减少绘制调用 (Draw calls) ,而不是完全移除掉被遮挡的物体。此外,无论物体距离观察者有多远,Unity 都将不会隐藏它判断为可见的对象。所以我们可以看出,距离并不是影响遮挡剔除的因素。
遮挡剔除是否仅限于视觉效果?
是的,遮挡剔除的作用仅仅是阻止物体的渲染!它并不会终止物体的其他处理过程,因此如果你有一个划分为多个区域的大型世界,你可以通过剔除那些当前不活跃的区域来提高整体性能。
2. 遮挡剔除如何影响物体
遮挡剔除对静态对象(如地图元素)和动态对象(如玩家和可拾取物品)的处理方式有所不同。
- 静态对象既可以隐藏其他物体,也可以被其他物体隐藏。(在某些情况下,你可能不希望静态对象同时具备这两种特性。)这些对象的遮挡信息会在运行前被预烘焙,而在运行时无法更改。
- 动态对象则无法隐藏它们背后的物体,但它们可以根据一种粗略的特殊计算而被其他物体隐藏,这种计算会判断它们是否位于某个静态对象之后。
Unity 通过检查对象上的静态标志来确定遮挡剔除将会如何影响它们。遮挡剔除考虑了以下三种不同的情况:
- 静态遮挡物。唯一能够遮挡其他物体的静态对象——特别是网格渲染器和地形。如果它们被标记为遮挡物,则它们后面的物体会被隐藏。这些遮挡信息会在运行前被预先烘焙。
- 静态被遮挡物。这指的是那些可以被隐藏的静态对象。被遮挡物可以是任何带有渲染器的物体,只要它在运行过程中不移动。
- 动态被遮挡物。这包括了场景中的其他所有物体。如果启用了“动态遮挡”属性,那么这些物体可以被静态遮挡物根据预先计算的遮挡信息隐藏。
需要注意的是,动态遮挡的效果通常不如静态遮挡精确。实际上,只有那些大型的、实心的物体才可能有效地隐藏动态对象。
3. 如何设置场景以实现遮挡剔除
默认情况下,Unity 会将整个场景放入一个称为 视图体积(View Volumes)的大空间块中。
通过在场景中划定特定的 遮挡区域(Occlusion Area),我们可以让 Unity 仅在这些区域内进行遮挡数据的计算,从而大幅降低所需处理的遮挡数据量。如果您的场景被划分为若干独立区块,您可以使用遮挡区域来逐个覆盖这些区块,而非让 Unity 对整个场景统一处理,这将会是一种更为高效的方法。
您可以在对象的静态标签或 遮挡窗口(Occlusion window)中进行遮挡剔除的设置。
遮挡剔除的简单推荐设置
只有体积大的实体对象才适合作为遮挡物。
若物体尺寸小、透明度较高或存在空洞,则不适合作为遮挡物。例如,树木不应作为遮挡物,因为其叶片会形成许多微小空隙,这些空隙难以通过遮挡剔除准确计算;同样,边缘结构复杂的对象也不适宜作为遮挡物。
对于始终处于可见状态的对象,无需将其纳入被遮挡物的范畴。
例如,天空盒或由大片平面组成的海洋等,将其纳入遮挡剔除并无实际意义,而且错误地将它们判定为被遮挡物所带来的性能损失可能超过由此带来的性能收益。
应该使较小的对象成为被遮挡物,而不是遮挡物。
即使是小型对象,也可以作为被遮挡物从中获益。
使用“EditorOnly”标签可以创建虚拟的遮挡物。
如果一个对象有 EditorOnly
标签,它不会在游戏中或运行状态下被渲染。然而,在烘焙过程中它仍会被视作遮挡物。
我要如何预览遮挡剔除的效果?
在 Unity 2018 中,遮挡剔除将影响场景相机的渲染(现在也不例外)。此外,通过在遮挡窗口中选择 可视化(Visualization),可以从相机视角观察场景中遮挡剔除的实际运作情况。
此时,场景层级结构(Hierarchy)将被屏蔽,仅展示含相机组件的对象和当前相机视角下的遮挡剔除结果。你可以观察到相机所使用的光线投射技术,以及它是如何确定哪些物体被遮挡,和被遮挡的具体位置。
若要恢复正常的场景显示,只需切换至遮挡窗口中的其他标签或关闭窗口即可。
"烘焙(Bake)"设置是什么意思?
在遮挡窗口中,有一个包含了若干预设的选项和一段说明文本的部分。正如文本所指出的,这些设置已针对速度和性能进行了优化,因此不建议随意更改。
最小孔洞(Smallest Hole) 设置了被视为“孔洞”的几何间隙的阈值,可通过该孔洞看见外部。这个值越小,烘焙遮挡的时间就越长。您可以将此值设置为适合您场景的值,理想值在 0.05 到 0.5 之间(5cm 到 50cm)。
最小遮挡物(Smallest Occluder) 设定了在计算遮挡时所考虑的细节等级。这个值越小,计算遮挡时会考虑更多的小物体,并且在运行计算可见内容时,遮挡的计算量会更大。将此值设置为略大于平均玩家大小的值,大约为 2-6 米(2m 到 6m)即可。
如果你想了解更多关于它们的信息,请访问Unity博客上的这篇文章,以便更深入地解释了它们。
4. 案例研究:世界设计实用技巧
《The Devouring (吞噬者)》是 VRChat 中一个利用遮挡剔除技术以最大化 Unity 性能的大型地图。以下是其开发者的一些建议:
- 不要忘记,遮挡是使用不透明的网格渲染器作为遮挡物来计算的。透明材料不会产生遮挡效果。有复杂的边缘的游戏对象是不利于遮挡剔除的。
- 对于大型且复杂的世界,尤其是那些被划分为多个“区域”的世界,开发者建议使用大型遮挡方块来分隔这些区域。这些遮挡方块应当设置在 EditorOnly 模式下,这样它们在游戏运行时不会被渲染,但仍然会对烘焙过程产生影响。
- 对于大型且复杂的世界,尤其是那些被划分为多个“区域”的世界,开发者建议使用大型遮挡方块来分隔这些区域。这些遮挡方块应当设置在 EditorOnly 模式下,这样它们在游戏运行时将不会被渲染,但仍然会对烘焙过程产生影响。
《吞噬者》中使用的遮挡预制件。请注意,这些预制件被放置在了墙壁的后方。
- 如果在您编辑地图时,这些对象在您的场景中显得过于显眼,可以将材质上的着色器暂时更改为“隐形”着色器,以便在进行编辑工作时暂时隐藏这些遮挡物。(记得将其切换回不透明着色器以进行烘焙。)
- 在这种情况下,它们仅位于墙后,且宽度一致。对于装饰性的柱子,它们会被放置在内部,例如,如果柱子或墙上有一个小凹槽,您不希望在仅查看这个区域时出现闪烁现象。通常来说,让您的虚拟遮挡物要比暴露的边缘略微小一些。
- 如果您在场景的内部看到粉红色,这表明您可能会得到错误的遮挡反应。如果你在外部看不到粉红色,那意味着在遮挡中存在缺口。
《吞噬者》是由模块化资产构建而成的。所有的墙壁都包含在预制件中的遮挡盒,这简化了遮挡设置、烘焙流程,并减少了大量潜在的遮挡错误。在场景中,您可以看到它们呈现为粉红色的墙壁,并且可以相对容易地识别出它们的工作区域。这与单个游戏对象中的大型遮挡物相结合,并且仅在烘焙期间启用。
- 对于大型地图中的区块,遮挡区域非常有用,但需要注意,在 Unity 2018 中,您可能会在VR环境中经过某些区域时遇到“闪烁”现象,这非常令人沮丧,而我们尚未找到解决方案。
- 在遮挡烘焙完成后,Unity 2018 的表现令人失望,因为它会在编辑器中隐藏物体。建议您将烘焙设置在编辑工作时更改为较为粗略的设置,以便于轻松清理和快速重新烘焙。等到准备进行优化时,再执行更细致的烘焙。
- 在设计世界时,请考虑到遮挡的因素。如果您不需要一个开放的空间,就在那里建造一堵墙。在走廊中加入转角和Z字形的布局来遮挡另一侧的空间。如果它们没有展示任何东西,就阻挡掉大型开阔的视野范围。尝试避免让玩家一次性看到过多的内容——这在多人游玩的场景中尤为重要,遮挡玩家视线是您可以实施的最大的性能提升措施之一。
《吞噬者》中遮挡走廊的一个例子。
5. 其他说明
遮挡门
遮挡门是一种可以自由开启或关闭的遮挡机制,它能够影响遮挡剔除的效果。在你的场景中,如果有大型的可开闭物体,比如一扇门或者一个可切换的物体,你可以在它的旁边放置一个遮挡门。当这个遮挡门关闭时,你可以相应地激活或关闭遮挡门,以此来享受遮挡剔除带来的性能提升。
参考资料
特别感谢Fionna提供《The Devouring(吞噬者)》遮挡的详细信息。更多的细节在VRCPrefabs TLX的视频中有详细展示
想了解更多关于遮挡剔除的工作原理,请尝试查阅 Unity 文档。
确实,初次接触遮挡门户这一概念时,可能会感到有些困惑,因为它涉及到一些复杂的渲染和性能优化技术。但是,通过不断的实践和试错,我们可以逐渐理解并掌握这项技术。
在过去的一年里,Unity也在不断地接收来自开发者的反馈,并对他们的官方文档进行了更新和改进,使得相关的教程和指南变得更加清晰易懂。这对于开发者来说是一个非常好的消息,因为良好的文档是学习和使用新技术的重要资源。
以下是用到的参考资料:
- https://docs.unity3d.com/Manual/OcclusionCulling.html
- https://docs.unity3d.com/Manual/occlusion-culling-getting-started.html
- https://www.gamasutra.com/view/feature/164660/sponsored_feature_next_generation_.php
- http://web.archive.org/web/20131204230947/https://blogs.unity3d.com/2013/12/02/occlusion-culling-in-unity-4-3-the-basics/
- https://blogs.unity3d.com/2013/12/26/occlusion-culling-in-unity-4-3-best-practices/
- http://web.archive.org/web/20140105091320/https://blogs.unity3d.com/2014/01/02/occlusion-culling-in-unity-4-3-troubleshooting/
- https://medium.com/@Umbra3D/introduction-to-occlusion-culling-3d6cfb195c79
- https://cdn.discordapp.com/attachments/437816654492073994/924630771367559178/boosting-frame-rates-in-unity-games-using-umbra-3.pdf