Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
遮挡剔除¶
在3D渲染引擎中,遮挡剔除 是将被遮挡物体移除的过程。
你会在这个页面中学习到:
遮挡剔除的优缺点有哪些。
怎样在 Godot 中设置遮挡剔除。
解决 Godot 中控制器的问题 。
参见
你可以使用 遮挡剔除和网格 LOD 演示项目 来了解遮挡剔除的实际工作原理。
为什么要使用遮挡剔除¶
这个示例场景中有数百个房间相邻堆叠,一个动态物体(红色球体)隐藏在明亮房间的墙后面(门的左侧):

布局对遮挡剔除友好的示例场景¶
遮挡剔除关闭后,光亮房间后的所有房间和动态物体都需要被渲染:

禁用 遮挡剔除的示例场景(线框)¶
遮挡剔除打开后,只有真正可见的房间被渲染,动态物体被墙遮挡住,因此也不用被渲染:

线框模式下 启用 遮挡剔除的范例场景¶
由于引擎只有更少的工作要做(更少的顶点和更少的 draw calls),因此只要在场景中有足够多的遮挡剔除机会,性能就会提高。所以说遮挡剔除在室内场景中最有效,尤其是在很多较小的房间而不是较少更大的房间中。将此与 网格的细节级别(LOD) 与 可见范围(HLOD) 结合起来可以进一步提高性能效益。
备注
当使用集群 Forward 渲染后端时,引擎已经执行了 深度预处理 。这包括在渲染场景的实际材质之前渲染场景的仅深度(depth-only)版本。该技术用于确保每个不透明像素仅着色一次,从而显着降低过度绘制的成本。
使用 Forward Mobile 渲染后端时可以观察到最大的性能优势,因为出于性能原因,它并没有深度预处理。因此,遮挡剔除将主动减少渲染后端的着色过度绘制。
尽管如此,即使使用深度预处理,复杂 3D 场景中的遮挡剔除仍然有明显优势。然而,在遮挡剔除机会很少的场景中,遮挡剔除可能不值得其增加的额外设定和 CPU 使用率。
Godot中的遮挡剔除如何运作¶
备注
"occluder" refers to the shape blocking the view, while "occludee" refers to the object being hidden.
在 Godot 中,遮挡剔除是通过将场景的遮挡几何体光栅化到低分辨率的缓存中实现的。这是使用了软光追库 Embree 来完成的。
然后,引擎使用低分辨率缓存来测试遮挡物的 AABB 与遮挡物的形状。被遮挡物的 AABB 必须被要剔除的遮挡物形状完全遮挡。
因此,较小的物体相较于较大的物体更可能被有效地剔除。较大的遮挡物(如墙壁)往往比较小的遮挡物(如装饰道具)更有效。
设置遮挡剔除¶
使用遮挡剔除的第一步是在项目设置中启用 渲染>遮挡剔除>使用遮挡剔除。(确保在项目设置中启用 高级设置 选项,否则可能无法找到该设置。)
项目设置会立即应用,无需重启编辑器。
在启用项目设置后,你仍然需要创建一些遮挡物。出于性能原因,引擎不会自动将所有可见物体视为遮挡剔除的基础。相反,引擎需要只有静态物体被烘焙的简化场景表示。
有两种方法可以在场景中设置遮挡器:
自动烘焙遮挡物(建议)¶
备注
当前 遮挡物 烘焙过程中仅考虑 MeshInstance3D 节点。烘焙遮挡物时, 不 考虑 MultiMeshInstance3D、GPUParticles3D、CPUParticles3D 和 CSG 节点。如果你希望将它们也视为遮挡物,则必须手动建立以(大致)匹配其几何形状的遮挡物形状。
该限制不适用于 被遮挡者。任何继承自 GeometryInstance3D 的节点类型都可以被遮挡。
启用上述遮挡剔除的项目设置后,向你包含 3D 关卡的场景中新增 OcclusionrInstance3D 节点。
选择 OccluderInstance3D 节点,然后单击 3D 编辑器视口顶部的 烘焙遮挡器 。在烘焙后,OccluderInstance3D 节点将包含一个 Occluder3D 资源,用于存储关卡几何体的简化版本。此遮挡物几何体在 3D 视图中显示为紫色线框线(只要在 透视 菜单中启用 查看小工具 )。然后使用该几何体为静态和动态被遮挡物提供遮挡剔除。
烘焙后,你可能会注意到动态对象(例如玩家、敌人等)也被包含到了烘焙的网格中。为了防止这种情况发生,请在 OccluderInstance3D 上设置 Bake > Cull Mask 属性,以排除某些视觉层的烘焙。
例如,你可以禁用剔除蒙版上的第 2 层,然后将动态对象的 MeshInstance3D 节点配置为位于可视层 2(而不是第 1 层)上。为此,请选择相关的 MeshInstance3D 节点,然后在 VisualInstance3D > Layers 属性上,取消选中图层 1,再选中图层 2。配置剔除蒙版和图层后,按照上述过程再次烘焙遮挡物。
手动放置遮挡器¶
这种方法更适合专门的用例,例如为 MultiMeshInstance3D 设置或 CSG 节点创建遮挡(由于上述限制)。
启用上述遮挡剔除项目设置后,将 OcclusionrInstance3D 节点添加到包含 3D 关卡的场景中。选择 OccluderInstance3D 节点,然后选择要添加到 Occlusionr 属性中的遮挡器类型:
QuadOccluder3D(一个单平面)
BoxOccluder3D(一个立方体)
SphereOccluder3D(一个球形遮挡器)
PolygonOccluder3D(一个具有任意数量点的 2D 多边形)
此外还有 ArrayOccluder3D,其点无法在编辑器中修改,但可用于通过脚本进行程序生成。
预览遮挡剔除¶
可以启用调试绘制模式来预览遮挡剔除实际“看到”的内容。在 3D 编辑器视口的左上角,单击 透视 按钮(或 正交 ,具体取决于当前的相机模式),然后选择 显示高级... > 遮挡剔除缓冲 。这将显示引擎用于遮挡剔除的低分辨率缓冲区。
在同一菜单中,还可以启用 查看信息 和 查看帧时间 来查看右下角的绘制调用和渲染图元(顶点+索引)的数量,以及右上角渲染的每秒帧数。
如果在显示此信息时在项目设置中切换遮挡剔除,你可以看到遮挡剔除对场景性能的改善程度。请注意,性能优势在很大程度上取决于 3D 编辑器相机的视角,因为遮挡剔除仅在相机前面存在遮挡器时才有效。
要在运行时切换遮挡剔除,请在根视口上设置“use_occlusion_culling”,如下所示:
get_tree().root.use_occlusion_culling = true
在运行时切换遮挡剔除,对于比较正在运行的项目的性能很相当有用。
性能方面的考虑¶
在构建关卡时考虑遮挡¶
这是最重要的指导原则。 好的关卡设计并不只是满足游戏性的需求,也应该同时考虑遮挡。
For indoor environments, add opaque walls to "break" the line of sight at regular intervals and ensure not too much of the scene can be seen at once.
For large open scenes, use a pyramid-like structure for the terrain's elevation when possible. This provides the greatest culling opportunities compared to any other terrain shape.
Avoid moving OccluderInstance3D nodes during gameplay¶
This includes moving the parents of OccluderInstance3D nodes, as this will cause the nodes themselves to move in global space, therefore requiring the BVH to be rebuilt.
Toggling an OccluderInstance3D's visibility (or one of its parents' visibility) is not as expensive, as the update only needs to happen once (rather than continuously).
For example, if you have a sliding or rotating door, you can make the OccluderInstance3D node not be a child of the door itself (so that the occluder never moves), but you can hide the OccluderInstance3D visibility once the door starts opening. You can then reshow the OccluderInstance3D once the door is fully closed.
If you absolutely have to move an OccluderInstance3D node during gameplay, use a primitive Occluder3D shape for it instead of a complex baked shape.
Use the simplest possible occluder shapes¶
If you notice low performance or stuttering in complex 3D scenes, it may mean that the CPU is overloaded as a result of rendering detailed occluders. Select the OccluderInstance3D node, increase the Bake > Simplification property then bake occluders again.
Remember to keep the simplification value reasonable. Values that are too high for the level's geometry may cause incorrect occlusion culling to occur, as in My occludee is being culled when it shouldn't be.
If this still doesn't lead to low enough CPU usage, you can try adjusting the Rendering > Occlusion Culling > BVH Build Quality project setting and/or decreasing Rendering > Occlusion Culling > Occlusion Rays Per Thread. You'll need to enable the Advanced toggle in the Project Settings dialog to see those settings.
故障排除¶
My occludee isn't being culled when it should be¶
On the occluder side:
First, double-check that the Bake > Cull Mask property in the OccluderInstance3D is set to allow baking the meshes you'd like. The visibility layer of the MeshInstance3D nodes must be present within the cull mask for the mesh to be included in the bake.
Also note that occluder baking only takes meshes with opaque materials into account. Surfaces will transparent materials will not be included in the bake, even if the texture applied on them is fully opaque.
Lastly, remember that MultiMeshInstance3D, GPUParticles3D, CPUParticles3D and CSG nodes are not taken into account when baking occluders. As a workaround, you can add OccluderInstance3D nodes for those manually.
On the occludee side:
Make sure Extra Cull Margin is set as low as possible (it should usually be
0.0
), and that Ignore Occlusion Culling is disabled in the object's
GeometryInstance3D section.
Also, check the AABB's size (which is represented by an orange box when selecting the node). This axis-aligned bounding box must be fully occluded by the occluder shapes for the occludee to be hidden.
My occludee is being culled when it shouldn't be¶
The most likely cause for this is that objects that were included in the occluder bake have been moved after baking occluders. For instance, this can occur when moving your level geometry around or rearranging its layout. To fix this, select the OccluderInstance3D node and bake occluders again.
This can also happen because dynamic objects were included in the bake, even though they shouldn't be. Use the occlusion culling debug draw mode to look for occluder shapes that shouldn't be present, then adjust the bake cull mask accordingly.
The last possible cause for this is overly aggressive mesh simplification during the occluder baking process. Select the OccluderInstance3D node, decrease the Bake > Simplification property then bake occluders again.
As a last resort, you can enable the Ignore Occlusion Culling property on the occludee. This will negate the performance improvements of occlusion culling for that object, but it makes sense to do this for objects that will never be culled (such as a first-person view model).