干活!Unity 5 中的全局光照技术详解(一)

简介

全局光照,简称GI,是一个用来模拟光的互动和反弹等复杂行为的算法,要精确的仿真全局光照非常有挑战性,付出的代价也高,正因为如此,现代游戏会先一定程度的预先处理这些计算,而非游戏执行时实时运算。

同一场景里:没有照明(左),只有直接光源(中),和有间接光源的全局光照(右)的表现,注意颜色如何在不同的表面进行光的”反弹”,产生更真实的结果。

在本文中,我们会描述全局光照如何在Unity里运作,带领你通过不同的照明技术解释如何在项目里设定照明,并思考如何透过各种工具帮场景打光。

选择一个照明专案

广义的来说,Unity的全局光照是”实时”或是”预先计算好”的,在某些情况下两种方法可以结合使用,照出更逼真的场景。本节我们会针对两种技术的差异优势和使用时机做个简单的描述。

实时照明(REALTIME LIGHTING)

预设情况下,Unity的灯源(直接光源, 投射灯, 点光源)都是实时的,代表这些灯源会把光线照射到场景并以每一帧的频率更新,由于光源是可以在场景内移动的对象,场景灯光的更新是实时的,你可以在游戏窗口和场景窗口看到改变。

实时照明的影响:注意到因为没有反射光源的关系阴影是全黑的,只有投射光锥体范围内的对象表面才有光源影响。

实时照明是场景里照亮物体最基本的方法,用来照亮角色和会动的对象,可惜的是,Unity实时照明里的光线不会反射,因此我们才导入了全局光照系统,启用了预先计算的技术,都是为了表现一个更逼真的场景。

烘焙全局光照(BAKEDGI LIGHTING)

当烘焙一张光照贴图(Lightmap)时,场景内的静态对象会基于光的影响算出一张贴图成果,并迭在场景对象之上建立照明效果:

左:一个简单的光照贴图场景成果,右:由Unity产生的一张光照贴图(阴影和光源信息都被纳入计算)

这些”光照贴图”可以包含场景内投射到物体表面的直接光源,以及在不同物体间反射的”间接光源”,这样的光照贴图可以透过物体材质上的着色器(Shader)描述像是颜色的表面信息(Albedo)和凹凸(Normals)信息。

烘焙光照所产生出来的贴图,是无法在游戏运作的时候变更运算的,因此被定义为静态(Static),虽然仍可在这层贴图上继续迭加光源计算,但两者已无法交互运算,通常我们采用这光照法来让低阶的手机能顺利执行,解决光在游戏中运行的效能问题。

预计算全局光照(PRECOMPUTED REALTIME GI LIGHTING)

虽然传统的静态光照贴图无法在游戏执行时改变场景光照条件,但预先计算的实时全局光照系统能帮我们实时运算复杂的场景光源互动,透过这种方法,就能建立昏暗的环境带有丰富的全局光照反射,并实时反映光源的改变。好比做个日晷,阴影的位置和颜色会随着光源移动改变,这在原本的烘焙光照系统是无法达成的。

 一个用GI呈现的日晷案例

一个用GI呈现的日晷案例

为了在合理的帧率实现这些效果,我们需要在实时运算之前先将一堆垄长的数字数据做”预计算”,预计算负责计算游戏过程中光的复杂行为,它可以在时间空档时进行计算,我们称作一个”脱机”运算。

如何运作?

最常见的需求是我们希望间接光源能够列入场景光照贴图的计算,幸好,原理上这些间接光源都是从直接光源慢慢转变过来的颜色,只有少部分特定情况有比较大幅度的颜色改变,这样的Unity的全局光照预计算,利用间接光源漫反射(diffuse)特性对运算有利。通常好的阴影是透过即时光源所计算出来的,而非烘焙到光照贴图,假定我们并不需要太复杂的细节取样,可以大大降低全局光照所产生的数据大小。

透过预计算来简化整个流程,有效的降低了原本要在游戏中实时计算的全局光照运算数量,如果你要常在游戏中改变光源颜色,旋转光源或是调整光的强度,甚至对场景表面做变更,这点就很重要。Unity从表面上采样底层贴图,并从广义定义颜色的值到一个大型的群组,或是”丛集”,这会产生一个低解析的仿真静态几何,以方便我们用来计算光照。

左:场景显示设置为”Albedo”时,可以清楚看到由Unity预计算所产生的纹理;右:如同游戏的场景一样,即时光照计算完结果后套用到场景。

基本上,当在计算全局光照时,我们会针对静态场景周围做”光迹追踪”运算,这是非常耗效能的,因此无法苛求要实时运算,相反的,Unity把光迹追踪用在计算这些表面的丛集关系 - 在预计算”光传输”的阶段,然后把世界串成一个网络结构,我们在关键性的游戏过程就不再需要耗费效能的光迹追踪法。

我们有效的创造出一个简化的算法可以在游戏过程中变化输入结构,这代表我们可以改变光源或是表面颜色,并很快的看到场景内全局光照的影响,算出的结果产出光照贴图透过GPU着色,并和其他照明或是表面混合,最后输出到屏幕上。

收益和成本(BENEFITS AND COSTS)

虽然可以同时使用烘焙方式的GI和预计算的GI,但要注意是同时仿真两个系统,效能负担也会两次运算的总和,不只是因为要储存两套光照贴图在显卡内存,同时着色器也得付出两次的处理成本。

最终要选择哪个方法还是要取决于你项目的性质和预期的硬件考虑,例如在手机平台上,效能和内存限制较高,烘焙的GI法就会比较适合,如果是在有显卡的计算机上或是游戏机上执行,那可能使用预计算实时全局光照,或两个同时使用就比较可行。决定采用哪一种方法可以针对你的目标平台评估,记得如果项目要同时符合几个不同的硬件需求,往往都是以效能最高的平台为考虑。

预先计算的过程(THE PRECOMPUTE PROCESS)

在Unity里,预计算是在背景执行,不管是自动流程或是手动启用,计算期间你都可以继续编辑你的游戏对象而不受影响,预计算的时候会在右下角出现一个进度条,不同的算法会有不同的运算阶段,进度条上方也会显示阶段名称与进度。

从上面的例子可以看出,11个工作已经进展到第5个,”丛集”还有108件工作要执行完才会到第6个会话,数值状态栏表如下:

启用一个预计算(STARTING A PRECOMPUTE)

只有静态对象会被纳入GI预计算,要让预计算启动首先必须最少要有一个静态对象,不管是单独设定对象或是从层级选单用Shift + 选择多个对象后一次修改。

从属性面板,将对象的Static勾选起来,这会将该物体所有跟静态对象相关的旗标打开,包含导航旗标或是批处理旗标,这或许不是你想要的,针对预计算只要把”Lighting Static”这个旗标打勾即可。更细部的控制,只要点选属性接口Static右边的下拉式选单即可,此外,从Window里的Lighting接口也能指定设定静态对象。

如果你的场景设为自动(Lighting->Scene->Auto),Unity的预计算就会自动启动,否则就需要用下列的流程手动执行。

自动/手动预计算(AUTO/MANUALPRECOMPUTE)

假如Lighting接口底下Auto这个选项是被勾选的(Lighting->Scene->Auto),那么预计算就会自动在背景不停的改变场景产出的静态几何。但如果这个勾选没勾,你将需要点击在Auto旁边的”Build”按钮手动启动预计算,这会用同样的方式进行预计算,让你比较好控制计算的开始时间。手动启动预计算会对场景所有的照明与各方面进行重新评估并重新计算,如果你希望有选择性的计算,可以从”Build”旁边的下拉选单来选择。

使用烘焙GI或是预计算GI(ENABLINGBAKED GI OR PRECOMPUTED REALTIME GI)

预设情况下,两种计算法在Unity里都是启用状态(Lighting->Scene),因为如此,你可以针对单独的光源设定要采用哪种计算法(Inspector->Light->Baking)

在一个场景同时采用两种方法可能会对效能造成负担,最好的做法在同一个时间只用一种方法,要关闭任何一种方法可以从GI的接口(Lighting->Scene),把不要用的方法取消打勾即可,只有有打勾的算法会计算,任何相关光的设定都会被覆盖。

预灯光设定(PRE-LIGHTSETTINGS)

Unity里每盏灯光默认的烘焙模式都是”Realtime”,这代表这些灯光仍然会照亮你的场景,Unity的预计算GI系统会处理间接光。但如果默认的烘焙模式是”Baked”,那么这些灯光将会透过Unity的烘焙GI系统处理直接光源和间接光源,产生出来的光照贴图一旦贴到场景上在执行期间是不能改变的。

一个设定烘焙模式为”Realtime”的点光源

一个设定烘焙模式为”Realtime”的点光源

选择烘焙模式为”Mixed”的话,场景内的静态对象会被烘焙GI拿去做计算,然而,不像”Baked”模式,混合模式的灯光仍会继续运算即时光源到非静态对象上,这对于你想把静态环境烘成光照贴图,但同时又希望同样一盏灯能为会动的角色计算阴影很有帮助。

GI快取(GI CACHE)

无论是烘焙还是预计算系统,Unity会”缓存”场景的光照数据到”GI快取”,并会在计算时尝试重复运用这些数据来节省时间,你对场景的改变会影响这个数据重复利用的多寡。

如果你要清除这个快取可以从(Preference->GICache->Clear Cache)来清除,清除后代表所有数据都必须重新运算,因次会花费一些时间,在某些情况下你也许需要降低档案空间大小(例如要把项目转到另外一台计算机)是有帮助的。

场景设定(SCENESETUP)

选择着色路径(CHOOSING A RENDERING PATH)

Unity支持许多著色技术或”路径”,在启动一个项目时,必须要订出出一个路线,Unity预设是”Forward Rendering”。在”ForwardRendering”里,每个对象著色是根据每个影响对象的光,透过”Pass”来著色,所以有可能一个对象被重复著色了好几次,取决于有几盏灯在作用范围里。

这种方法的优点是快速,也代表硬件需求低,此外,这种正向著色提供了广泛的自定义”着色模型”,可以快速处理透明度,也支持像是多重采样柔边(MSAA)的硬件功能,等等有些在其他路径上是无法实现的功能,对于图形质量有很大的影响。

然而他的缺点是要为每盏灯光付出相对应的成本,也就是说,对象被越多盏灯光影响,花费的运算成本就越高,有些类型的游戏必需要大量的光源,就会令人望之却步,反观如果你能管理好你的灯光数量,那这个路径会是一个非常快速的解决方案。

“Deferred”路径,是延迟了光的遮蔽与混合信息直到第一次接收到的表面的位置 法线 以及材质数据著色到一个”几何缓冲器”(G-buffer)作为一个屏幕空间的贴图,最后合成这些结果,这种方法优点是照明的著色成本是和像素数量成正比,而非灯光数量,因此你不用再管控场景灯光数量,某些游戏类型将会是一个关键优势。

“Deferred”路径呈现可预见的效能特点,但通常需要较强大的硬件,对于手机平台支持度也较低。


关于”Deferred”,”Forward”或是其他路径的更多信息,可以参阅这里

未完待续!

来源:cocoachina

--电子创新网--
粤ICP备12070055号