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.

优化 3D 性能

剔除

Godot 会自动执行视锥剔除,以防止渲染视口外的物体。这对于发生在一个小区域内的游戏来说效果很好,然而在较大的关卡中,问题很快就会变得复杂。

遮挡剔除

例如在小镇上行走时,你可能只能看到你所在街道上的几栋建筑,以及天空和几只飞过头顶的鸟。然而就一个朴素的渲染器而言,你仍然可以看到整个小镇。它不仅会渲染你前面的建筑,还会渲染后面的街道、街上的人、以及更后面的建筑。你很快就会遇到这样的情况:试图渲染的内容是可见内容的 10 倍甚至 100 倍。

情况并没有看上去那么糟糕,因为 Z 缓冲区通常允许 GPU 仅对最前面的物体进行完整着色。这称为深度预渲染,在使用 Forward+ 或 Compatibility 渲染方法时,Godot 会默认启用它。但是,不需要的对象仍然会降低性能。

一种可以减少渲染量的方法是利用遮挡。Godot 提供了一种使用遮挡器节点进行遮挡剔除的方法。请参阅 遮挡剔除,了解如何在场景中设置遮挡剔除。

备注

在某些情况下,你可能需要调整关卡设计以增加更多遮挡机会。例如,你可能需要添加更多墙壁以防止玩家看得太远,否则会因遮挡剔除的机会减少而降低性能。

透明物体

Godot 会按 MaterialShader 对对象进行排序以提高性能。然而,这对透明对象来说是不可能的。透明对象需要从后向前渲染,以便与后面的内容进行混合。因此,尽量少使用透明对象。如果一个物体只有一小部分是透明的,尽量让这部分成为一个独立的表面,拥有自己的材质。

更多信息,请参阅 GPU 优化文档。

细节层次(LOD)

在某些情况下,尤其是在远处时,用更简单的版本替换复杂的几何体可能是个好主意。最终用户可能看不出太大区别。想象一下观察远处的大量树木。有几种策略可以用于替换不同距离的模型。你可以使用多边形数量更少的模型,或者使用透明度来模拟更复杂的几何体。

Godot 4 提供了多种控制细节层次的方法:

虽然这些方法可以单独使用,但结合使用时效果最佳。例如,你可以设置可见范围来隐藏距离玩家太远而无法注意到的粒子效果。同时,你可以依靠网格 LOD 让粒子效果的网格在远处以较少的细节渲染。

可见范围也是为远处几何体设置伪装物(impostor)的好方法(见下文)。

广告牌和伪装物

使用透明度处理 LOD 的最简单方法是广告牌。例如,你可以使用单个透明四边形来表示远处的一棵树。除非许多树彼此重叠,否则这种方式的渲染成本非常低。在这种情况下,透明度可能会开始占用填充率(有关填充率的更多信息,请参阅《GPU 优化》)。

另一种方法是渲染不只一棵树,而是将多棵树作为一组来渲染。对于游戏中你能看到但无法实际接近的一个区域,这种方法可能特别有效。

你可以通过预先渲染对象在不同角度的视图来制作伪装物。你甚至可以更进一步,周期性地将对象的视图重新渲染到一个纹理上,作为假像使用。在远处,你需要将观察者移动相当长的距离,视角才会发生显著变化。实现这一功能可能比较复杂,但根据你制作的项目类型,这可能是值得的。

使用自动实例化

此功能仅在 Forward+ 渲染器中实现,Mobile 或 Compatibility 渲染器中不可用。

如果场景中有许多相同的对象,可以使用自动实例化来减少绘制调用次数。这对于使用相同网格和材质的 MeshInstance3D 节点会自动发生:无需手动设置。

要使自动实例化生效,材质必须是不透明或 alpha 测试类型(alpha scissor 或 alpha hash)。Alpha 混合或深度预渲染材质永远不会以这种方式实例化。相反,你必须使用下文所述的 MultiMesh。

使用手动实例化(MultiMesh)

如果必须在同一位置或附近绘制多个相同的对象,请尝试使用 MultiMesh 来代替。MultiMesh 允许以很小的性能代价绘制成千上万个对象,非常适合用于群体、草地、粒子以及任何其他有大量相同对象的场景。

另请参阅《使用 MultiMesh》文档。

烘焙光照

物体光照是成本最高的渲染操作之一。实时光照、阴影(尤其是多个光源)和全局光照尤其消耗性能。它们对于低功耗移动设备来说可能过于繁重而无法处理。

考虑使用烘焙光照,尤其是移动设备。这可以呈现出极佳的效果,但缺点是它不是动态的。有时,这是值得做出的权衡。

有关使用烘焙光照贴图的说明,请参阅使用光照贴图全局照明。为了获得最佳性能,你应该将灯光的烘焙模式设置为 Static(静态),而不是默认的 Dynamic(动态),因为这将跳过对已烘焙光照的网格进行实时光照计算。

使用 Static 烘焙模式的灯光的缺点是,它们无法将阴影投射到已烘焙光照的网格上。这会让具有室外环境和动态物体的场景看起来平淡。性能和质量之间的良好平衡是让 DirectionalLight3D 节点保持 Dynamic,而对大多数(如果不是全部)泛光灯和聚光灯使用 Static

动画和蒙皮

在某些平台上,动画和顶点动画(如蒙皮和变形)可能非常消耗性能。你可能需要大幅降低动画模型的多边形数量,或限制同时出现在屏幕上的数量。你还可以降低远处或被遮挡网格的动画更新频率,或者在玩家不太可能注意到动画停止时完全暂停动画。

VisibleOnScreenEnabler3DVisibleOnScreenNotifier3D 节点可用于此目的。

大型世界

如果你要制作大型世界,需要考虑的因素与小型游戏有所不同。

大型世界可能需要以分块方式构建,在你在世界中移动时按需加载。这可以防止内存使用失控,也能将所需的处理限制在局部区域。

在大型世界中,由于浮点误差,渲染和物理可能会出现异常。可以使用大世界坐标解决该问题。如果无法使用大型世界坐标,你可以使用一些技术,例如围绕玩家定位世界(而不是相反),或定期移动原点以使事物以 Vector3(0, 0, 0) 为中心。