liuqingmei 发表于 2020-11-24 10:31

写给美术看的Unity全局光照技术(理论篇)

现在是北京时间晚上11点半,起来搞点小文章778。
很久没有混迹知乎了,今天突然起了兴致,决定放一篇远古时期写的文章,分享给大家。
文章知识点是我当时对Unity GI的认识,技术大佬们看到有纰漏的地方就凑合着看吧哈哈,不过这些内容对美术来说,还是是一定帮助的。
写在前面

什么是全局光照? 全局照明(GI)是一个系统,用于模拟光从表面反射到其他表面(间接光)的方式,而不是仅限于直接从光源(直接光)照射到表面的光。 全局光照 = 直接光照 + 间接光照 那什么是直接光照?什么是间接光照?
在Unity4中,我们可以试试打一盏灯照亮物体,会发现物体在光源没有覆盖的地方,是一片死黑的。这就是仅考虑直接光照的结果。现实世界中,光线到达物体表面后被弹射开去,在空气中传播,在各个表面来回弹射,直到能量消耗殆尽。可以想象一束光投进窗户,从而整个房间的阴暗角落也被照亮的画面。这就是间接光照效果。然而,实现间接光照的算法非常复杂,计算速度太慢,用过3D Max渲染的同学应该知道渲染一张图片需要多长时间。所以,面对游戏等实时渲染领域,一秒钟需要渲染数十张图片以达到流畅的画面感的要求,要实现全局光照(GI)效果,显然需要另寻蹊径。
在游戏领域,解决这一局限性的一种方式就是:只为预先知道不会移动的物体(即被标记为静态的物体)计算间接光照。这样慢的计算可以提前完成,同时由于对象不移动,所以以这种方式预先计算的全局光照在运行时仍然是正确的。 Unity支持这种称为Baked GI(也称为Baked Lightmaps)的技术,也就是我们常说的“烘焙”。除了间接光照外,Baked GI还利用了更多的计算时间,可以从area light和间接光中生成更逼真的柔和阴影。至此,Unity4烘焙出来的lightmap信息包括了直接光+间接光+烘焙阴影。
ps:全局照明效果对于动态物体也是有办法的。Unity提供了一套Light Probe的技术,可以将光照信息保存在这些预先布置好的灯光探头中,动态物体从这些探头中获得光照信息。当然,效果不会很精细。这种技术后面再做论述。
然而随着对游戏画面要求的日益提升,这种方法暴露了诸多局限性与不足。为此,Unity5提供了一套更为完善的光照技术解决方案。有如下特点: - 支持预计算的实时全局光照效果(Precomputed Realtime Global Illumination)。 - 更完善的混合光照模式。 - 加入环境反射探针(refletion probe),以适配PBR效果。
EnLighten全局光照系统

Enlighten为我们提供了预计算的实时全局光照(Precomputed Realtime Global Illumination)和混合光照(Mixed Lighting),这些技术不一定都用得上。根据项目要求和画面特点,选择性能和效果最平衡的技术方案,才是我们学习这套系统的关键。
组成部分

一般来说,Unity中实现照明的方法可以被分为“实时”和“预计算(烘焙)”两种,都可以结合使用来创造逼真的场景照明。因此,我们需要了解全局照明的各个组成部分,以便根据相对优势和性能特征来选择适当的方法。
全局照明(global illumination) = 直接光照(direct lighting) + 间接光照(indirect lighting) + 环境光(ambient light)
直接光照(direct lighting):
directional/point/spot等光源的直接光照 环境光(ambient light):对于动态物体,提供实时的环境光计算。实际上是light probe。
间接光照(indirect lighting):
directional/point/spot等光源的间接光照(indirect bounce) 环境光(ambient light):对于静态物体,作为简介光照烘焙到Lightmap中。自发光材质(emission Material)
Unity对于indirect lighting的定义为:自光源发射,至少击中场景表面两次,最终到达摄像机的光线。
常用光源类型

常用的光源类型包括平行光(directional light)、点光源(point light)、聚光灯(spot light)、区域光(area light),这些光源可以为场景物体提供直接光和间接光效果,需要注意的是由于area light计算过于复杂,目前只支持烘焙的实现方法。 下面以spot light为例,通过构建一个纯净的实验环境,分别展示直接光照、间接光照的效果。ps:暂时不用管间接照明是用哪种方法实现的。
spot light的直接光照效果(Indirect Multiplier为0,表示间接光强度为0)
spot light的间接光照效果(灯光组件是非激活状态,因为间接光已经烘焙到lightmap中,而这里要屏蔽直接光效果)
spot light的直接+间接光照效果(可以留意到光源范围内强烈的光照,以及范围外的光线从各表面弹射产生的结果)
环境光

环境光表示场景周围的光线,并不是来自任何特定的源物体。它对整个场景的色彩基调起到重要作用。
可以在Lighting面板的Environment Lighting选项中对环境光进行设置,它的色彩来源Source可以设置成 - Skybox与指定颜色的混合(Skybox) - 指定固态颜色(Color) - 渐变色(Gradient)
Ambient Mode通常为自动设置,这取决于你当前使用的是Baked GI还是Precomputed Realtime GI。除非你两者都开了或者不开。                     
PS:在Unity中,ambient light对于动态物体或未经烘焙的物体而言,是作为直接光照并实时参与计算的。对于静态物体而言,ambient light所有成分都被视为间接光照并参与到烘焙中。
下面展示ambient light作为直接光照与间接光照的区别。
图一:所有物体为动态物体,环境光只为物体提供实时的直接光照
图二:静态物体经过烘焙后,环境光作为间接光照被烘焙到lightmap中
图一中环境光作为直接光参与实时计算,导致所有物体都是同一种颜色。这是因为环境照明本身就作为从四面八方照亮物体的照明,没有考虑到物体与物体之间的遮挡关系。我们把这个问题叫做环境光遮蔽(Ambient Occlusion)问题,也就是我们常说的AO。
图二中,环境光作为间接光照,在烘焙过程考虑到光线从物体各表面弹射(bounce),从而能够烘焙出柔和的阴影。如果要更明显的环境遮挡效果,Unity还提供了烘焙AO到lightmap的功能,可在Lightmapping Settings选项中勾选Ambient Occlusion开启。
自发光材质

与area light一样,自发光材质(emissive materials) 在其表面发射光线,可以在场景中作为光源照亮其他物体,但这毫无疑问,计算过程复杂,需要烘焙(baked)或预计算(precomputed)才能发挥效果,而这就要求自发光物体和被照亮的物体都必须是静态物体,而且需要Shader本身支持Emission效果。
Emitted Light自发光线也包含直接光和间接光部分。其直接光部分可视为对发光体自身进行照明,间接光部分对其他物体进行照明。
以下摘自官方文档,对于全局光线的图解。
选择一种合适的光照技术方案

当你看到这里,相必你已经对全局照明效果的组成部分、光源的类型有了大致的认识,这有助于我们去选择一个合适的光照技术方案。 所以接下来,我们要学习的是对光照效果的控制,以及选择其合适的实现方式。 在本节中,我们将简要介绍不同方案的适用场合,相对优势和性能特征。
光照模式(Lighting Modes)

选中灯光,在Inspector面板中,你可以指定光源的光照模式,这个光照模式定义了该光源的预期用途。
实时直接光照(Realtime)

实时直接光照的环境设置:把Realtime GlobalIllumination和Baked Global Illumination勾选去掉,同时将Auto Generate关闭并清空烘焙数据Clear Baked Data。
此时,realtime灯光为场景提供实时直接光照,并能选择是否开启实时阴影。实时光照是在场景内对物体进行照明的最基本的方式,对于照亮人物或其他可移动的物体非常有用。
但值得注意的是,在没有被光源范围覆盖的地方,这些区域是完全黑色的,因为没有反弹的光线(bounced light)。该问题见 上文阐述。因此,为了营造更逼真的场景,我们需要启用全局照明技术,Unity5为我们提供了两套解决方案:混合光照(Mixed lighting)和预计算全局实时光照(Precomputed realtime global illumination)
混合光照(Mixed lighting)

Unity在5.5版本中加入了混合光照技术,是可以将Realtime光照与Baked GI混合的一种技术方案,让我们可以按照实际需求和主观意愿,去组合搭配。
典型应用一:灯光的间接光部分被烘焙到lightmap中,烘焙完成后,该光源还能继续参与实时光照计算,以提供材质的法线高光效果。 典型应用二:将灯光对静态物体产生的阴影烘焙到单独的lightmap中,这种lightmap叫做ShadowMask,在运行时,根据ShadowMask,对动态物体产生的实时阴影能够与烘焙阴影更好地混合。
烘焙GI(Baked GI)

开启方法:只要勾选Baked Global Illumination,就会启用Mixed Lighting的技术方案,因为Baked GI是它的一部分。我们只需要将所有光源设置成Baked模式,确保只使用了Baked GI技术。 Unity在运行时之前预计算这些灯光,并且不会在任何运行时内计算它们。这意味着Baked灯没有运行时间的开销。 Unity将Baked灯光的直接和间接照明映射到光照贴图(lightmap)照亮静态游戏对象)和光源探测器(light probe)(照亮动态光照游戏对象)。 Baked模式也是唯一的不能在其他动态GameObjects上投射阴影的light模式。
Baked GI的优点
- 来自静态GameObjects的高品质阴影,而无需额外成本。 - 提供间接照明。 - 静态GameObjects的所有光照来自Shader中的一张Texture,即Lightmap。
Baked GI的缺点
- 没有实时直接照明(导致也没有镜面高光(Specular Highlight)效果)。 - 动态GameObjects要获得来自静态GameObjects投射的阴影,只能使用Light Probes,但是其效果是低分辨率的。 - 与实时照明相比,Lightmap图集会导致内存需求增加,因为光照贴图包含直接照明信息而需要更加精细。
混合光照模式(Mixed Lighting Mode)

Mixed灯光是指将Mode属性设置为Mixed的Light组件。 Mixed灯光可以在在运行时可以改变其Transfrom属性和灯光属性(如颜色或强度),但只能在有限的范围内。 它们照亮静态和动态GameObjects,总是提供直接照明,并可以选择提供间接照明。 混合光照下的动态GameObjects可以在其他动态GameObjects上投射实时阴影。
场景中的所有混合灯光使用相同的混合光照模式(Mixed Lighting Mode),需要在Lighting面板Mixed Lighting选项的Lighting Mode中进行选择,有Subtractive、Baked Indirect、ShadowMask、DistanceShadowMask四种模式。
Subtractive模式

在Subtractive模式下:
会将Mixed灯光的直接照明、间接照明、阴影信息全部烘焙到Lightmap中去,这一点跟Baked GI是一样。Subtractive模式也是四种混合光照模式中,唯一会将直接照明烘焙到lightmap的模式。在烘焙完成后,Mixed仍然可以给动态GameObjects提供实时光照,并支持高光效果。但是,他们只能通过Light Probes从静态GameObjects接收阴影。在减法模式中,主方向光是唯一能够将动态GameObject中的实时阴影投射到静态GameObjects上的光源。但该模式不能保证烘焙阴影和实时阴影的正确组合。因此,Subtractive模式提供Realtime Shadow Color设置。
Unity在Shader中使用此颜色将实时阴影与烘焙阴影进行合成。要做到这一点,它可以减少动态GameObjects覆盖区域的光照效果。因为引擎无法提供一个预定的正确值,所以选择一个适用于任何给定场景的值是自己的艺术选择。
注意:Mixed Light的Shadow Type设置若为No Shadow,该光源只有间接光部分参与烘焙,并可以为所有物体提供实时光照。这与文档描述的不符,疑似Unity的一个Bug,是一个要注意的问题。所以,要么所有Mixed Light都开启阴影选项,要么就都设置成Baked模式,只留一个平行光作为Mixed模式,并注意开启阴影选项。 仍然存在的不足: - 它不能为静态物体提供实时直接照明,因此不提供高光效果。 - 它不提供将动态GameObject中的实时阴影投射到静态GameObjects上,除了一个方向灯(主灯)。 - 它无法很好地解决动态和静态阴影组合。
Baked Indirect模式

对于设置为Baked Indirect模式的灯光,生成的Lightmap和light probe只包含间接光部分信息,并且不执行阴影的烘焙。烘焙后,Mixed灯光会继续为所有物体提供实时直接照明和实时阴影。 Baked Indirect模式的性能要求使其成为中档PC和高端移动设备的理想选择。
优点:
- 它提供了与实时照明相同的视觉效果。 - 它为静态和动态GameObjects的所有组合提供实时阴影。 - 它提供间接照明。
缺点:
- 与其他混合光模式相比,它具有更高的性能要求。 - 由于Unity实时阴影会有距离限制,远处的阴影将不会被渲染。
ShadowMask模式

ShadowMask是一张遮罩图,它与相应的光照贴图共享相同的UV布局和分辨率。它的每个像素储存最多4个灯光的遮挡信息,因为纹理最多只有RGBA四个通道。
Unity会烘焙静态GameObjects间的阴影信息,并将它们存储在一个单独的Shadowmask Texture中,同一个像素最多可保存4个灯光的遮挡信息,如果超过4个灯重叠,任何额外的灯产生的阴影将会被烘焙到lightmap中去。光探头也可以接收最多4个灯的相同信息。
在ShadowMask模式下:
静态GameObjects通过ShadowMask接收来自其他静态GameObjects的阴影。他们也会从动态GameObjects中获得实时阴影,但是只有阴影距离(Shadow Distance)内的阴影。可在QualitySettings面板中设置。

动态GameObjects通过ShadowMap从阴影距离内的其他动态GameObjects接收阴影。他们还通过Light Probes从静态GameObjects获得阴影。阴影保真度取决于场景中Light Probe的密度,以及在Mesh Renderer上选择的Light Probes模式。
PS:ShadowMap叫做阴影贴图,Unity是实现实时阴影过程中生成的一张贴图。注意与ShadowMask做区分。
Unity会根据ShadowMask(包含静态GameObject阴影信息)和ShadowMap(包含动态GameObject阴影信息),在Shader中做相应的处理,将静态和动态GameObjects的重叠阴影组合在一起,
解决了静态阴影和动态阴影的融合问题,全面提供实时光照效果,可对比上图Subtractive模式
优点:
- 为所有物体提供与实时照明相同的视觉效果,因此具有法线高光效果。 - 所有Mixed光源都能提供从动态GameObjects到静态GameObjects的实时阴影。 - 很好的融合了动态和静态阴影。 - 适用于中低以上的性能要求,因为静态GameObjects的阴影不是实时计算的。 - 提供间接照明。
缺点:
- 它只能通过Light Probes将静态GameObjects中的低分辨率阴影提供给动态GameObjects。 - ShadowMask允许最多4个重叠的光线量。 - ShadowMask贴图增加了较多的纹理内存。
DistanceShadowMask模式

DistanceShadowMask模式是ShadowMask模式的升级版。
在阴影距离(Shadow Distance)内的GameObjecs(Edit > Project Settings > Quality > Shadows): Unity会将动态和静态的GameObjects渲染到ShadowMap中,换而言之,就是都进行实时阴影计算。由于这个原因,DistanceShadowMask模式比ShadowMask模式具有更高的性能要求。
在Shadow Distance之外的GameObjecs:
- 静态GameObjects通过ShadowMask从其他静态GameObjects接收高分辨率阴影。- 动态GameObjects通过Light Probes接收来自静态GameObjects的低分辨率阴影
实时全局光照(Realtime GI)

尽管Mixed Lighting已经很完善,但还是无法对场景的间接照明做动态变化。为此,Unity 5.0新增了号称为“预计算实时GI(Precomputed realtime GI)”的新技术,通过这种方法,可以创建具有丰富全局照明的光照环境,并实时响应照明变化。 一个很好的例子就是昼夜变化系统:光源的位置和颜色随时间而变化。 用传统的Baked GI,这是不可能的实现的。
需要注意:Realtime GI仍然需要一个类似于上面提到的烘焙(baked)的预计算(precomputed)阶段,仍然限于静态对象。但是,它不仅在构建时预计算光线的反弹,而且还会预先计算所有静态物体间光线反射可能经过的路径,并对这些信息进行编码以供在运行时使用。所以对于所有的静态对象来说,预计算(precomputed)阶段解决的问题是“如果任何光照射到这个表面,它会在哪里弹跳?”然后Unity会保存这个信息,指出光线可以传播哪些路径以备后用。最后的照明是在运行时通过将现有的实际灯光输入到先前计算的光传播路径中完成的。更多内容见技术细节。
这意味着灯的数量和类型,其位置,方向和其他属性都可以改变,间接照明也会相应更新。类似的,也可以改变物体的材质属性,例如它们的颜色,它们吸收多少光线或者它们自己发射多少光线。
虽然预先计算的实时GI也会产生柔和阴影,但是除非场景非常小,否则它们通常必须比Baked GI所能达到效果的更粗糙。还要注意的是,虽然预计算实时GI在运行时计算最终的照明,但它在几个帧内迭代地计算的,所以如果在照明中做了大幅度的改变,则需要更多的帧才能完全生效。尽管这对于实时应用来说足够快,但是如果目标平台资源非常有限,那么使用Baked GI可能会更好地实现更好的运行时性能。
使用Realtime GI

实时照明与Realtime GI的组合是Unity中最灵活和最现实的照明选项。要启用Realtime GI,打开Lighting窗口并勾选实时Realtime Global Illumination。
启用实时GI后,实时灯会向场景中提供间接照明以及直接照明。但这种组合适用于光源变化缓慢,对场景有高度的视觉冲击的情况,如太阳在天空中移动,或者在封闭的走廊中缓慢的脉动光。不要使用Realtime GI来快速改变灯光,因为迭代的计算造成的延迟效果得不偿失。
请注意,与较不复杂的Baked GI相比,实时GI使用大量的系统资源。全局照明在Unity中由一个名为Enlighten的中间件管理,该中间件具有自己的开销(系统内存和CPU周期)。
因此Realtime GI适用于针对中高端PC系统的游戏,以及针对PS4和Xbox One等平台的游戏。一些高端移动设备也可能足够强大,以利用此功能,但您应该保持场景小,实时灯光分辨率低以节省系统资源。
要禁用某一光源的实时GI的效果,可以选中该光源Gamobject,然后在Light组件中将Indirect Multiplier设置为0。这意味着Light不会提供任何间接光源。要完全禁用实时GI,请打开Lighting窗口,并取消Realtime Global Illumination。
技术细节

预先计算的实时GI模式:Unity仅预先计算表面到表面的信息:物体间光线可能会经过的路径。
在运行时,Enlighten利用这些预计算的信息,通过CPU计算光线的弹射,因为过程计算量很大,所以它被分散到几个帧中计算,这就是上文一直说的迭代计算。并将最终的结果储存在动态光照贴图(Dynamic lightmap)和光照探针(light probe)。换句话说,Realtime GI最终的实现方式还是lightmap,只不过这个Lightmap是在运行时动态更新的,而且它需要几帧时间,直到光线完全反射到场景中的静态元素上,动态光照贴图和光探针才能获得到最终结果。
对于属性缓慢变化的灯(例如发光的太阳在天空中移动),这不会造成问题。但是,对于属性变化很快的灯(如闪烁的灯泡),实时GI的迭代计算的特性可能不适用。而且快速的变化属性的照明不会显著地影响光系统,所以在计算中包含它们没有意义,可以考虑将这部分的光的realtime GI效果关掉,通过调节light组件上的Indirect Multiplier为0。
有几种方法可以解决迭代计算造成的延迟问题。一种方法是减少实时光照分辨率(在Lighting面板的Lightmapping Settings选项中的Indirect Resolution属性)。因为这会减少的计算量,照明迭代的速度更快。另一个选项是增加实时GI运行时的CPU使用率设置。通过投入更多的CPU时间,运行时更快地迭代。权衡当然是其他系统接受较少的CPU时间来完成他们的工作。这取决于项目的具体情况。
缺点

由于动态光照贴图(dynamic lightmap)和光照探针(light probe)采样,用于存储由Enlighten照明系统计算的实时间接反弹,增加了Shader计算复杂度和性能消耗。间接照明是迭代计算的,更新需要一定的时间,所以光源的属性变化不能太快。 虽然一个适当的HDR ToneMapping可能会帮您掩盖这一缺点。
GI与材质

物体的材质属性也是影响光线的一个重要因素,材质表面的颜色,直接决定了从该表面弹射出去的光线的颜色。还有更多的影响因素如:PBR(基于物理的渲染)材质的金属度(Metallic)和粗糙度(Roughness)会影响光线的吸收和反射程度。
粗糙的非金属材质
光滑的金属材质
GI的局限性

无论是Baked GI和还是PreComputed Realtime GI都有一个局限性,即烘焙/预计算中只能包含静态物体,所以移动的物体不能将光线反射到其他物体上,反之亦然。 不过,他们仍然可以使用Light Probes拾取静态物体的反射光。将 Light Probe事先布置在场景中的,在烘焙/预计算阶段, Light Probe会储存其位置上的照明信息,然后在运行时阶段,动态物体会获取附近的light probe里面的光照信息,从而近似地获得静态物体反射的光线。
在PBR材质中有一个很重要的照明部分:IBL(基于图像的光照)。它基于环境贴图(Environment Map)的每个像素作为入射光,计算来自环境贴图各个方向的入射光对物体的光照信息,是PBR中模拟物体周围环境光照的一个重要方法。这也是GI算法无法达到的效果。对应相关的技术是反射探针(Refletion Probe)以及Lighting面板的相关设置。
后记

以上便是“理论篇”的全部内容,一部分描述翻译自Unity官方文档。 接下来会在“实践篇”重点介绍如下内容: - 项参数详解 - 烘焙流程 - 常见问题及技巧 - PBR效果等内容
页: [1]
查看完整版本: 写给美术看的Unity全局光照技术(理论篇)