灯光是游戏最重要的方面之一。它可以烘托气氛、引导玩家、识别威胁或目标等等。灯光可以决定游戏的视觉效果。例如,好的灯光可以让一个糟糕的模型在游戏中看起来更好,而糟糕的灯光则会让一个出色的模型看起来更差。
本指南提供有关提高移动游戏灯光性能的信息。您决定如何使用灯光会影响移动游戏的性能。高效使用灯光以确保游戏尽可能流畅运行至关重要。
本文部分内容基于 Arm Limited 贡献和版权所有的作品。
渲染管线选项
Unity 的旧版渲染管线包含以下渲染路径
- 前向渲染
- 延迟着色
前向渲染
对于前向渲染,实时灯光非常昂贵。如果您减少每个像素存在的灯光数量,可以抵消此成本。
延迟着色
延迟着色需要 GPU 支持。在兼容的硬件上,延迟着色可以渲染大量实时灯光,并具有高水平的灯光保真度。不幸的是,延迟着色在移动 GPU 上表现不佳,因为它们的带宽较低。
当您制作移动游戏时,让游戏在尽可能多的设备上流畅运行至关重要。
通用渲染管线
Unity 开发了通用渲染管线 (URP)。我们强烈建议您在移动游戏中使用 URP。
灯光模式
根据灯光在场景中的移动方式或使用方式,会使用不同的灯光模式。灯光模式类型具有不同的性能特征。在实现灯光时,请考虑以下事项:
- 对静态灯光使用烘焙。这最适合在运行时不改变灯光的对象。烘焙灯光是将灯光数据预计算并存储在纹理贴图(称为光照贴图)中的过程。
- 烘焙灯光无法在运行时修改。光照贴图中的灯光和阴影是静态的。由于所有灯光都在 Unity 中进行了预处理,因此不会有任何运行时灯光计算影响性能。
- 烘焙灯光无法创建动态阴影。这对于动态或移动对象可能看起来很奇怪。
- 对您打算与移动对象交互的固定灯光使用混合。例如,火炬将光投射到玩家身上,并在玩家移动时产生阴影。
- 混合灯光创建动态直射光和阴影。
- 您可以在静态对象的光照贴图计算中包含混合灯光。
- 您可以在运行时更改强度。只有直射光会更新。
- 昂贵。
- 对动态或可移动灯光使用实时,例如从地面升起并爆炸的火球所投射的灯光。
- 动态灯光和阴影属性可以在运行时修改。
- 实时灯光不会烘焙到光照贴图中。
- 非常昂贵。
有关详细信息,请阅读Unity 的灯光管线。
尽可能使用静态灯光,避免动态灯光
动态或实时灯光每帧都会计算和更新。这对于移动对象、交互性以及营造氛围非常有用。
相比之下,静态灯光信息会烘焙到光照贴图中。光照贴图纹理的使用使对象能够避免昂贵的每顶点或每像素灯光计算。光照贴图纹理的渲染成本始终远低于动态灯光。我们建议将烘焙灯光作为移动游戏实现的第一个选择。
光照贴图烘焙
灯光效果的预计算称为光照贴图烘焙。灯光效果存储在单独的纹理中,称为光照贴图。光照贴图可用于增强对象的视觉效果。光照贴图烘焙只需在场景的每次迭代中进行一次。如果您更改场景的几何体,或更改烘焙灯光的参数,则需要重新烘焙光照贴图。除了光照贴图纹理的开销外,运行时没有额外的性能成本。这是移动平台上灯光处理的最佳初始方法。
烘焙灯光不受场景中任何动态或移动方面的影响。烘焙灯光确实包含所有静态元素的烘焙全局照明。这意味着光照贴图计算包括从其他静态对象反射的间接光以及直接照射到对象上的烘焙光。
图 1. Armies 技术演示中使用的全烘焙灯光设置。
要烘焙灯光,请执行以下三个步骤。
步骤 1:将灯光设置为“混合”或“烘焙”
将灯光的模式设置为“混合”或“烘焙”。对于移动游戏,最好使用“烘焙”灯光而不是“混合”。“烘焙”是渲染灯光最经济的方式。
图 2. Unity 中灯光的模式设置。
步骤 2. 将对象设为静态
将受烘焙灯光影响的任何对象设为静态。对于标记为静态的对象有许多优化,但通常最好在静态下拉列表中选择所有。将对象标记为静态后,Unity 就会知道将其包含在灯光烘焙中。
图 3. 静态菜单示例。
步骤 3. 烘焙灯光
您可以使用“窗口”>“渲染”>“灯光设置”中的灯光菜单烘焙灯光。
烘焙灯光时,保存的数据基于您开始烘焙时处于活动状态的场景。将生成一个与烘焙场景同名的文件夹。此文件夹存储灯光数据的所有组件。如果您的项目同时加载多个场景,则必须为每个场景烘焙灯光。如果您调整了场景,则必须重新烘焙灯光。
图 4. 烘焙光照贴图示例。
优化光照贴图
设置好烘焙灯光后,请确保烘焙的贴图已优化。光照贴图的大小根据烘焙时的设置而异。您必须在移动设备上控制内存使用,因此必须监控光照贴图大小。
在 Armies 演示的以下示例中,有七个 1024x1024 像素的光照贴图。在贴图预览中,您可以看到网格铺设在光照贴图上。选定的网格会高亮显示。
图 5. 这是光照贴图的示例。蓝色部分是选定的网格。
“光照贴图设置”中有很多设置,以及贴图的大小,这些设置决定了每个贴图使用多少内存和存储空间。以下部分重点介绍了一些重要设置。
光照贴图烘焙器
Unity 提供以下三种方法来烘焙场景中的灯光
- Enlighten:仅支持到 2020 年长期支持 (LTS) 版本。新项目请勿使用此方法。
- 渐进式 CPU:因为它能增量创建光照贴图,所以节省了大量时间。如果选择了优先视图,则场景视图中的区域将获得优先权。这可以减少设置场景灯光的迭代时间。
- 渐进式 GPU:这与渐进式 CPU 的工作方式相同,但光照贴图是在 GPU 而不是 CPU 上生成的。在受支持的硬件上,与使用 CPU 相比,此方法可以大大减少烘焙时间。设置渐进式 GPU 还有其他要求。在“渐进式 GPU 光照贴图烘焙器”页面上了解有关要求的更多信息。
图 6. “光照贴图烘焙器设置”允许您更改场景的烘焙方法。
纹素
“纹素”(即纹理像素)是纹理贴图中的单个像素。纹素将光照贴图中每个点光源击中对象的光照信息存储起来。每单位空间使用的纹素越多,会影响光照质量、烘焙计算时间、磁盘存储成本以及光照贴图的 VRAM 成本。
为了减少所需的光照贴图数据量,请在光照贴图设置中调整烘焙每单位的纹素数量。
图 7. 光照贴图的可用设置。
在光照贴图设置中,光照贴图分辨率参数控制光照贴图中每单位使用的纹素数量。以下是具有不同光照贴图分辨率设置的立方体示例。您可以看到更高分辨率如何快速增加所需的工作量。
图 8. 第一个立方体的光照贴图分辨率为 1
。第二个立方体的光照贴图分辨率为 2
。第三个立方体的光照贴图分辨率为 5
。
要查看纹素在场景中的布局方式,请在“场景视图”中选择绘制模式下拉列表,然后选择烘焙光照贴图。
烘焙对象覆盖有棋盘格叠加层。棋盘格图案显示了烘焙灯光时纹素的分布方式。
在以下示例中,Armies 演示中将光照贴图分辨率从 15
降低到 12
,所需光照贴图的数量从七个减少到四个。
图 9. “光照贴图分辨率”为 12
的 Armies 演示。
纹素使用
虽然您可以设置整个场景中每单位的纹素数量,但通常有些对象不需要那么多纹素。
Unity 允许您控制每个对象使用的纹素数量。在对象的检查器 > 网格渲染器中,光照贴图中缩放参数值控制对象在光照贴图中使用的纹素数量。
在以下示例中,左侧立方体每个烘焙单位有五个纹素的光照信息。右侧立方体的“光照贴图中缩放”设置为 0.5。该设置将光照纹素缩放到 2.5,这比左侧立方体在光照贴图中所需的空间更少。
图 10. 具有不同光照贴图分辨率的两个立方体。
图 11. 您可以更改光照贴图中缩放设置,使对象具有更少的纹素。
尽量避免在以下方面消耗纹素
- 玩家看不到的表面和物体。这可以防止在屏幕上看不到的细节光照贴图上浪费内存。
- 光照变化很小的表面。例如,阴影中的对象或被单个光源触及的对象。
- 小型或薄型物体。它们接收的灯光量对场景的最终渲染不会增加太多。
尽可能使用假灯光
为了减少处理要求,您可以伪造一些元素。这可以使您的内容看起来像使用了灯光,但实际上使用了更有效的方法。
假阴影
实时阴影开销很大。它们是通过一种称为阴影贴图的技术生成的。将场景几何体渲染到阴影贴图的成本与启用阴影绘制的顶点数量成正比。我们建议您限制投射阴影的几何体数量和实时投射阴影灯光的数量。
您可以为动态对象上的阴影实现假阴影,而无需动态灯光。这可以降低渲染成本,并实现与动态阴影类似的效果。以下是实现假阴影的一些方法
- 使用放置在角色下方(例如平面或四边形)的 3D 网格,并对其应用模糊纹理。
- 您可以编写自己的自定义着色器,以实现更复杂的斑点阴影。
以下示例显示了如果使用 3D 网格作为阴影的结果
图 12. Armies 技术演示中的阴影实现。
直接在纹理上绘制灯光信息
如果您将一些阴影绘制到纹理中,则可以减少额外灯光所需的计算量。这在烘焙场景灯光时可以节省内存,因为它需要更少的光照贴图数据。
光照探头
当您将动态对象与烘焙灯光一起使用时,它们不会受到光照贴图的影响。这可能会导致它们感觉不像场景的一部分。
您可以使用光照探头来解决这个问题。光照探头与光照贴图具有相似的优点。它们存储可以提前计算并保存以供运行时使用的光照数据。这会将大部分计算成本转移到编辑时。
光照贴图将纹素中接收到的表面光照编码,而光照探头存储穿过空白空间的光照。您可以使用此数据来照亮移动的对象。光照探头有助于将动态对象与场景中的光照贴图对象在视觉上进行整合。
光照探头最适合用于照亮场景中移动的对象。这些探头利用了您的烘焙灯光,这使得您的移动对象具有与场景相同的光照。使用光照探头照亮动态对象比实时灯光成本更低。
您可以了解更多关于“带有光照探头的静态灯光”和“光照探头”页面。
图 13. 在 Armies 技术演示中,用于照亮动态人群的光照探头。
网格渲染器设置
无论您的场景使用哪种类型的灯光,网格渲染器设置的正确性都至关重要。
关闭所有不使用的功能。像投射阴影这样的设置在渲染场景时会增加成本,即使对象没有被照亮。以下网格渲染器设置的示例适用于图 13 中显示的角色。该角色使用光照探头数据,但不使用反射探头。
光照探头的混合探头设置将最近的光照探头的光照信息混合到角色上。当角色在场景中移动时,影响角色的光照探头会发生变化。投射阴影已关闭,因为渲染使用斑点方法。接收阴影也已关闭,因为场景已烘焙且没有实时阴影。
图 14. 图 13 渲染的网格渲染器设置。
实时灯光和灯光类型
我们建议使用烘焙灯光、光照探头和假灯光技术(例如绘制的灯光纹理或着色器材质效果)来处理灯光。但是,如果您需要实时灯光,则必须考虑要使用的灯光类型。
每种灯光类型在计算灯光时都有不同的成本。以下列表详细说明了每种灯光类型
- 平行光:这种灯光方向均匀,没有衰减。平行光是最便宜的实时灯光。每个场景通常只需要一个平行光。对于移动设备建议使用的渲染路径(前向渲染),如果场景中没有平行光,Unity 将包含一个默认的平行光。
- 聚光灯:聚光灯会剔除锥体外的对象,并且不会照亮它们。这使得聚光灯的计算成本低于球形点光源。为了获得最佳性能,请保持锥体宽度紧密,并且只击中预期的对象。
- 点光源:这些灯光向所有方向投射光线。向各个方向投射光线很有用,但非常昂贵。点光源在广阔区域内成本很高。此外,阴影计算可能是灯光中最昂贵的部分。如果您向所有方向投射光线,则会有更多的阴影和更多的计算。