【GDC 2011】Lighting You Up In attlefield 3
今天介绍的是战地3在GDC 2011上分享的寒霜引擎2的光照方案,分享者是Kenny Magnusson,是一位美术同学。照例,这里对工作内容做一个总结:
- 采用的是延迟管线
- 大尺寸静态物件用的是lightmap方案
- 小尺寸静态物件跟动态物件则用的是lightprob方案
- lightprobe不是PRT,而是用SH表达的来自各个方向的输入radiance,通过烘焙多套数据来实现TOD的支持
- lightprobe的烘焙得到的是中间数据,目的是加速运行时的计算,降低运行时消耗。需要运行时计算的原因是希望支持破坏等动态场景的需要。
介绍分三部分:
- 过去的表现
- 项目的需求或目标
- 具体如何达成
最后对全文做一个总结
过往的两个项目分别使用寒霜1跟UE3开发,两者都是前向管线,其中:
- Bad Company有如下的一些值得注意的点
- 寒霜1的特点:
- 为户外场景设计,以动态破坏为主要特点
- 最多可以支持100+动态阴影
- 方向光阴影是动态的,采用三级CSM,都是1024的分辨率
- 每个物件最多受一盏点光影响
- 引擎最多可以支持3盏
- 没有SSAO与GI
- 大尺寸的物件如建筑会需要(静态)天光遮蔽效果,室内等区域则通过天光遮蔽volume来标注
- 寒霜1的特点:
- 镜之边缘则有:
- 不是特别看重动态破坏效果,主要聚焦于City Landscape,因此lightmap+覆盖动态物体的probe就已经足够
- 通过烘焙的lightmap来实现静态场景的GI效果
- 通过预计算的light probe来对动态物体做relighting
期望在保持对动态破坏效果支持的同时,还能保有镜之边缘的GI表现,下面对需求做进一步明确。
Battlefield BC 2(左)的室内光照表现与镜之边缘(右)的差距十分明显,这里期望能达成一致(室内有破坏)
期望能够有较好的户外景色表现以及城市远景表现。
反射效果对于提供一个鲜活可信的场景具有重要意义。
有多光源,有破坏,一个非常自然的需求就是要能够支持光源的可破坏。
当然,这里的目标不只是承袭之前的优点,还希望能够推陈出新。
期望能够实现延迟管线所能够支持的那么多光源(或者说直接支持延迟管线)
更多种类的shading model,比如皮肤的SSS
甚至能支持半透的SSS效果。
期望能够提升光照烘焙的效率。
同时支持多职能以及职能间多成员的协同开发。
期望给特效增加光照逻辑,使得表现跟场景能够较好的吻合。
标配的bloom效果
与之配套的更先进的Filmic Tonemapping效果
期望在寒霜引擎中实现Enlighten方案。
编辑器工作流也需要优化
大多数游戏中主要关注specular跟diffuse lighting,且只关注一次反射,多次反射由于消耗高通常会被忽略。
表面可以分为三种:
- 完全反射
- 完全吸收
- 先吸收,后部分散射出去
对于反射属性比较强烈的表面,这里称之为highly specular
先吸收,后散射(均匀向各个方向)的称之为highly diffuse
这两者都会将接受到的光线返还给环境。
对于后续发生的多次反射效果则统统用间接光表示,或者这里用GI代指(实际上GI应该包含直接光),最常见的GI方案有两种:
- 烘焙到lightmap
- 给场景补光
lightmap有如下特点:
- 效果好
- 需要时间烘焙
- 需要制作2UV
- 不支持TOD与动态物件
补光方案有如下特点:
- 耗费美术时间
- 部分情景效果不佳
- 性能差
考虑到上述的问题,一个策略就是采用实时GI方案(如上述的Enlighten),Enlighten会给出每个点收到的光强颜色与主光方向(用于计算indirect specular)
这里首先会对场景物件做区分处理,分为lightmap覆盖的以及lightprobe覆盖的
-
前者对应的是不可移动的静态物件,可以接受lightmap光照,也会对周边环境的光照结果产生贡献。
-
后者对应的是动态物件(或者小尺寸的静态物件,从性能与效果的平衡考虑,不用过于高分辨率的数据),仅接受场景其他静态物件的光照反射输入,不做输出。
黄色表示lightmap覆盖范围,蓝色表示lightprobe覆盖范围。
lightmap需要的2uv是自动生成的。
为了能够handle所有的radiosity数据(?),这里还需要一个简化模型(?)
上面介绍了如何从detail model得到简化model
简化模型会需要生成对应的lightmap数据。
之后将高模的lightmap数据迁移到低模的贴图上,还是没解释这么做的意义是啥,用于给probe提供indirect incoming radiance?
再来看lightprobe,通过volume来约束probe的生成区域,结果用grid存储,其实就是VLM的思路。
每个probe的光照数据(仅包含该probe位置所接收到的来自四面八方的输入光照)用SH来表示
probe数据的生成,需要先在离线走一个预处理pass,这个pass会搜集静态场景的结构,输出一些中间数据,这些数据后面会用于计算dynamic SH数据。
因为这个过程相对比较费(前面的场景大约需要20min),所以放在离线完成,不过由于仅当静态场景变化,才需要触发,所以还好。
运行时的shading管线分为三个步骤:
- 先完成lightmap跟lightprobe的数据更新
- 再进行延迟管线Base Pass的渲染,得到GBuffer数据
- 在lighting pass中,对前面的数据进行取用以完成最终的光照计算
为了保障室内外光照结果的正确,避免室内物件受到来自天光的淡蓝色加持,这里还增加了一项叫做天光可见性的参数用于表征该位置可以接收到的天光的强度。
室内环境贴图的颜色与强度会跟之前计算的dynamic radiosity有关。
为了给户外的大尺寸物件照明,这里选择用SH来表达天光照射(为啥不用一张cubemap呢,这样可以得到正确的高光效果呀?)
地形的lightprobe也是均匀摆放的,不过会自动贴合到对应的高度上
也需要lightmap,两者的分辨率都跟地形的patch size有关。
场景受方向光照射
加了一盏绿色聚光灯
对场景产生了color bleeding反射效果。
这里会将一部分元素从光照体系中剥离出去,主要出于对灵活度的考虑,比如可以实现红色的天空、绿色的墙面的表现
下面介绍一些实际工作中的一些经验建议。
对于复杂物件如可以破坏的房屋,可以考虑将房屋做拆分处理,不可破坏部分用lightmap(灰色),可以破坏部分用lightprobe(红色)。
战地3开发了一个static radiosity maps系统(同样,不知道做啥用的),用于快速完成lightmap跟light radiosity(像是lightprobe SH计算所需要的中间数据?)数据的烘焙。
在小尺寸的区域,比如室内,可以启用enlighten的实时计算部分以避免烘焙消耗
对于大尺寸区域,则是提前烘焙好,运行时streaming
只有在实时enlighten启用的时候,才会支持TOD功能。
不过如果要做TOD,需要约束分段存储的数据的数目,这个会导致内存上的增长。
需要了解电影的后处理逻辑,通常来说,color grading应该放到最后一个环节。
上面两图展示了color grading的作用:增强对比度。
根据效果需要,选择合适的filmic tonemapping公式。
新增lightprobe特性,相比于之前纯粹的lightmap方案的不足:
- 内存增长了
- 基于lightprobe的密度,会有一定的性能占用
- 增加了编辑成本
- 增加了烘焙成本
优点则是:
- 相比于lightmap而言,精度更低,且有很大一部分实时计算环节,因此迭代效率更高
- 可以更好的适配场景的变动
- 提供了动态、静态物件统一的光照方案
参考
[1]. 【GDC 2011】 Lighting You Up In attlefield 3