GDC2016 【全境封锁】的全局照明技术
GDC2016 UBISoft Nikolay Stefannov : Global Illumination in 'Tom Clancy's The Division'
翻译 TraceYang 校对 Qiankanglai
负责演讲的是UBI Massive工作室的技术主管Nikolay Stefannov
在家用机和PC游戏的世界,GI早以变得习以为常,在品质,效率,制作方面也越来越讲究,加上现在RPG开始把开放世界和昼夜天候变换作为必须的要素,GI在这方面的支持也成为了了一个课题,这次介绍的是在线射击RPG游戏【全境封锁】中,是如何通过改进传统的PRT和Light Probe技术,来制作出次世代级别的光影效果。
【全境封锁】GI的技术方向
首先,Stefannov【全境封锁】的GI技术做了简单的概述,本游戏是UBI的瑞典工作室UBI Massive使用最新自研引擎【雪莲花(Massive Drop)】开发的一款开放世界的在线RPG射击游戏。为了可以在PC和Console身上得到的尽可能精确的例如场景中太阳光和天空中的点光和区域光的光照反弹(light bounce)产生的间接照明等动态环境光的全局照明效果。因为以往的那些烘培光照贴图的技术并不适用于全动态的光照环境,【全境封锁】在GI上选择了相对更快速,计算成本更低,占用内存更少,并且适合在GPU上运行的比较传统的预计算光能传递Probe技术(PRT Probes : Precomputed Radiance Transfer )。
在美术制作的要求方面,因为是整个游戏场景是开放世界无缝衔接的,需要这种技术室内室外可以同时支持,并且要防止光照不会透过建筑物的墙壁在室内产生渗出现象(light bleed),而美术也可以随时的修改光源,并把新的结果立刻反馈到游戏场景。
全境封锁的GI使用的是PRT Probe
室内外是相同技术并支持实时编辑
然后,是室外和室内打开和关闭PRT后画面效果的对比,上面的图是使用了PRT Probes的正常渲染,而下面的图关闭了环境光并把他替换成了纯黑色。可以清楚的看到PRT Probes贡献的效果。
室外PRT效果的对比
室内PRT效果的对比
技术简介
整个技术分享分为四个部分,首先是从高层次上对【全境封锁】的GI方法的特性做一个预览,然后是如何制作生成PRT,第3个部分是如何在运行时使用GPU渲染,最后介绍的是使用这种技术在生产中遇到的一些问题。
开放世界(Open World)特性的要求
前面也有提到,【全境封锁】有着“开放世界”的特性,玩家的游戏场所是在美国纽约曼哈顿(Manhattan),大概有6平方公里的广阔区域内,里面有近200万个场景实体,并通过美术师手动摆放了22000个以上的车辆载具,以及28000个垃圾堆。游戏世界的尺寸,以及物体对象的数量,使得传统方法例如Llightmap并不能适用,为了控制成本,不得不使用基于Probe的方法。这种Probe或Irradiance Volume的方法,有些类似3D Texture,并不是通过UV来索引,而是用位置和法线信息来确定渲染效果。这种技术的最大优点就是,美术师不需要考虑如何展开UV,也不用担心改变了物体的位置,就要重新烘培光照的问题。
玩家可以在曼哈顿整个的区域内自由移动,除了快速旅行外,游戏世界在移动时都是无缝的
昼夜循环(Day-Night Cycle) / 室内光照( Interior Lighting)
此外,【全境封锁】的特性还有昼夜循环系统(Day-Night Cycle),Stefannov他们认为环境光的品质对于游戏来说是非常重要的,通过在美术师设置太阳光方向上的限制,让环境看起来尽可能的好。同时由于纽约有很一些高层的建筑,一些区域是一直处于阴影之中,只能受环境光的影像。美术师要调整每个时间的光照效果,而不需要长时间的重新的烘培处理就可以立即精确的显示出GI的效果。
而在晚上,主要的光源是靠放置在场景里的点光(Point),聚光灯(Spot)以及区域光(Area Light),UBI以前的游戏Far Cry中使用的技术,是把光照的二次反射(Secondary Bounce)烘培到Probe里,但【全境封锁】需要动态的移动和编辑光源,并且不需要重新烘培,在自由的删除和修改光源后,立刻把夜晚的结果正确反馈给美术师。
白天的环境光,需要限制太阳的方向,每个时间的光照都需要细致的调整
夜晚依靠各种放置在场景里各种光源照明,每个光源都可以是动态的。
【全境封锁】的室内光照( Interior Lighting)特性方面,游戏的室内面积通常非常大,而且密布了各种道具。为了获取正确的光照,这里没有使用以前那种负值的光源(Negative Light)Trick,同时也避免用造假方式来提升环境光照等级,而是使用同样的PRT Probe,在室内获得较好的外观。因为很多室内环境会有打开的窗户或缺口,这样就会受到室外昼夜循环的影响,也需要室内外使用相同的基于Probe方法来适应。还需要特别注意的是不同房间之间光的渗入现象(light bleeding)。
室内的光照和室外使用了相同的技术
动态天气(Dynamic Weather)
【全境封锁】里也提供了不同的天气环境,有晴天,多云,降雪,暴风雪等等,游戏中天气的实际是通过运行在服务器端的脚本来控制的,每种天气都有自己的光源的预设,美术师可以调整例如阳光,天空的颜色,云的类型,雾的密度等等。另外有意思的一点是,天气的预设也决定了雪在不同平面是如何堆积起来的。当雪花在场景堆积起来的时候,我们需要替换BRDF也就是对应的Shader,完全关闭GI就会有问题,通过这种PRT的方法,只需要简单的共享指令,就可以用最小的成本来实现效果。
天气预设里有各种环境的参数,以及程序化的雪的堆积。
在下面的视频里展示了,所有内容适配到一起的效果。场景里的白色球体是用来计算光照的PRT Probe,在视频里,可以看到当太阳在天空中移动时,透过街道和建筑物的光照反弹的环境光的变化,以及不同的天气环境下的效果。到了夜晚,受到街灯的光照影像,也展示了体积雾是如何受到这个处理影响的。
PRT预计算的光能传递
接下来要讲解的是雪莲花引擎中使用的PRT技术,PRT是一种在某个固定场景中计算光在表面之间如何传递的渲染技术,就像以前在Far Cry那样,我们可以把顶点(Vertex)的PRT保存在Texture或Probe里。对PRT有兴趣的可以看下SIGGRAPH 2005上的论文由于PRT通常只能支持HDR环境贴图或者方向光那类有距离的光源。虽然也有支持动态区域光的方法,但消耗过于昂贵又不准确。下图右下里的基于小波的方法(Ren Ng et al. “Thttp://www0.cs.ucl.ac.uk/staff/j.kautz/PRTCourse/
riple Product Wavelet Integrals for All-Frquency Relighting.” SIGGRAPH 2004)虽然可以获得清晰的阴影和反射,但并不适用于GPU。
PRT也有很多限制
因为上面所说的限制,在【全境封锁】中,Stefannov他们放弃像以前的Paper那样寻找更优雅的方法,而是选择了蛮力的方式。把每个Probe所有的可见Surfel保存到显式列表里,每个Surfel元素里,包含了位置,法线,颜色,以及其他一些信息(比如雪的堆积系数)。这个方法就好像每个局部的Probe都有一个Gbuffer cubemap。
Probe使用Gbuffer cubemap的简单粗暴的方法。
通过下面调试窗口的截图,从Probe绘制绿线到场景中的Surfel,可以看出很像是Gbuffer cubemap。也可以看到从Probe投出了很多的射线,并保存射线碰到第一个的Surfel的信息
Sky Visibility / Transfer Basis
上面图例中,从Probe投射的绿线,并不是所有的线会击中到几何体上,那些没有击中的线,我们就把那里假设为是天空可见的(Sky Visibilty),通过这个来设置每个Probe的Spherical Shadow term的值,这个方法有些类似远距离的AO。下图幻灯片的右边,上面图是只有SSAO的效果,下面图是使用了预计算的Sky Visibilty和SSAO效果,可以看到火车隧道和一些建筑的也有了遮挡的效果。
使用Sky visibility来模拟大范围的AO效果
在使用Probe时,并不能用特定法线来预计算光能传递,必须为整个球体来计算,在以前的Farcry系列中,是通过传递基底(Transfer basis)实现的。下面幻灯片中左上的图是HDR Lightprobe(Grace Cathedral 格雷斯大教堂)。右上的图,是余弦卷积(cosine convolution),可以用特定的Probe对漫反射表面进行光照。为了可以用更少的数量来表示光源,需要对Light Probe使用余弦卷积来压缩,这里有几种方法。
其中一种标准的方法是用特定传递基底的系数来表示,幻灯片中下面的两个图是两种最通用PRT Transfer basis的比较。 左下的是2nd Order Spherical Harmonics(球谐),通过方向值来获得光照,这种方法的问题在于,当有两个来自相反的方向的很强的光源时,只会提高光照值,却不能识别出方向,而优点是非常适合在GPU上运行,因为只需要保存4个浮点数就可以了。右下图,是半条命2(Half-Life2)中使用的ambient cube,它只使用了6个轴向的factor,我们计算每个factor接受了多少光照就可以了,只需要在6个不同的法线方向计算余弦卷积。而它的问题是,当你旋转光源时,会有从一方向上产生淡入或淡出的效果,并不能平滑的混合。
右上是cosine Convolution,左下是2nd Order SH,右下是HL2的Ambient Cube
在评估了上面的几种方法后,Stefannov选择了HL2的transfer basis这种只需要6个浮点数的非常友好的方法。只用计算6个法线,在运行时对这六个向量做一次混合就可以了。下面幻灯片的图是每个特定方向分开的排列,从左到右,从前到后的顺序,来显示6个不同的值是如何正确配置的。
特定方向的分开排列
Probe Placement / Sector Layout
为了可以生成光能传递,首先要解决的是在世界场景中摆放Probe的方法,这里以自动化方法为主。首先,是使用一组Raycast grid,这个Raycast grid是长度为4m的正方形格子,从上往下发射射线,击中物体的时候就生成一个probe...在击中点往回移动一点距离,这样就避免和物体重合。另外还有就是沿着建筑物的墙壁自动的生成Probe,这样可以产生更加光滑的渐变效果,避免墙壁看起来太过单调。虽然这些都受到Sky Visibility的影响,但这样可以让底角的Probe变得更暗。
使用多种方式来自动的生成和放置Probe
这些数据是如何保存到硬盘上的?这里要把Probe划分到不同的Sector Grid里,Sector是一个64x64米大小的2D网格,最大可以容纳1000个Probe,通常一个sector里会有200~300个Probe,Sector里最多的有960个Probe。这里把所有的Probe简单的存放在数组里,也可以使用像边界体层级的方式来分类。 在运行时,最小时有3个Sector,处在玩家移动周围位置,最多是有25个Sector同时加载。
通过Sector方便加载
Surfel Sharing / Surfel Grid
接下来,如果要在一帧中对所有的Probe重新计算光照的话,那么速度就太慢了,所以需要寻找出一些优化的方法,让每帧中GPU尽可能少的工作。要做到这点,首先要让在相同Sector里的所有Probe共享surfel数据,用这种方法,只需要relight所有的Surfel各一次,Probe就可以实际的反应结果,不需要重复的工作。
下面幻灯片的右图中显示了实际的工作内容,Probe引用了相同Surfel。同时为了减少GPU上关联的surfel的数量,可以选择使用比较成熟的Cluster算法。由于时间有限,Stefannov他们仅仅使用了非常简单的hash grid。
通过让Probe共享Surfel数据,降低计算消费。
下面的幻灯片里,显示了Surfel hash grid的一些实现细节。这里使用了2个grid level,第1个level中,在每个Grid中的每个的Cell里把surfel的位置,法线,颜色等信息计算平均值,并通过Surfel的位置和主要的法线方向作为Grid里的Index,这样做的目的,是避免把相反方向的surfel取了平均。因为Cell的大小决定了在运行时需要光照计算的工作量,这个大小的设定需要非常的注意,因为只是用粗糙的Grid做的简单评估,像使用狭窄的聚光灯时就会出现问题。最后Stefannov他们发现,1立方米的大小是平衡性能和质量的最佳选择。
第1层grid level的示意图
在第2个grid level中,是把在一个irradiance brick里的surfel做平均,这种优化方法也是为了减少Probe的总体工作量,如果每个probe引用surfel,而不是引用Brick的话,每个Probe就要做大量无用的工作。同样这里也要注意,如果Brick的尺寸过大的话,也会影响性能。4立方米的Cube对游戏来说是一个比较好的配置。
第2层grid level的示意图
我们整体来看下实际存储的情况。每个Sector里,都有一个像下面幻灯片中左图那样的Probe数组,每个Probe有它自己的位置信息,以及关于Sky Visibility的HL2的Ambient Cube系数,这里只保存每个Probe的6个方向的Sky Visibitly,还有就是一组Brick factor的索引范围(用两个索引值来表示)。通过Brick factor,可以查找到有每个Probe在irradiance brick里受到多少光照影响。
Probe Array和 Brick Factor Array
每个Brick Factor里有他的HL2 Ambient Cube系数(6个浮点值)以及Brick Index,通过索引,在irradiance brick的数组里,保存的是Surfel的索引范围(用两个索引值来表示)。
Irradiance Bricks Array
通过索引,在从Surfel数组里找到和Probe相关的Surfel数据,包含了位置,法线和颜色,以及一些其他的信息。
Surfel Data Array
Baking Process
为了生成上面所提的这些信息,需要离线的进行Bake的处理。首先是为每个Sector里的所有Probe烘培Gbuffer cubemap,然后把信息从GPU读回到CPU,当所有的Gbuffer Cubemap渲染玩后,通过上面提到的Cluster算法,保存到hash grid,并计算Surfel数据在irradiance brick中的平均值(这里其实是两步,一方面算surfel里的平均值(第一层),然后在brick算surfel平均(第二层))。当在CPU中进行这些计算处理的时候,可以利用空闲的GPU来渲染队列中其他的Sector,每个Sector的处理大概需要5到6秒的时间,具体时间还是要根据它所处世界的Probe和几何体的数量来决定。
整个曼哈顿区的数据大概有1个GB,接近4000个Sector,100万个以上的Probe,以及5600万个surfel。这些所有数据的离线生成,大概需要8个小时的时间,灯光师不需要手动处理这些,只需要设置一次,每天晚上会自动的跑一遍最新的数据。
整个bake处理的参数
渲染
接下来是【全境封锁】在渲染在每帧中处理的细节介绍,首先是Relight Surfel的部分,要计算每个Surfel上的光照,并平均到brick里。然后是Relight probe,计算来自天空的光照,并加入到每个Brick和sky irradiance里。最后的Shading部分,是把所有的内容生成为一个Irradiance volume,它就是一个普通的Texture Volume,包含了6个方向的RGB颜色,使用它来进行最后的着色。
从高层次总览渲染流程
Relighting
那么每一帧开始,都需要计算因为加入了新的光照环境而改变的Probe的PRT,并获得Probe的Irradiance 。但并不是不同 Irradiance的probe之间的简单混合,需要可以在特定时间有非常精确的光照,这种GI效果因为维持时间很短所以很难捕捉到。
下面的幻灯片就是这种效果的示例,左边的图里,有很强烈的橘黄色光照反弹的效果,这个光照是直接由太阳光产生的,因为一天中只有几分钟是这种效果,如果你使用的是那种标准的为每天的特定时间来计算PRT的方法的话,那么需要很高的数据密度或足够幸运才能获得这个时间的效果。这个时候,因为油布在阴影里,所以墙壁的主要照明是靠阳光产生的,同时也包括街道上光的反弹照射。
特定时间光照效果的对比
实际的处理也非常的简单,这里使用了程序员容易理解的伪码来进行描述,
整个渲染的伪代码
首先计算的是每个brick的radiance,通过个brick里的surfel,我们计算每个surfel的光照并加入到brick的radiance里,最后得到这个brick的radiance的平均值。而里面计算光照的函数也没什么特殊的,就像是延迟着色函数那样,输入位置,法线,颜色值(Albedo)就能得到光照结果。
蓝色Relight部分的伪码
下面的幻灯片,是太阳光照射到阴影中的效果。和以前在Far Cry3里使用的PRT方法中,把阴影系数通过每个Probe的球谐系数来近似的相比,新的方法得到了更加精确的结果。下面图例的对比中,光照的方向根据时间有了变化。右边中是太阳光的Irradiance,随着时间动态的变化着。因为不是很好捕捉PRT,需要通过采样很高密度的不同Probe set来计算特定时间的结果,
Sun Shadow / Local Lights Irradiance
另外需要注意的,就是太阳所生成的动态阴影,它并不能覆盖到所有的surfel,而是跟随着玩家移动的。那么在视截体外的surfel就无法获得有效的阴影采样结果。除非全部进入阴影,否则就会得到不一致的结果。如果要覆盖虽有的surfel,效果过于昂贵,这里对surfel做了追踪判断他的历史是否是有效的阴影采样,并使用最后可知的值,可以这样使用的关键,是因为天阳光的方向并没有非常快的变化。
对太阳阴影的有效采样进行持续的跟踪,并使用最近的结果。
PRT上另外的一个改进,就是可以很容易的融入局部光源(Point,Spot,Area light)。这需要在CPU上做一些额外的工作,用来计算出哪个光源与surfel的AABB边界盒相交了,再把这个属性保存到GPU的constant buffer,为了优化操作,还把一些不会改变或闪烁的静态光源用Mask标记出来,在计算前把这些光源分离出来。这样就可以支持更多的光源了。
下面的视频中展示了一盏动态的亮度非常高的聚光灯(spot light)移动的同时直射到墙面,墙面是由多种颜色的tile构造的,Probe捕捉到Tile上光反弹的信息,生成次级照明,作出了多种颜色的效果。
Procedural Snow / Multiple Bounces
在会议一开始时有提到,天气的预设定义里有雪在不同的Surfel上如何堆积的参数。通过brick中获取的天气的预设值,可以知道雪的大小,然后用区域surfel的原始颜色与纯白色做混合。右图就是效果的对比。
左边是关闭效果的结果,虽然结果也是正确的但比较灰暗,右边受到底部白色的影响更明显。这样的处理不但效果好而且也不怎么消耗性能。
打开和关闭PRT雪的效果对比
听过上面的解说,可能会指出,只使用PRT预计算了一次反弹,为了可以模拟更多次的反弹效果,有个程序员提出了一种非常好的方法,只需要从前一帧计算Irradiance,在光照时读回到当前的surfel(feedback loop),为每个Surfel保存最接近的probe,作为环境光系数使用,这种方法可以捕捉来自光照,天空以及地面的反弹信息。在下面幻灯片中底下的那张图里可以看出效果。
多次反弹也有方法支持
下面的幻灯片是更加接近的效果对比,左边的图只用了一次反弹,看起来更加的暗一些,如果打开多次反弹效果,可以看到更加正确的照明效果。
单次反弹和多次反弹的对比
下面幻灯片是室外环境的对比,使用多次反弹的整体更亮,light probe的照明让物体的底部也更加明显。
室外环境的对比
室内环境的对比效果,左边使用一次反弹的效果并不明显,右边有probe的地方有少许的差别,会更亮一些但并不明显。
室内环境的对比
在Relight birck的radiance后,接下来是Relight每个probe,需要计算天空的Irradiance,这个处理非常地简单,渲染整个天空到一个非常小的Texture上,然后计算余弦卷积,并保存为HL2 Ambient cube的基底系数,然后再乘以保存在probe里的sky visibility。
第二部分处理是Relight probe
这里把天空绘制为非常小的Texture的主要原因,是因为【全境封锁】的天空盒是很多很难清晰的解释技术混合而成的。这里准备了6个点光照明的cloud texture,这样能够使得我们根据太阳的位置不同,照亮不同的cloud texture来模拟这个效果,右上的没有任何的云彩,Probe捕捉的是蓝色的环境,右下面的图有很多乌云覆盖,比蓝色更灰暗一些。
下面的幻灯片是另外一组对比,使用了相同的云和相同的基础颜色,只是移动太阳看起来像日出或日落的效果。这时,云的颜色变成橘黄色, 而下面白天的云是白色的。
相同云的场景下不同时间的对比
在计算完sky irradiance后,最后要处理的就是来自brick的Irradiance,并生成最后的结果
Performance
在讨论完上面实现的方案后,或许都很关心这个方案的性能。游戏中,每帧只Relight两个sector,一个 是玩家所在的sector。因为要relight surfel,brick以及probe,所以在PC或Console上,我们在GPU 渲染Gbuffer时,在CPU上同步的进行处理。XBox one这里将近1ms的时间是将Compute Shading放到同步下计算统计出来的,同步和非同步的性能应该是差不多的。家用机是60%处理brick和surfel的光照,40%用来处理Probe的,PC上是各50%
这个方案在不同平台的性能对比。
Irradiance Volume / Interior Volume
当运行完Relighting compute shader后,就是要把所有的Irradiance数据放入到一个volume map里,这样做的目的是通过trilinear filtering,以支持大的物体对象或者小的物体。这个volume map会跟随玩家相机,并使用每个方向32x16x32的voxel,覆盖玩家周围100x50x100米的范围。这里使用的是一张单独保存了6个方向的数据纹理,shader计算时通过偏移值来指定出要读取的数据。这个volume map可以在Deferred(延迟) Lighting Pass和Forward(前向)Lighting Pass中使用,并在不透明物体,透明物体以及粒子之间保持一致。
把所有结果保存在Irradiance volume中
不过,100x50x100米范围相对应低精度的volume map,会产生漏光现象(probe leaking), 这是因为从trilinear filiter读取到错误的数据。那么像建筑物的墙壁那样薄的表面(thin surface)上就会产生出光渗出的效果。在下面幻灯片右上的图里可以看出,室外的Probe受到了天空照明的影响,但室内的照明就错误了,得到了不正确的环境。为了能修正这个问题,这里室内和室外分别使用了单独的volume texture。 对特殊的模型,可以知道门入口的位置,我们override Stencil buffer。然后在Deffred Lighting Pass中, 我们可以读回这个Stencil的值,来指出是从室内还室外的volume texture获取数据。
另外,游戏中还要尽力防止光照从不同房间之间的墙壁里渗出,这里的方法是房间大小用AABB包围盒来制定,然后对应到volume space里去。当然,只有房间中有接近玩家的光是才会起作用。下面幻灯片的右下可以看到最后的效果,从入口到楼梯有更正确的天空蓝色的反弹效果,看起来也更加的自然。
室内外使用不同的volume texture
Distant Shading/Ambient Occlusion
室外的irradiance volume是保存在一张很大的2D Texture上,但要覆盖整个游戏世界,Texture里的每个Texel就要表示一个“sector probe”。从环境中很高的位置来计算配置的Probe。这里并没有做大量的反弹,只是计算了来自天空的Irradiance。
室外的Irradiance
通过下面的幻灯片中左右图的比较,可以看出不同的着色。左边的图是完全关闭Distant Shading的效果,所以街道远处的建筑物变成了全黑色。而右图是打开的效果,可以看到在volume map和后面的Texture有着并不太明显的混合效果,看起来效果更好。
打开和关闭Distant Shading的对比
很多人都会把Ambient occlusion作为间接光照的Shadow term来使用。【全境封锁】中的AO的来源有以下几个:SSAO,Bake在模型,材质,以及贴图里,以及前面提到的Probe sky visibility。使用时,把AO保存在Gbuffer的单独通道里。AO只作用在sky term上,做来自brick的二次反弹的时候就不用算shadow term了。在项目中也发现,车底下效果比较难做。于是使用了屏幕空间的贴花技术(Screen space decal)来Fake AO的方法。
下面幻灯片中可以对比使用AO Decal前后的不同,上面的图是关闭AO Decal的效果,汽车和街道之间看起来是连在一起了,而下面的图可以看到地面上的阴影,就分开了。
使用多种方式来实现AO效果。
AO Decal的实现方法也非常的简单,把Texture box放置在车辆的下面。从下面的截图中可以看到,这个车辆并不是一个简单的模型,有他的节点图表以及很多可以调整的属性。当然也可以用一个不可见的box作为附加的图元,并贴上一个简单的渐变Texture,然后把这个Texture输出到Gbuffer的AO通道上,虽然方法简单,但效果出奇的好。
使用Texture box来实现AO Decal
Volumetric Lighting
我们也可以在volumetric中使用PRT Probe。这里对volumetric使用ray marching来采样光照环境,来模拟空气中介质的散射效果。对于阳光和局部光源,我们同样从他们的probe采样环境光,为了优化操作,我们保存在不同的volume map的六个轴方向的Probe Irradiance的irradiance的平均值,储存到到一个RGB的 volume map里,用来在Raymarchi是做实际的采样以及Trilinear Filtering。这种方法是有效的,因为算散射的时候本来就要求平均。
Post Mortem
然后是本次分享最后的部分,这里讨论的是Stefannov他们在使用这种方法生产时所遇到的问题。
Initial Approach
雪莲花引擎最初是和很多其他游戏一样使用的Irradiance Volume,但通过修改,改为离线的方法为Probe来bake surfel,把cubemap改成运行时渲染,通过把预计算内容保存在硬盘,当你在游戏里走动的时候,cubemap实时生成然后保存到cache里。这种方法非常优秀,但也有一个缺点,就是更新交互的速度并不够快。所以有时你会看到一个特定区域的可见的灯泡是黑色的,但我们渲染这个probe突然就变亮了。还有就是日夜循环上,不能很快的切换到想要的时间,也就是不适合快速的动态光。
这种方法的一些缺点
Transfer Basis / Probe Placement
还有就是切换PRT Probe,一开始使的是可以覆盖整个球体的8个向量的非正交basisi,可以在图中看到Probe球体上的白点,但美术师发现这种方法街道有些太暗了。这时因为没有直上或直下的向量,所以来自天空的主光源以及来自街道的光反弹,是在两个斜向的向量上混合的。正因为这个原因,Stefannov他们决定改回HL2的Ambient Cube Basis,使用6个基础的向量虽然看起来少了,但因为有一个直上的向量可以精确的捕捉天空的光,以及直接朝下的向量捕捉来自地面的街道的光照反弹,所以更附合要求。
HL2的Ambient cube 更适合游戏的需求
在生产过程中,在自动摆放Probe如何正确的停止位置上也遇到了问题,由于一些原因,在一些特定区域无法生成Probe,这样就会在Irradiance Volume中产生黑色的Spot light。那个位置就无法获得任何的光照信息。为了解决这个问题,有些全封闭那种地方因为没有光照信息就不需要有probe,自动摆放算法没有在建筑里的某两层生成Probe,下面画面中右侧的起重机也是这样。
同样这里也提供了特殊调试工具,那些有问题的区域颜色会变得高亮,方便找到问题。解决问题很无聊,而且需要很多程序员的努力,所以考虑未来给美术师更多的摆放Probe的控制权。另外可以支持的是大型建筑物的UV mapping,在计算相同类型的PRT时,不需要6个向量,只需要维持4个切线空间的方向就可以了,另外允许美术师控制PRT的分辨率来达到更高的效率。
Interior Volume / Solution Accuracy
前面也提到过了,有时在室内的入口位置会丢失probe, 因为有设置室外和室内的Volume,所以在进门和出门是会有很明显的过渡。 下面的幻灯片里的右图可以看到效果的对比。通过在窗口的特定位置自动的摆放Probe来解决,因为发现的比较晚了,所以没有实现在最后的游戏里。幸运的是因为穿过房间时材质变换了,这些瑕疵并不明显。
其他想要改进的方案,还有要可以修改Surfel的Gird大小,反弹的参数可以bake,但必须要关注性能,在Baking和压缩上做优化。因为没有足够时间去写更复杂的渲染器,所以只预计算了一次反弹,多次反弹运行时是大致的估算出来的。在下时代的雪莲花引擎上,通过更强力的GPU可捕捉更多的反弹。
只实现了粗糙的反弹近似
Ease of Use
易用性方面,【全境封锁】的技术和雪莲花引擎是同时开发的,因为并没有足够的时间修改bug,所以就像下面右图那样,提供给美术师很多的参数,这样在解决问题前,可以先高效的隐藏这些bug。最后因为有了大量的参数,每个参数都关联着很含糊的特效,程序修完BUG之后为了不搞乱项目,这些参数都是不会去动的,最后的问题就是经常有些参数突然不起作用了,或者作用的效果变了。这样对灯光师造成了很大的困惑,不清楚那些只可以拿来调整光照。因为着色Bug的调试非常重要,所以要提供一些美术师可以读懂的参数。 在下一代的雪莲花引擎里,提供一组滑块让开发者调整。
也要考虑调试的易用性
译者留言:谢谢可以看完整文章,本文也是今年新的GDC翻译计划的第一篇,GDC上有很多的讲座是不提供PPT的,而且光看PPT也很难了解细节。在加上这些演讲都过于偏图形技术,对应新入门的国内开发者来说还是比较难的。这里也是想基于视频的讲座结合自己的理解,把技术内容更好的带给开发者。目前计划是每2周分享1篇,从最近的GDC2016开始,最后也感谢Qiankanglai在校对上的友情支持。如果有建议或问题,也可以通过RTX或QQ和我们联系。