技术专区 \ Unity3D

Unity预计算即时GI (四)光照探测

Unity3D 预计算实实Gi Gi ⋅ 2017-05-16 13:33:50
预计算实时全局光照(PRGI)是优化场景的一种手段,我们曾经详细介绍过它的必要性,定义适合当前场景的光照分辨率,以及影响计算时间的光照图的概念。本文我们聊聊如何使用光照探针(Probe Lighting)来降低光照方案的复杂度,这种方法非常适用于场景中的小物体,一起来一探究竟吧!

何谓光照探测

光照探测是一种快速计算实时渲染应用中的光照技术,通常会用于处理游戏世界的人物角色或是动态物体的光照,它的优点在于运行时有不错的处理性能而且预计算也相当快速。

光照探测的原理是通过放置在3D空间里的探针来接收光照信息,然后用类似球谐函数(spherical harmonics)的数学方法将信息编码在一个球体上。这些系数占用空间很小,在游戏运行时能快速”解包",以便Shader可以存取并计算表面光照,在Unity中这个功能叫做光照探针(Light Probes)。它是一种让对象接收场景间接照明的好方法,虽然被光照探针指定的对象无法计算场景的光照反射,但通常影响不大。

使用光照探测是有些限制的,其中一个限制:在不提高探针数量的前提下很难在球形范围上表现出高频或斑驳的光照,并且其精度和消耗成本成正比。也就是说,在考虑性能的前提下,必须限制使用较低阶的球谐函数。

实际上,一个3D坐标只能用一个球体来记录光照信息,所以光照探测不适合用于有大量光照投射在大物体表面的情况,所以不得不提到另外一个限制:当用球谐函数在一个球体上进行编码时,通常不擅于处理拥有特大平面的物体或是带有很深的凹洞的物体。如果想要将光照探测技术用于大型物体,可以参考Unity手册中Unity提供的另一个光照探测代理体(Light Probe Proxy Volumes, LPPV)技术做进一步了解。

尽管有这些限制,光照探测还是很适用于和符合条件的小物体一起搭配使用,以较低的成本消耗发挥出卓越效果。 我们后续将深入探讨如何设置及摆放光照探针(Light Probes),现在只了解适当使用光照探测功能可以降低光照贴图的数量。

为对象设置光照探针

尽管我们一般将环境里的对象都设置为静态后再做光照计算,但其实整个环境里有很多对象都适合用光照探测技术进行处理。减少场景里光照图的数量是加快预计算时间的关键,将对象的静态标签清除之后,它们不再受到PRGI计算的影响的同时,光照贴图的数量也会降低。 

使用光照探测的最佳物体就是像这种凸起的小碎石

从Unity编辑器的层级视图(Hierarchy)看Environment下的子对象,会发现Props下的对象几乎都是点缀场景用的小物体,例如:石头、水桶或木板。 这些物体非常多,而且很多小物体的UV可能不太好展开。获取不失真的光照贴图UV可能会产生很多UV Shell,一旦UV Shell过多就会需要额外的光照图,更多的光照图代表将产生更多的贴图像素。

假设这些物体很小,不太可能对场景的间接照明产生什么影响,而且它们表面能显示的光照细节也有限,所以这样的物体非常适合用光照探测技术来计算,不但可以加速预计算时间,同时要存到内存中的光照图和Shader解码的数量也变少了,在运行时的性能也会因此提升。具体操作如下:​​​​​

  • 从层级视图(Hierarchy)选择Props对象

  • 在检视面板(Inspector)中取消勾选最右上角的Static

  • 在弹出的提示框中,选择"Yes, change children"

这时等待计算完成,就能看到场景最终的光照计算结果,你会发现被探测光影响的非静态物体(non-Static objects)和周围的物体有些格格不入,和场景的光照也不匹配。 这是因为我们还未设置光照探针(Light Probes),导致这些物体被纳入环境探针(Ambient Probe)的光照计算。 环境探针本质上是一个在场景里无法看到的隐形探测器,只对Lighting视图中的Ambient Source所指定的来源进行采样。

在没有光照探针影响下,非静态物体的位置可能看起来有些异样

为了让非静态物体的摆放位置更为合理,我们需要花点时间来将光照探针放置在场景的周围,方便对世界中的间接照明进行采样。

放置光照探针

非静态物体会通过附近的光照探针接收光照信息,光照探针会基于探针之间的空间划分四面体,然后检查物体属于哪个四面体来决定物体"读取"哪个探针。 为了正确地产生这些四面体,探针之间的位置关系在3D空间里就必须要放得有体积感。

画面中那些白色的球体就是光照探针在场景里的样子 

光照探测技术执行的消耗非常低,预计算也非常快。然而考虑到性能,也有些需要注意的地方:尽管设置简单,但密度太高的探针可能会浪费资源,因为太接近的探针在特定光照条件下的采样结果没什么差异。 最好的做法是在光照变化明显的区域放置密度较高的探针,例如由亮转暗的区域,或是强光反射的区域。设置光照探针的具体方法如下:

  • 从GameObject菜单新建一个光照探针群组(GameObject > Light > Light Probe Group)

  • 开始放置光照探针,从层级视图(Hierarchy)选择刚才新建的光照探针群组对象

  • 在检视面板(Inspector)中找到Light Probe Group组件,选择Edit Light Probes开始编辑

  • 可以从场景直接点选那些探针,留下角落的一个光照探针,其他可以全部删除

  • 将剩下的一个光照探针移到地形上方,然后按住Ctrl + D( Mac是按Cmd + D)键复制

  • 用移动工具(按W键)将复制的二号光照探针沿着Y轴往上约2米(2 meters)

  • 再复制一次光照探针,并将新光照探针的Y轴上移更高,约5米

Light Probe Group组件的Edit Light Probes按钮位置

这样的垂直光照探针分布为的是可以同时采样到地面、头部高度和天空的间接光照(Indirect Light)。 当我们开始将这组光照探针大量复制到场景其它位置来产生光照探测区域时,要确保可玩区域都会被探针所产生的四面体覆盖到,可以看到光照探针之间会以品红色的线串联表示这些区域。

光照探针的位置和它们之间所产生的四角面

  • 全选刚刚建立好的三个光照探针(按住Shift并点选每个光照探针或是拖拽进行框选)

  • 复制整个光照探针组并移到场景其它需要采样的地方

需要采样的地方不外乎是有阴影的区域或是地形材质色调会变化的地方。请记住,我们的目的是对场景里的间接或反射光照进行采样。 为了让每个光照探针的性能都用在刀刃上,尽量确保它们对一些光照变化明显的地方进行采样,如果光照探针放在一致性很高的光照区域,那光照探针反映给动态物体的结果不会太明显。 如同游戏优化的各方面技巧一样,尽量确保每个光照探针都有其存在的必要。

继续重复上述操作,在照明区域大密度地放置光照探针直到产生一个像笼子般的区域,涵盖所有的可玩区域。 布置这些光照探针时,请记得每一次都要检查最底部的光照探针要和地面保持一定的距离。

在我们的示例LightingTutorialOptimal场景中带有两组光照探针,VillageLightProbeGroup比较密集、用于村庄区域,ExtentsLightProbeGroup比较稀疏、用于村庄外无法到达的区域。 第二个光照探针组涵盖了整个游戏世界以防止任何非静态物体离开可玩区域,这一组不需要像村庄那组探针那么密集,垂直轴方向只要两个探针就够了。

将光照探针拆成两组,方便定义光照探针的用途,每个光照探针组都可以独立开启或关闭,方便适应场景的各种需求,这些光照探针在运行时会自动组合并执行重叠检查(de-duplication pass)以删除所有重叠的探针。

想看到光照探针的照明结果,必须等到预计算完成,如果勾选Lighting视图(Window > Lighting)下的Auto就会自动进行计算,如果未勾选,则需要按下旁边的Build按钮来手动计算。

一旦计算完成后,你会发现场景里面的非静态物体会开始接收光照探针的信息,看起来和场景光源会更匹配。如果要查看照明状态下的光照探针,可以从层级视图(Hierarchy)选择光照探针组。

现在场景里有了光照探针组,我们就能为场景中的小物体取得间接光照信息,而不需要从PRGI的流程中为这些物体生成额外的光照图。 

总结

本文我们通过对光照探针的定义、设置方法和放置技巧进行阐述,希望能为您带来处理光照的新思路。