Unity提供许多进阶的光照贴图控制方法,这些设定被放在一个光照参数集(LightmapParameters)的资源里,好让设定能在不同的项目场景或是透过版本控制和团队一起共享。
- 要建立一个Lightmap Parameters资源,先找到Project窗口
- 从Create下拉选单建立(Create> Lightmap Parameters)
- 我们也可以在Project接口里右键单击选(Asset> Create > Lightmap Parameters) 来建立。
透过这个参数集可以针对烘焙光照或预计算GI做更高阶的设定
建立完成的光照参数集可以被指定给静态对象。
- 从Hierarchy接口选择你要指定变量集的对象,对象必须是带有Mesh Renderer组件的静态对象。
- 开启Lighting接口(Window> Lighting)并选择Object页签
- 从Advance Parameters下拉选单指定你的变量集给对象,右边的"Edit"按钮是开启编辑光照变量的快捷方式。
从Lighting接口里的AdvancedParameters字段指定光照参数集
同一个光照参数集可以指定个许多不同的对象,你只要从Hierarchy接口一次把要指定的对象全选起来,执行上面说明的步骤把档案指定到Advanced Parameters字段即可。
光照参数集:实例(per-instance)还是预制(per-Prefab)好?
和拆UV的部分很像,光照参数集可以指定给Prefab预制对象或给场景里的独立对象,一旦参数集被贴上对象就会覆盖掉对象身上旧有的设定。
这个方法的好处是你可以把正常情况下会用到的光照设定贴在预制对象上,然后依照不同需求修改覆盖场景里实例对象身上的光照参数设定。
本教学里,我们会从一个实例对象身上示范如何使用光照参数集,主要是因为我们想根据使用的对象来选择不同的光照参数集。
预设参数集
这部分适合用来设定场景预设的光照参数,这个参数集待会会被指定给所有场景里面带有Mesh Renderer组件但却还没指定Lightmap Parameters的对象。场景里建立的任何带有Mesh Renderer的对象都会以此为基础,这样可以省下手动指定的时间。
- 开启Lighting接口(Window> Lighting)并选择Scene页签
- 从General GI区块里找到DefaultParameter,选择你刚才建立的光照参数集。
虽然新的对象会开始采用这个预设设定值,你仍然可以从Advanced Parameter参数单读覆盖它。
默认的设定会反映到所有新的静态对象
Unity预设有几组光照参数集可以选,分别是:
- Default - HighResolution
- Default - Medium
- Default - LowResolution
- Default - VeryLowResolution
这几个不同的设定存有会影响到光照结果的设定像是光照贴图分辨率,光照图大小以及其他一些进阶选项设定,可以用来快速调整总体结果。
光照参数集说明
Unity默认的参数组合事实上已经很适合大多数的情况,但我们还可以建立自己的参数组并做更多的微调,来让GI计算达到比预期更好的结果。
Unity手册上关于光照参数集有个别的详尽说明,但针对这个教学我们也会重点说明几个最有用的设定。
Resolution
分辨率的值确订了对象采用的光照贴图解析,这个值会和Lighting接口里的分辨率做加乘。比如说,如果场景分辨率设为2,这里的分辨率设为0.5,那所有带有这个参数集的对象都会采用1texel/unit来计算光照贴图。
由于PRGI只会呈现场景里的漫反射(diffuse)和间接照明,所以我们不需要用到像传统烘焙贴图那么高(20-30)的采样值,通常设定2-3已经很好了。如果是户外场景,甚至可以缩小很多倍像是0.1就足以提供足够的细节。
分辨率值很大光照贴图所产生的影子斑点可以把Irradiance Budget这个参数调高来获得缓解。
注意,当分辨率值很大时,在较低分辨率下可能会产生奇怪的阴影,这些阴影在最终的光照贴图里可能看起来像是斑点或脏污。如果有这种情况可以试着把Irradiance Budget参数提高来获得改善。
Cluster Resolution
丛集分辨率用来决定1个像素里能有多少丛集数量。假如这个值设为1,代表光照图里面每个像素都都会有一个丛集,0.5代表一个像素会有2个丛集,换句话说丛集会是光照图的两倍大。
进一步来说,可以想象如果我们把场景的分辨率设为1,并建立一个1x1x1的方块,然后指定这个光照参数集给对象,那么方块的每一面都会有1个丛集。如果我们把分辨率改为2,结果就会变成2(1x1),方块的每一面丛集会变成4个。
上图可以看到一个分辨率设为1的1x1x1方块,光照参数设定丛集分辨率(Cluster Resolution)为1和光照贴图分辨率为2时,我们每一面都会有4个丛集。
在大多数的情况下,Cluster Resolution只需要设为低于贴图像素(lightmap texels)大小即可,例如Default -HighResolution设定值为0.6。
一个场景中丛集太多的话会很快拉高预计算时间,还会影响到实时场景的光照效能,因此必须要把丛集的数量花在刀口上,永远以保持质量尽可能的降低丛集数量为目标。
将光照贴图解析和丛集分辨率保持指定比例,这样我们可以和场景整体的分辨率建立一个相对关系。我们可以把Lighting接口里面的分辨率定义为高分辨率作为整体设定,然后针对个别对象微调各自的光照参数集。
Unity采用这种分层法方便让开发者能更全观的控制场景光照,不然要针对每个对象手动都设定光照参数的值会很麻烦。
Irradiance Budget
我们之前说明过光照计算是如何用丛集来计算静态对象的预计算光照,在预计算的过程里,丛集之间的关系被建立起来,好让光线得以在丛集网内快速传递。
在本质上,光照贴图像素值的算法是基于丛集从该像素的位置对场景的一个检视所计算得来,这会让我们可以很快计算丛集之间的光照反射最后产生一个全局光照,这些丛集就能在画面渲染完之前给予适当的样本数。
Irradiance Budget(辐照度范围)用来制订当丛集采样时每个光照贴图像素所使用到的内存量,这会决定照明结果的精度,数值太低代表每个贴图像素在记录时使用较少内存同时提升CPU效能,代价就是会失真,数值越低光照结果会越模糊。反过来看,数值拉高GI会更准确,但内存和CPU的消耗都会提升。
如果我们的预计算在Runtime执行时更新有点慢或会lag,可能降低这个值会得到改善,这个设定比较适合用在不用精细的对象,很大、模糊或遥远的物件。
Irradiance Quality
当计算PRGI时,每个光照贴图像素会开始对场景投出射线,然后将可视数据报告给附近的丛集,然后贴图像素就会得到每个丛集的百分比数值,这个值用来定义光照贴图里每个像素从丛集所分到的可视数据,而一栏设定就是用来设定每个像素能对场景投射多少射线。
如果场景里的对象和周围对象光照不合的情况下可以斟酌加大这个值,有时该暗的时候光照结果却意想不到的亮,有可能是因为投射到场景的射线不足或遮挡到,导致漏算丛集资料。同样该亮的的放如果射线没有检查到,可能会造成过暗。
提高射线的投射量就能解决类似的问题,代价就是增加预计算的时间,要优化这个时间,我们应该找出最适合的值来达到我们理想的照明效果。请注意,这个值不会影响到Runtime时的效能。
Backface Tolerance
当射线从光照贴图像素投射出,从场景丛集搜集光线时有时会打到几何的背面,当计算全局光照时我们只需要关心投射到物体表面的光照,从背面来的光照资源通常都会忽略掉,这些从背面来的光照数据会破坏光照结果,因此调整这个值能防止这类情况发生。
这里的地板上的阴影就是Unity在计算期间从对象无效的背面所创造的,增加Backface Tolerance能改善这个问题。
Backface Tolerance必须指定从前方光源来的百分比,好让正面的像素被判定为有效。假如一个贴图像素没通过测试,Unity会采用邻近的像素值尝试算得正确光照数据。
调整这个值并不会影响PRGI运算效能,也不会对预计算时间长度有太大影响。反而是蛮适合在调整Irradiance Budget都无法解决的场景贴图太亮或太暗问题时,Backfacetolerance会是一个不错的除错工具。
Modelling Tolerance
有时候在场景静态对象中存在小间隙的区域会产生黑色的光晕或是不需要残像,很容易发生在邻近有相反几何图形的区域,像是地板上的对象:
像这样物品的黑暗边缘通常可以透过加大Modelling Tolerance来改善
通常在这样的情况下,物体和物体之间存在着小小的缝隙,因为没有太多光线可以进入,导致非常暗的光照图产生。当光照分辨率低的时候,这些黑暗像素的大小可能会导致它们跑出遮挡物的边界并产生不协调的黑色块。
Modelling Tolerance是用来忽略比Threshold值还小的细节,提高这个值可以确保Unity 在计算GI时忽略掉非常靠近其他物体表面的几何面,这个值越高代表Light Transport这个阶段需要额外计算忽略这些间隙,调低ModellingTolerance也能确保小对象不会被遗漏计算。
Modelling Tolerance不会影响PRGI的优化,对于计算时间和执行效能也没甚么负面影响,它能用在一些除错流程上,解决连Irradiance Budget都无法改善的残影问题。
开始建立Lightmap Parameters光照参数资源
现在我们已经明白光照参数能做甚么了,可以开始尝试建立这些资源。
- 打开LightingTutorialStart场景
- 在Project窗口找到Assets >LightmapParameters目录并点进去
- 从Project窗口最上面的下拉选单建立一个光照参数集(Create > Lightmap Parameters
- 把对象名称改为"TutorialTerrainLow"
这个对象从镜头看起来非常大,蛮适合设一个光照参数集而不是用场景预设的
接下来我们要把刚刚新建的光照参数集指定给这个对象
- 在场景窗口里,选择最接近主场景的两座山,这些山都已经被命名为"MountainPeak"。注意,我们将忽略最远的山。
- 从Inspector接口确认两个对象都是设定为静态对象
- 开启Lighting窗口(Window> Lighting) 并选择Scene页签
- 确保最底下的Auto是打勾
- 改选择Object页签
- 从Advanced Parameters下拉选单选择刚建立的TutorialTerrainLow
- 单击右边的Edit按钮,准备开始调整设定
预设的光照参数集
首先我们要看的是Resolution,降低这个值可以加速预计算时间同时也提升执行效能,所以我们应该目标定在不影响画质的前提下采用较低的分辨率。
会很接近看的对象可以设比较高的值,但是两座山距离镜头都非常远,因此这个例子设低一点是比较好的。这些大对象表面材质相当一致,从镜头的角度来看,接收到光的颜色变化也不大,所以可以降低这个值而不会影响结果质量。
像是山或地形的大场景,采用默认值反而很浪费
使用较低的分辨率牺牲质量但可以大大节省预计算和执行效能
- 慢慢的降低TutorialTerrainLow光照参数集里面的Resolution参数并观察结果的变化。
请记得这里的分辨率和Lighting窗口里的场景分辨率是会相乘的,目前场景分辨率是1,代表如果这里的分辨率小于1的话,输出的光照贴图每unit也会小于1像素(texel)
两座山和其他的对象距离非常远,它们不可能接受频率很高的光照,因此如果我们采用较低的分辨率损失的质量不会太多。教学里我们发现用0.05就足以采样该有的光照数据。
- 从Project窗口点选TutorialTerrainLow对象
- 从Inspector界面把Resolution设为0.05
然后来看看Cluster Resolution的值,之前讨论过,这个值也是一个用来和光照贴图像素数量相乘计算丛集的乘法器,当数值是1的时候丛集的数量就等于光照贴图像素的数量,因此低于1会比较好。丛集本质上是为了计算PRGI所产生类似静态场景的仿真体,所以只有在数量不足以反映物体的光照反射时才需要加大这个值。
和光照贴图解析很像,这两座山的丛集分辨率可以设很低,如果把它设的跟其他小场景一样的话,代表可能会需要几百个小场景的丛集量来覆盖这两座山。
- 对于很大的对象,丛集分辨率可以设很低
- 把Scene窗口左上方的绘制模式改为Clustering
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector界面里把ClusterResolution的值慢慢降低,彩色色块会慢慢变大,数量会慢慢变少
或是改用Lit Clustering绘制模式来评估设定的分辨率是否足以采样场景细节的光照。
- 把Scene窗口左上方的绘制模式改为LitClustering
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector接口里把ClusterResolution的值慢慢降低,观察场景的变化。
调整到这里时,可以问问自己是否能接受更低的丛集数值,如果继续调高对画质已经没有好处了,那就应该要往下修正。请记住丛集数量对于预计算的时间和GI有很大的影响,这个案例我们发现用0.4是很适合的值。
- 从Project窗口选择TutorialTerrainLow光照参数集
- 设定Cluster Resolution为0.4
LitClustering绘制模式可以用来评估场景里是否有足够的丛集
需多情况下只是单单降低光照和丛集的分辨率就足够提升很大的效能,但是我们还能用IrradianceBudget和Irradiance Quality做更进一步的改进.
首先我们先看看Irradiance Budget,如之前所提,这个值控制贴图像素会占用多少内存计算,为了执行时的效能,我们应该使用最低的值以免产生负面的影响。
如果预计算的结果模糊不清的话可以试着调大这个值,对于场景里有着高对比度度却没有被精确表达出来的区域是很有用的。
Irradiance场景绘制模式可以用来评估调整Irradiance Budget或Quality的值
两座山照明的频率没有很高,也没有任何高对比度的光照处理,代表在不影响质量的情况下,默认值128还能再低。
- 把Scene窗口左上方的绘制模式改为Irradiance
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector界面里把IrradianceBudget的值慢慢降低
- 你会看到当我们减少这里的值时,两座山上的照明会变得柔和一点
经过一些实验之后,我们发现将Irradiance Budget设定为64最好
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector界面里把IrradianceBudget的值设为64
现在来看看另外一个Irradiance Quality,像之前所说的,Irradiance Quality影响着当计算光照像速时从丛集所投射出来的射线数量,不像Irradiance Budget只会影响到预计算时间,这个设定会影响到Runtime执行效能。
我们的两座山是非常大的对象,代表不太容易错过邻近的丛集,因此我们可以透过降低IrradianceQuality来提升预计算的效能。
- 把Scene窗口左上方的绘制模式改为Irradiance
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector界面里把IrradianceQuality的值慢慢降低
- 随着值的下降,产生的光照贴图变得越来越模糊
我们发现2048是一个既可保持我们要的质量又能提升计算效能的平衡点,虽然准确对度会有点损失,但整体来看是利多于弊的。
- 从Project窗口选择TutorialTerrainLow光照参数集
- 从Inspector界面里把IrradianceQuality的值设为2048
把设定好的光照参数集指定给场景其他对象
现在我们可以帮LightingTutorialStart场景里剩余的静态对象建立并指定光照参数集。
我们之前讨论如果决定一个分类方法。基于特征(例如大小或是距离镜头的距离)将场景对象分组,以方便我们能更容易为对象指定光照参数集。
当我们在处理Environment对象底下其余的子对象时,请尽量帮能共享光照参数集的对象分同一类,例如:对象是否会很接近? 这样如果提高该对象的分辨率对于结果会明显的改善,如果是很远的对象你就不需要相同的设定值,如果物体材料无法反映材质的大量变化,高分辨率就没甚么好处。
分组不需要太细,对于大多数情况下,几组差异性大的设定就够了,分太细也不好管理,可能每个细节都要针对对象独立修改。
在我们完成的场景LightingTutorialOptimal里面,我们分组依据如下:
- RockLow:距离镜头有段距离的光滑石头,因为距离远所以分辨率低。
- RockMedium:光滑石头,更接进玩家区域,所以需要高一点分辨率和设定。
- StructuresHigh:需要高分辨率呈现的重要的建筑物,同时也需要更高的IrradianceBudget和Quality设定。
- StructuresLow:远距离的建筑物,只需要低分辨率设定。
- TerrainLow:大,遥远的网格,比如山
- TerrainPlayable:会很靠近镜头的大型地形,需要一个光照贴图分辨率来平衡,大的地形把丛集数量降低也还是很合理
- TerrainVeryLow:非常遥远和假的仿真地形,低分辨率和低丛集数量,IrradianceBudget和Quality也都很低
除了这些自定义参数之外,在完成的教学LightingTutorialOptimal里面,我们还放了一些使用预设光照参数的结构,这里我们用默认的Default-Medium。
使用场景中大多数静态对象默认的参数集可以减少很多手动的工作,将常用值指定为预设参数设定很有帮助,对于我们的目的,Default-Medium和默认1像素的分辨率搭配使用很适合。
Irradiance绘制模式用来评估场景照明非常有用,因为它只会显示对PRGI有贡献的静态对象光照结果。
当要决定你的光照设定决策时,可以用LightingTutorialOptimal来当作一个评估基础,将光照参数集指定给场景的对象不会花你太久的时间。记住,当你设定这些对象时,要不断的思考调高参数值所带来的好处有多少,如果调低带来的负面影响不多,那不管如何都是首选。