3D性能和局限性

简介

Godot遵循平衡的表现理念。 在效率表现中,总是有需要权衡交易的东西,可用性和灵活性。 一些实际的示例是:

  • 高效地渲染对象很容易,但是当必须渲染大型场景时,它会变得效率低下。 要解决这个问题,必须将可见性计算添加到渲染中,这会使渲染效率降低,但同时渲染的对象也会减少,因此整体效率会提高。
  • 为每个需要渲染的对象配置每种材质的属性也很慢。 为了解决这个问题,对象按材质排序以降低开销,但同时排序会产生开销。
  • 在3D物理学中,会发生类似的情况。 处理大量物理对象(例如SAP)的最佳算法在插入/移除对象和射线投射时很慢。 允许更快插入和移除以及光线投射的算法将无法处理尽可能多的活动对象。

还有更多的示例! 游戏引擎本质上是通用的,因此平衡的算法总是比在某些情况下可能快速且在其他情况下速度慢的算法,或者算法速度快但使可用性更难的算法更受青睐。

Godot不是一个例外,虽然它被设计为可以为不同的算法交换后端,但默认的(或者说,现在唯一的那些)优先考虑平衡和灵活性而不是性能。

清楚了这些,本教程的目的是解释如何从Godot中获得最大的性能。

渲染

3D渲染是获得性能最困难的领域之一,因此本节将提供一系列提示。

重复使用着色器和材质

Godot渲染器与其他的渲染器略有不同。 它旨在尽可能减少GPU状态的变化。 class_SpatialMaterial 在重用需要类似着色器的材质方面做得很好但是,如果使用自定义着色器,请确保尽可能多地重用它们。 Godot的优先事项如下:

  • 重复使用材质:场景中不同的材质越少,渲染速度就越快。 如果一个场景有大量的物体(数百或数千),请尝试重复使用这些材质,或者,在最坏的情况下,使用图集。
  • 重用着色器: 如果材质无法重复使用,至少尝试重新使用着色器(或具有不同参数但配置相同的SpatialMaterials)。

例如,如果一个场景有20.000个对象,每个对象有20.000个不同的材质,那么渲染将会很慢。如果同一场景有20.000个对象,但只使用100个素材,渲染将非常迅速。

像素成本vs顶点成本

人们普遍认为,模型中多边形的数量越少,渲染的速度就越快。这是 非常 相对的,取决于很多因素。

在现代PC和控制台上,顶点成本很低。 GPU最初只渲染三角形,所以所有顶点都是:

  1. 要被CPU变换(包括剪裁)。
  2. 要从主RAM发送到GPU内存。

如今,所有这些都是在GPU内部处理的,因此性能非常高。 3D艺术家通常对多计数性能有错误的感觉,因为3D DCC(例如Blender,Max等)需要将几何保留在CPU内存中以便进行编辑,从而降低实际性能。 事实上,3D引擎渲染的模型比3D DCC显示模型更加优化。

在移动设备上又是另一个故事了。 PC和控制台GPU是蛮力的怪物,可以从电网中获取所需的电量。移动GPU仅限于小型电池,因此它们需要更高的能量使用效率。

为了提高效率,移动GPU试图避免 透支 。 这意味着,屏幕上的相同像素被渲染(如,通过照明计算等)不止一次。 想象一个有几座建筑的小镇,GPU不知道什么是可见的,什么是隐藏的,直到它们绘制它。 GPU可能会绘制一个房子,然后在它前面的另一个房子(对于同一个像素渲染两次!)。 PC GPU通常不关心这一点,只是将更多像素处理器投入硬件以提高性能(但这也增加了功耗)。

在移动设备上,提供更多能量不是一种选择,因此使用了一种称为“Tile Based Rendering(基于图块渲染)”的技术(几乎每个移动硬件都使用它的一种变体),它将屏幕划分为网格。 每个单元格保留绘制到它的三角形列表,并按深度对它们进行排序,以最小化 重绘 。 这种技术可以提高性能并降低功耗,但会降低顶点性能。 因此,可以处理进行绘制更少的顶点和三角形。

一般来说,这并不是那么糟糕,但在移动设备上有一个必须避免的特殊情况,即在屏幕的一小部分内具有大量几何形状的小物体。 这迫使移动GPU在单个屏幕单元上用很大的力气,大大降低了性能(因为所有其他单元必须等待它完成才能显示帧)。

简单地说,不要太担心移动设备上的顶点数量,但要避免在屏幕的小部分中集中顶点。 例如,如果角色,NPC,车辆等距离较远(因此看起来很小),请使用细节程度(Level of detail, LOD) 较小的模型。

必须考虑顶点开销的一种特殊情况是物体每个顶点需要额外的处理,例如:

  • 蒙皮(骨骼动画)
  • 变形(形态键)
  • 顶点照明对象(在移动设备上常见)

纹理压缩

Godot提供在导入时压缩3D模型的纹理(VRAM压缩)。 视频RAM压缩在存储时的大小不如PNG或JPG,但在绘制时极大地提高了性能。

这是因为纹理压缩的主要目标是在内存和GPU之间减少带宽。

In 3D, the shapes of objects depend more on the geometry than the texture, so compression is generally not noticeable. In 2D, compression depends more on shapes inside the textures, so the artifacts resulting from 2D compression are more noticeable.

作为警告,大多数Android设备不支持具有透明度的纹理的纹理压缩(仅不透明),因此请记住这一点。

透明物体

如前所述,Godot通过材质和着色器对对象进行排序以提高性能。 但是,这不能在透明对象上完成。 透明对象从后向前呈现,以便与背后的内容进行混合。 因此,请尽量将透明物体保持在最低限度! 如果对象有一小部分是透明的,请尝试将该部分作为单独的材质。

细节程度(LOD)

如前所述,在某些情况下,使用具有较少顶点的对象可以提高性能。 Godot有一个简单的系统来改变细节层次 GeometryInstance 基于对象的可见范围可以定义。 在不同范围内具有多个GeometryInstance对象可用作LOD。

使用多网格(MultiMesh)

如果必须在同一个地方或附近绘制几个相同的对象,请尝试使用 MultiMesh 。 MultiMesh允许以极低的性能成本绘制数十万个物体,使其成为鸡群,草,颗粒等的理想选择。

烘焙照明

小灯通常不是性能问题。 阴影问题就稍大一些。 一般来说,如果几个灯需要影响一个场景,理想的是烘焙它( 烘焙光照贴图 )。 烘焙还可以通过添加间接光反弹来改善场景质量。

如果在移动设备上工作,建议烘焙到纹理,因为这种方法更快。