光照烘焙与你
Unity 中的照明是一个复杂的话题,其性能开销也很大。它常常让人面对到大量的试验和错误。为了消除这种试验和错误,本书总结了许多关于光照烘焙的重要信息。
本书基于原作者在Gitlab上的指南:
https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Light-Baking
作者:Silent
- 为什么要烘焙光照?
- 什么是Bakery?
- 未烘焙的光照性能开销有多大?
- 实时光照及其“重要性”
- 什么是光照贴图?
- 如何制作光照贴图UV
- 什么是光照探针?
- 用于自动放置光照探针的工具
- 关于Unity内置生成光照贴图的初学者指南
- 关于使用Bakery的初学者指南
- 高级烘焙说明
为什么要烘焙光照?
当你在场景中放置一个光源时,它会直接起作用,那为什么我们还要费心思去 烘焙光照(Bake) 呢?原因有二。
首先,每个 实时光源 都需要反复绘制它所接触到的一切,这意味着光源的渲染成本非常高,相比之下烘焙过后的 光照贴图 只以纹理贴图的方式存储。
其次,实时光源没有光的反射。在现实生活中,光的反射在我们身边随处可见,晴天时刻来自地表的光反射和来自太阳本身的光一样多。光反射也是打开一扇窗户就可以使得整个房间如此明亮的原因。
以上两个原因为烘焙光源提供了很好的论据。烘焙光源唯一的缺点是,由于烘焙后的贴图数据总得存储在某个地方,你的地图体积会因此变得更大。不过,取决于您正在制作的地图类型,这个代价通常是值得的。对于较大的地图来说,优化后的光照贴图可能会占用 50-60MB 的大小。
什么是Bakery?
Bakery 是 Unity 中用于光照烘焙的一个工具。它只在英伟达 GPU 上起作用。
对 VRChat 来说,这个工具非常好用,因为:
- 高质量,使用光线追踪与AI降噪。
- 支持物理上精确的光照,但也有伪环境光遮蔽等风格化选项。
- 十分快速,比Unity原本的光照烘焙快很多。
- 能够烘焙不同种类的较 Unity 默认的视觉效果更好的光照贴图。
- 相较于使用的 xatlas 的 Unity,能够打包体积更小的光照贴图。
- 实时预览拓展(需要单独购买)使你能够在烘焙之前测试你的光照,检查使用内建工具时看不到的问题。
代价是什么?它需要花费55美元购买。实时预览拓展需要花费额外的35美元。所以,我真的只推荐你在时间十分珍贵的情况下使用它。(请留意,Bakery 会定期打折)同时,在使用它时你的确需要了解有关 Unity 的常规光照烘焙工作流的知识。
该指南的一些部分将仍然遵从 Unity 的内建光照贴图渲染方式,但不保证全部遵守。在互联网上有很多使用 Enlighten 光照系统 来烘焙光照贴图的指南,也有许多有关 一般光照理论 的指南,即使你当前主要打算使用 Bakery,我仍推荐你寻找一些其他的替代品,你知道的, Unity 嘛。我将在这篇指南的末尾加上一些资源。
未烘焙的光照性能开销有多大?
该部分详细涵盖了每种光源的性能开销。
在计算开销时,使用 Draw Call Passes 作为基本单位。一个 Draw Call 是Unity为显卡提供渲染数据的过程。我们不考虑在这部分实际着色像素的性能开销,如果它不新增 Pass ,我们称之为免费(Free)。否则,我们将记录它产生的 Draw Call Pass 数目。
让我们想象一个完全没有光源的空场景。
我们添加的第一个光源不是一个真正的实时光源,而是一个天空盒。这提供了环境光,并且它是免费的。来自天空和的光照将进入光照探针中,我们将在后面提到。
我们添加的第二个光源是一个方向光。这提供了主要的光照,并且它是免费的。一个考虑光照的着色器将渲染一个方向光,无论如何。
然而,这假设了它不投射阴影。如果我们打开阴影,我们将面对第一个额外的性能消耗。Unity必须渲染阴影级联——一组包含了视图中所有物体的阴影的材质。VRChat将渲染四个分级,每个分级将包含从光源视角可见的任何对象,在最坏的情况下,它将渲染四次所有对象。(诶,阴影不使用遮挡剔除)
有一个额外的性能开销。当打开阴影时,Unity将需要渲染一个渲染包含所有可见对象的深度通道的深度缓冲(Depth Buffer)。这会与主阴影通道一起渲染。深度缓冲对于着色器效果非常有用,但是它是一个额外的性能开销。
我们添加的第三个光源是一个点光源。它为它范围中的所有对象增加一个 Pass,并且再次渲染它接触到的任何对象。
点光源没有阴影。如果我们打开阴影,Unity将渲染一个六面的立方体贴图——从光与阴影的透视关系来看。这意味着在光源范围内的对象将渲染至多六次。
我们添加的第四个光源是聚光灯。它与点光源工作原理相同,为它范围内的所有对象添加一个 Pass。
如果对聚光灯打开阴影,它将为阴影渲染一个 Pass。只需要一个,因为它是聚光灯。
我们添加的第五个光源是区域光。无事发生,因为区域光只能在烘焙后生效。
如果设置这些光源为烘焙的(Baked),然后烘焙光源,它们将不再有性能开销。它们将被放入光照探针中,这个探针之前仅包含了环境光。
所有非静态的物体可以基于它的位置读取Unity提供的光照探针信息。这是光照的性能开销最小的形式,即使它能够重现任意数量的光源及其反射——那些正常情况下无法重现的情况。
烘焙光源是好的因为它们性能开销小,而且视觉效果良好。
实时光照及其“重要性”
实时光源同样有一个重要的设置,在 VRChat 中 Unity 将只渲染八个光源作为完整的额外 Pass 的光源,对单个物体受灯光影响并重新渲染的次数设置了上限。
它选择哪个光源取决于光源设置的重要性。
当一个光源是重要的时候,根据优先级它将被渲染为实时光源。重要的光源可以渲染阴影,无论实时阴影和与一个实时阴影烘焙遮罩连接的混合阴影。
什么是光照贴图?
如同一个模型可能包含的基本反射/颜色贴图和法线贴图等等贴图,光照贴图同样是一个作用于模型表面的贴图。使用 Bakery 或其他的工具,我们能够使用比实际场景中更高质量的照明算法来预先计算照明,然后将其保存到贴图中。
这意味着使用光照贴图的模型需要 单独一组 UV 以储存光照贴图。这些 UV 可以通过在模型文件中启用 "Generate Lightmap UVs(生成光贴图 UV)"功能在 Unity 中自动生成,也可以在建模工具中手动创建第二个 UV 通道。Blender 可以获取现有的 UV 并重新拆包作为光照贴图 UV,使得这个过程更加简单。
Unity 为光照贴图提供了三个选项以供 Bakery 使用。
间接烘焙(Baked Indirect)
间接烘焙(Baked Indirect) 将非直接的光照烘焙入光照贴图中,允许你选择是要 将主光源包括在内 还是 单独添加在顶部。这意味着你可以在场景中使用烘焙的光照贴图,同时仍能包含带有动态阴影的实时日光或月光等光源。这样做的性能开销相当高,因为主光源仍需要为每个物体渲染实时阴影,但视觉效果也是最好的。
阴影遮罩(Shadowmasks)
阴影遮罩(Shadowmasks) 将烘焙包含环境光(ambient light)的光照贴图,还会烘焙包含方向光阴影(directional light shadow)的光照贴图。这允许光源获得部分实时光源的优点,例如适当的镜面高光(specular highlights),同时避开场景烘焙部分的实时阴影的性能开销。阴影遮罩(Shadowmasks)可以与动态阴影(realtime shadows)相结合,看起来漂亮而逼真。或者,您也可以使用遮蔽探针(Occlusion Probes)将光源设置为完全烘焙,在这种情况下,Unity 还会在每个光线探针中烘焙一个值,指定其是否被主方向光照射,从而使其看起来基本相同,但没有玩家阴影。
削减式(Subtractive)
削减式(Subtractive) 模式将烘焙包含场景中所有光源的光照贴图,但如玩家之类的动态对象将仍然投射阴影。这些阴影将在与阴影颜色关联的光照贴图上裁切。这样做优化很好,但是有些许难看。
如何制作光照贴图UV
为对象创建 UV 贴图十分困难。而为光照贴图创建 UV 贴图更是难上加难。但这对视效质量的影响很大。Unity 的自动光照贴图 UV 生成功能在处理复杂对象时效果并不理想,而对于简单对象,它还会在一些非常明显和难看的地方出现接缝。解决办法是什么?我们自己来制作它们吧!
光照贴图 UV 必须完全位于 0-1 范围内,并且其中的任何部分都不能重叠。如果光照贴图 UV 的某些部分重叠,则烘焙结果将被破坏,因为来自重叠区域的光线会相互冲突。如果你在光照贴图中看到了黑色斑点,可能是因为光照贴图 UV 损坏导致的(Bakery 将会在日志中对 UV 重叠向你警告)。
尽量使每个表面的像素密度保持一致。换句话说,确保物体的每个部分都能获得大致相同的光照贴图面积,这样的话如果模型的纹理是棋盘格,那么方格的大小就会一致。Bakery 会在可能的情况下自动抹平光照贴图之间的接缝,但如果两侧没有对齐,最终看起来还是会有损坏。
鉴于这个,我们来看看需要记住的一些要点。
1. 不要重叠 UV。
像之前说的,如果 UV 重叠,光照贴图将不能正确生成。
2. 保持纹理坐标在 0-1 之间。
如前所述,如果 UV 在此范围之外,就无法正确生成光照贴图。光照贴图对象的实际分辨率是在 Unity 内设置的。
3. 不要将单独的 UV 岛屿(island)打包得太靠近。
如果靠的太近,模型的其他部分的阴影将会泄露。为了避免光渗(Light Bleeding),每个 UV 岛屿之间必须保留足够的空间。
4. 尽可能隐藏接缝。
请确保接缝看上去不明显,因为根据光线贴图分辨率的不同,接缝可能会非常显眼。
5. 如果可以与坐标轴对齐,不要把 UV 对角放置。
对角的 UV 将非常明显,并且与轴对齐的矩形相比它们的性能很浪费。请尽可能避免这样做。
6. 把 UV 岛屿连接起来并不总是好的。
一方面说,将岛屿连接起来一般是合理的。这样会减少接缝与难看的缝隙。但是另一方面,如果一个区域的分辨率不够高,网格某一区域的纹理会渗入其他部分,导致不正确的着色。
7. 在曲面角度发生变化的边角处增加像素分辨率。
如果模型存在斜边,在光照贴图上给斜边区域留出额外的空间可以避免光渗和接缝。
实际上,特别是对 VR 来说,给硬表面模型的边缘加上斜边是个好主意。这样做会去除了明显很假的如同 CG 一样的超级锐利的边缘...但是同样使得光照贴图视觉效果更好。
如果你的模型有硬边缘,分割那里的光照贴图看起来是正确的,但是现实生活中的绝大部分物品不会有超级硬的边缘。不过,如果连接那里的边缘,光照贴图会以一种难看的方式渗过它。所以请使用斜面将边缘变得光滑。斜面将使得落下的光平滑地穿过模型,增加更多可感知的细节和自然的外观。
笔记:
* http://tsumikiseisaku.com/blog/unity-japan-office-2/
这条信息主要基于这条日文博客稿件。检查原文,了解 Unity 日本办公室项目的建模过程和一些精美的演示图片。
* https://docs.unity3d.com/Manual/LightingGiUvs-GeneratingLightmappingUVs.html
有关生成光照贴图 UV 的 Unity 文档,展示了更多有关自动生成过程如何失败的细节信息。
* https://docs.unity3d.com/Manual/ProgressiveLightmapper-UVOverlap.html
Unity 的有关如何调试 UV 重叠及其导致的问题类型的页面。
* https://docs.unity3d.com/Manual/GIVis.html
Unity 的有关各种可能会显示光线贴图的问题的可视化模式的页面。
什么是光照探针?
光照贴图可以覆盖环境,但如果仅仅只是烘焙光照贴图的话,动态物体将不会受到影响。 你还需要光照探针!
光照探针是空间中的一个点,可以从各个方向捕捉周围的光照图像。
当有足够多的探针在它们之间形成一个四面体时,这个空间就会影响其中的动态物体,并将最近的探针的数据发送给它们,在四面体的点之间进行混合。
光照探针对动态物体从场景中接收光照的方式有很大影响。因此,如果摆放位置有误,就会使动态对象看起来完全错误。然而,光照探针的性能开销极限的小。您可以在一个场景中使用数以万计的烘焙光照探针,而对性能表现几乎没有影响。相反地说,放置数以万计的探针会非常繁琐,因此建议使用工具来帮你完成。
在这种情况下,我建议您阅读 Unity 有关光照探针的页面,了解光照探针的工作原理和放置位置。
用于自动放置光照探针的工具
本节主要涵盖有关光照探针安放工具的信息。
Light Probes Volumes (免费)
Light Probes Volumes 是一款免费工具,可根据场景碰撞情况放置探针。它使用方便,设置快捷。只需放下体积,它就能将其投入使用。
Magic Light Probes
Magic Light Probes 是 Asset Store 中的付费资产。它的价格和 Bakery 差不多,打折频率也差不多。它使用一些算法,沿着光线变化的地方和灯光所在的地方放置探针。它可以用来同时放置大量探针,紧贴地图几何图形,以令人惊讶的方式真实地再现光照。设置程序虽然复杂,但却能产生非常好的效果。 然而,它也容易出错。
AutoProbe
AutoProbe 是 Asset Store 中的付费资产。 它的价格是 Bakery 的一半,但也经常打折。它使用简单的方法在体积内将光照探针均匀地散射到场景周围。它还具有优化功能,可在场景烘焙后去除不必要的探针。 它能产生良好的效果。
关于Unity内置生成光照贴图的初学者指南
(不幸的是,这篇更像是一个*悲观*的指南)
本节将介绍如何使用 Unity 内置的烘焙工具。 Unity 提供了三种光照贴图制作选项。
- Enlighten 屡试不爽,但非常过时,而且在较新的 Unity 版本中使用它已经不值得。
- Progressive 烘焙工具因为它们的特殊功能组导致其有许多 Bug,特别是在 Unity 2018 中。
如果你使用 Enlighten,你同样也可以使用实时 GI(全局照明)。实时 GI 会生成一个 meta 光照贴图,存储光照贴图各部分所能看到的内容,然后在场景实时运行时计算光照,并在光照发生变化时刷新。如果你想制作电影院或是变化光源,这是非常好的。但是这需要保持地图的大小较小,否则为了视觉效果而更新光照贴图的速度将会很慢。Realtime GI 同样影响性能表现,即使它刷新速度很慢。如果你不需要它,就关掉它。请在接下来的章节中牢记这一点。
The Lighting Window
在 The Light Window 中,您可以为内置光源贴图配置最重要的设置。我将逐一介绍。
对于环境照明来说,我推荐使用天空盒模式,并且始终在场景中应用天空盒以体现你想要的环境光。将强度系数始终保持在1。环境模式应与你是否希望天空盒改变光照(使用实时光)或天空盒是静态的(使用烘焙光)相匹配。
对于环境反射来说,最好使用天空盒或者场景中的自定义探针。想了解更多细节,请看我的反射探针指南。切勿留空。
实时光源 - 你需要吗?如果不需要,确保将它关闭。
混合光源 - 像之前说过的,这些是混合光源模式,仔细地选择。
光照贴图设置 - 这是你做出选择的地方。如果你关闭实时或烘焙 GI ,不同的选项将被关闭。这些选项主要影响最终结果。这些是 Enlighten 的选项,因为进一步的选项在 Unity 文档中有更好的解释。
* 间接分辨率设置实时 GI 中的光照贴图大小。这对烘焙的静态光照贴图没有影响。
* 光照贴图分辨率设置烘焙的光照贴图的纹理元素大小。你可以通过在场景视图的右下角选择烘焙过的光照贴图来看每个物件上应用了几个纹理元素。
* 光照贴图填充设置光照贴图上每个对象之间的间隙大小,但你很少需要使用它。
* 光照贴图大小设置光照贴图能够被生成的最大大小。如果一个物件有一个大小很大的光照贴图,或者其在场景中的比例很大,他将被压缩以融入这些纹理当中,并且如果更小的话,它将被与其他小的纹理一同分组,直到填充整张光照贴图。更大是更好的,但是 Unity 并不擅长将他们填充得紧密,所以小物件的更大的光照贴图经常有大块区域被浪费。
* 压缩光照贴图应该始终打开。如果不压缩的话,光照贴图可以变得非常的大。
* 环境光遮蔽将在光照贴图的角落增加额外的暗处,这可以提升视觉效果,即使它不是与实际相符的。
* 最终收集(Final Gather)将提升最终结果的视觉效果,使其看起来更好。然而这需要额外的烘焙时间。
* 方向模式决定方向性光照贴图是否被生成。普通光照贴图如果需要与烘焙光源一同使用,则需要方向性光照贴图。
* 间接强度改变间接光源的强度高低。该文档显示它应该是光照贴图的直接系数。
* 反射率增强使对象的基础颜色变得更亮。该文档显示它能让东西变白,但实际情况似乎并非如此。
* 光照贴图变量是一个有这更多难以解释的设置的单独的设置文件。想了解更多请查阅 Unity 的相关文档。
关于使用Bakery的初学者指南
如果打开 Bakery 的窗口,它将更改你的光照设置,这样 Unity 将不会自动覆写它烘焙的的光照贴图。 由于 Bakery 独立于 Unity 的光照系统,你需要注意以下几点:
- 不要使用光照(Lighting)窗口里的生成光源(Generate Lighting)按钮,否则 Unity 将覆写 Bakery 的光照。
- 同样的原因,不要打开光照窗口中的自动生成(Auto Generate)选项。
- 不要在反射探针上使用烘焙(Bake)按钮,除非他们是你自定义的。在“烘焙的(Baked)”反射探针上使用烘焙将会启动整个 Unity 光照贴图烘焙流程。
Bakery 不使用 Unity 的光照组件。如果在场景中使用常规光源,它将始终作为实时光源渲染。相反,Bakery 有自己的一套 Light 组件,与 Unity 本身有不同的设置。
您可以在同一个对象上放置 Unity 光源和 Bakery 光源。 如果将 Bakery 光源放在 Unity 光源上,它将提供复制 Unity 光源参数的选项。当您要将大量光源转换为 Bakery 光源时,这非常方便——只需选择所有光源,添加相应的 Bakery 组件,然后选择 "从实时光源复制 "即可。
在 Bakery 中烘焙光源时,也会在 Unity 光源上设置烘焙标志。这可用于混合光源,其性能开销与实时光源相同,但由于有环境的间接光照反射,因此其视觉效果更好。您也可以在烘焙前使用它来预览方向光源和点光源,将它们可视化为实时光源。
在 Unity 中,天空盒将会自动用于渲染天空盒中的环境光,但在 Bakery 中并非如此。要渲染环境光,你必须添加一个 Bakery Sky Light 组件。Bakery Sky Light 会使用环境颜色或立方体贴图将场景外部的光照投射到场景上。 如果没有,阴影将是黑色的。
理想情况下,您应该使用自定义反射探针渲染天空盒的立方体贴图,并隐藏除天空以外的所有内容。 然后在 Sky Light 中使用生成的纹理。 这样做的结果看起来既精确又平滑。
烘焙的确使用 Unity 的光探针组组件来烘焙光探针。 它提供两种光探针模式:
- L1模式,Bakery 将通过光源映射过程创建光照探针。 这是默认选项,也是最快的选项。 但它有一个小缺点,就是只能看到 Bakery 所看到的场景,而不能看到 Unity 所看到的场景,因此无法正确地捕捉特殊着色器效果。
- Legacy 模式,Bakery 会在光照贴图生成流程后创建光照探针。 它将 Unity 中的场景渲染生成反射探针,从而确保结果的准确性,但速度有点慢。
如果使用 L1 模式,光照探针会与光照贴图同时烘焙。 如果使用 Legacy 模式,则需要单独烘焙。 点击 "生成光照探针 "按钮后,Bakery 会将数据烘焙到光探针中。
所以,回顾一下,在为场景制作灯光时,你应该:
- 禁用 Unity 灯光组件,除非您的光源是混合光源。
- 添加一个 Bakery 天空球,并为其添加一个天空盒立方体地图,用于环境光。
- 添加一盏 Bakery 方向光源,设置方法与主方向光源相同。
- 如果需要,可添加 Bakery 点光源。
- 使用 Bakery 中的 Show Checker 选项查看单个网格的光贴图分辨率,并在必要时进行调整。
- 如果您拥有支持 RTX 的显卡,请打开 RTX 模式。
- 如果场景使用法线贴图,请将方向模式(Directional Mode)设置为主方向(Dominant Direction),这是最兼容的模式。
高级烘焙说明
Mixed Lighting
混合光源的性能开销与动态物体的实时光源相同。由于第一个方向光源是免费的,因此您可以使用阴影遮罩模式将高质量的烘焙照明与实时阴影相结合。将混合模式下的 Unity 方向光与设置为 "阴影遮罩和间接(Shadowmask and Indirect)"的 Bakery 方向光相结合,就能创建阴影遮罩方向光源。
要充分利用这一优点,请在 Bakery 中启用遮蔽探针。遮蔽探针将方向光源的阴影储存到光照探针中。当物体处于阴影中时,Unity 会根据探针的数值使主方向光变暗,就像它们从照明中获得了阴影一般。
Light Probe Ringing
Bakery 将把所有射入的光源烘焙入光照探针。不过,由于光照探针计算的性质,在高对比度照明区域,如果来自单一方向的光线水平较高,就有可能产生极强的阴影。这种现象被称为 Ringing。 这主要影响使用标准阴影的物体。
有几种方法可以避免 Ringing。 可以将场景中的物体设置为使用 Bakery 的 标准 着色器,该着色器有一个使用 "non-linear SH "的选项,可以执行过滤步骤来避免这一问题。不过,无法控制着色器的对象(如虚拟形象)则需要单独进行更改。
使用阴影遮罩的混合光源可以避免这一问题,因为它可以将高强度的方向光源(产生 Ringing 的主要原因)从光照探针中移出,并进入着色器计算。不过,这不会影响较小的光源。 另外,也可以通过避免场景照明的高对比度来规避这一问题。
如果 Bakery 在光照探针上增加了它的 deringing 过滤器,情况可能会有所改变。
Realtime GI
我建议不要在主要使用 Unity 实时 GI 的地图项目中使用 Bakery,因为 Bakery 会自动为您关闭它。如果在 Bakery 的设置中勾选 "与 Enlighten 实时 GI 结合使用 "选项,就可以同时使用 Bakery 和实时 GI。 像设置中指出的,这使用的是 Enlighten,这意味着你需要等待一段时间让 Unity 完成烘焙,然后在上面添加 Bakery 的光照贴图。
https://github.com/MerlinVR/VRC-Bakery-Adapter
一个脚本。该脚本可将 Bakery RNM 和 SH 方向光照贴图绑定转换为 VRChat 可以处理的格式,而无需将 Bakery 脚本列入白名单。
http://techblog.sega.jp/entry/2019/04/25/100000
在 Unity 中设置物理层面上可靠的光照的指南。
https://gitlab.com/s-ilent/lightmap-quality-regions
作者的工具,用于在区域中设置模型的光照贴图质量。 与 Bakery 兼容。