完全理解Unity预计算全局光照及其优化(二)

时间:2024-04-04 10:05:51
上一篇介绍了许多预计算全局光照涉及的概念,那么本篇就将介绍这些概念的具体的用途,以及相关的优化方法。实际使用中,预计算全局光如果不进行优化的话,往往会让编辑器耗费大量的时间,甚至长时间没有反应。那么对GI进行优化,加快其烘焙效率,同时也能对运行时的性能造成影响。

在Unity中,对预计算全局光照的设置分为两部分。一种是对整个场景进行的设置,通常就是我们在lightmap setting窗口中看到的相关的参数设置。 还有一部分是通过lightmap paramter对每个object进行的设置。

另外我想说明的是,对于有些内容我也许会以自己的理解来写,而不是按照文档以专业的术语来写,所以也许你会发现对照文档,我的内容可能会有不准确甚至错误,对于错误的还请指正,对于不准确的,我希望大家本着理解内容的心态,因为本文只是抛砖引玉帮助大家理解unity的文档,如果要说100%准确,那啃官方文档必然是最好的。

一。场景全局光照优化
(一)Realtime Resolution
上一篇已经介绍过Realtime Resolution的概念。当该值大于1时,在生成光照贴图时,世界空间中1单位就会在贴图中包含多个像素。而小于1时,就说明光照贴图的1像素包含了多个世界空间中的单位。物体的光照贴图包含的像素越多,对像素的光照着色计算量就越大。因为我们需要优化的话,就是减少每单位的像素量,或者说采用一个合理的值。比如在室内的小场景,但是具有复杂的光的反射环境,我们取2-3纹素。下面有一张表,可以作为经验参照
Scenario
Realtime Resolution
Indoor
2 - 3 texels per unit
Outdoor
0.5 - 1 texels per unit
Terrains
0.1 - 0.5 texels per unit

在unity中,我们的单位按照一定比率缩放,那么相应的,以上的经验数值也要等比的缩放。比如经验数值是1单位2-3个像素,如果我们导入的模型单位是原本的10倍单位,那么就需要对应20-30个像素。

合理的设置该值,可以适当的减少预计算的工作量和时间,同时也能获得不错的光照效果。

我们可以使用Realtime Resolution来对整个场景设定一个默认的纹素数量,然后通过对lightmap parameter中lightmap resolution设置值来,对每个物体来设置纹素数量。

(二)Chart
在unity中,物体最终的光照贴图占用多少像素,决定了预计算全局光照的计算量。同时,如我们前面说到的,占用多少像素是由Realtime Resolution和物体所选定的lightmap parameter中的lightmap resolution所决定的。而chart是unity计算像素光照的最小单位,一个chart最少需要4*4的像素。生成物体光照贴图时,unity会用一个个正方形的chart去覆盖shell的轮廓。然后对这些chart中的像素进行光照计算。

这里会遇到一个问题,假设Realtime Resoulution为0.5,此时2个世界空间单位对应一个像素,如果我们的物体是1单位。那么此时物体占用多少像素?此时物体也将占用一个最小的chart,4*4个像素(目前的unity似乎支持最小2*2像素了)。也就是说物体占用的像素,最终由chart的最小要求,Realtime Resolution和lightmap Resolution决定。而最少,物体会占用一个chart的像素。另外要注意的一点是,一个uv shell将对应一个uv chart,如果光照贴图中的uv shell越多,那么光照贴图的uv chart也会越多

Charts的数量决定预计算的时间。因此较少chart的数量,就可以做到对预计算光照的优化。Unity中并没有提供直接可以调整的chart数量的方法。那么想要优化chart数量的话,有以下几种方法
(1)通过调整Realtime Resolution和lightmap resolution的分辨率。分辨率降低,物体占用的像素也就减少,相应的,需要覆盖物体shell的chart就减少了。其实这还是基于调整分辨率的优化。
(2)通过勾选Mesh Renderer界面上的Min Chart Size,我们勾选4*4,或是2*2像素的。如下图

(3)如上图,也调整MeshRenderer中Max Distance和MaxAngle也可以有效减少相应的Chart。unity的自动拓展uv算法,会尽可能的合并uv shell。
          Max Distance会将距离小于该值的shell尝试合并,所以该值越小,不能合并的shell越多,chart也就越多。
          MaxAngle则是按Mesh表面的背面的内角计算的。该值越大,代表两个面的夹角越小,也就是越尖锐。增大该值,也就意味着更多夹角尖锐的shell可以被合并,chart就可以减少
(4)对于一些小物体,我们将它们排除出预计算全局光照的计算范围

(三)Cluster
Cluster的概念我们已经解释过,我们来看一下cluster是如何在unity的光照计算中起作用的。在预计算全局光照贴图时,unity是针对物体表面生成的cluster来简化光照计算的。cluster存储在一个层次结构中。cluster采样映射的物体表面的反射率,然后在预计算的光传输阶段,相关的cluster都会被计算,从而实现了光在cluster网络中的传播。

Unity用cluster代替物体表面是为了简化光照的计算量,改进在一个交互帧中用于模拟全局光对周围物体影响的计算。

完全理解Unity预计算全局光照及其优化(二)
看上图,我们就可以理解,cluster x的光照信息,是由A,B,C及黑色的cluster计算出来的。全局光照是一个迭代计算的过程,当第一次(第一个cluster)初始的光反射被计算后,它的光照结果将被更新用于其他cluster的光照计算(想象一下可以理解,全局光不就是场景中的各种物体互相作用的结果),每一次迭代都会将cluster的信息采样到对应的光照贴图,直到最后的输出。

不难理解,减少cluster的数量可以减少迭代,减少计算量。

我们可以设定lightmap parameter中的Cluster Resolution。这个值代表了光照贴图的一
个纹素对应多少个Cluster,也就是说1个纹素的颜色信息,由多少个cluster产生,增大该值,光照贴图上1纹素的信息就会需要更多的cluster的计算来生成。

完全理解Unity预计算全局光照及其优化(二)

上图中,我们将Realtime Resolution和lightmap Resolution设为1,cluster resolution设为2,改正方体为1单位的物体,可以看到在一个面的边上,对应了两个cluster,最终一个面4个cluster,并对应一个纹素

二。物体光照贴图参数lightmap parameter
Irradiance Budget
决定了光照贴图纹素在采样时的内存使用量,也就是决定了光照贴图采样的精度(浮点精度)。这个值同时会决定CPU的用量。减少该值,减少了内存用量,和CPU计算量,但也丢失了光照贴图精度

Irradiance Quality
预计算阶段,当光照贴图拓展了物体的uv后,每一个纹素将会像场景发射射线,来判断周围相关的cluster的可见性。该值决定了纹素发散的光线的数量。只有在光照结果不正确时,来调高该值,因为可能产生遮挡,或是发光的cluster没有被检测出,该值会影响计算时间,但不影响运行时计算时间

Backface Tolerance
指定一个使纹素有效的,来自几何体正面的光百分比。反弹自背面的光线是被认为无效。这会造成退化或事不正确的光照结果。改变该值不会影响预计算的时间,或是运行时的执行时间。但当Irradiance Budget调整无效时,这是一个可以调试调整的工具

Modeling Tolerance
增大该值会忽视掉一些小的物体。通过将间隙小于这个值的物体都无视调,从而不产生间隙,使光照贴图的采样避免在低分辨率时产生像素扩展到边界之外。会将小于光照贴图的纹素的该百分比的间隙忽略

完全理解Unity预计算全局光照及其优化(二)

在低分辨率时(高分辨率细节足够,不会出现问题),当物体和相对的面非常接近时,光照理论上是少量通过的。但因为在低分辨率,预计算可能会将该纹素扩展到遮挡物体的边界之外(低分辨率的采样失真,或事cluster再计算时从周围相关cluster进行的计算),从而产生不想要的暗部。

同样,该值不影响预计算或是运行时效率,并可以来解决一些不正常的阴影显示。

以上介绍了Unity中预计算全局光照的一些优化相关的参数。我想差不多应该都介绍清楚了。下一篇我想再对一些不是直接调整lightmap setting的优化方法,比如lighting probe和一些具体的优化的实战。来结束这个专题吧。