ue4多个关卡怎么构建光照_游戏中的全局光照(四) 漫反射GI

本文深入探讨了在UE4中构建全局光照漫反射GI的多种方法,包括光照预计算、带方向光照预计算、Lightmap、Light Probe和Precomputed Radiance Transfer。通过球谐SH、H-Basis、球形高斯SG等技术,解释了如何处理静态和动态物体的光照信息。此外,还介绍了全动态光照的发展趋势。
摘要由CSDN通过智能技术生成

26244e4ed5fa33e2f57e5aa43c77a4dc.png
TC130:实时渲染学习笔记目录​zhuanlan.zhihu.com

接下来我们来讨论GI的漫反射部分, 首先需要明确的是, 这里的漫反射GI, 指的是最后一步是漫反射, 而不关心前面的光传播是漫反射还是镜面反射.

光照预计算

和前面我们烘焙AO系数的过程一样, 最简单的方式就是将漫反射的光照预计算并保存下来, 当然, 这种方式仅仅适用于静态的物体和静态的光照. 另外, 这里的烘焙是可以包含前面我们讲的环境光照的.

一般来说, 我们通常需要将场景中的物体分为静态(static)和动态(dynamic)的, 对于静态物体使用烘焙的技术. 而对于动态的物体, 会在下面讲到如何实现GI效果.

最简单形式的烘焙就是直接记录静态光照在物体表面上的 irradiance, 对于一个平坦 lambertian 平面, 实时计算光照的过程非常简单, 只需要用 irradiance 乘以物体表面的albedo即可:

994f84d9801dd2a62bbaf080a1fad330.png

当然这里我们是假设物体表面是平坦的, 对于有法线贴图的物体, 这种方式就会出现明显的穿帮. 因此目前已很少见到预计算 Irradiance的做法.

你可能觉得困惑的一点是, 为什么不将物体表面的漫反射光照直接计算出来并保存呢, 因为漫反射Lambertian假设在所有方向上观察强度完全相同, 这样根本就不需要考虑法线的问题了.

原因是这样做会消耗非常大的存储空间. albedo 贴图本身是非常 high-frequency 的, 而且 albedo 贴图是可以在多个模型间复用. 但是 lightmap 无法复用, 只能做成 low-frequency 的. 这样将 lightmap 和 albedo 分离可以尽量降低内存消耗.

带方向光照预计算

因此, 我们烘焙的 lightmap 需要考虑不同法线情况下对应的光照信息. 幸运的是, 我们手头有很多现成的工具. 在本系列文章第一篇中讲环境光照的时候, 讲到过球形高斯SG和球谐函数SH, 正好可以在这里使用.

球谐 SH

使用球谐SH是比较直观的方式, 效果也非常好. 但是问题也很明显, 就是用球谐SH存储时, 消耗的存储空间太大. 使用三阶球谐, 每个颜色通道要存储9个float值, 3个rgb通道需要消耗27个float值. 如果使用二阶球谐, 每个颜色通道只需要存储4个float值, 但是效果又不太行. 在SH的基础上, 有很多基于SH的改进模型.

一种比较常用的是 H-Basis, H-Basis只考虑半球面上的光照, 因此相对SH需要更少的存储空间. H-Basis每个通道需要6个系数, 需要和几何体的切空间配合使用. 详情可以参考:(PDF) Efficient irradiance normal mapping.

f2229ebe08eec4d06dfd1c60d2e99e66.png
SH和H-Basis对比

另外一种改进是直接基于SH的改进, 比如这个 https://web.archive.org/web/20160313132301/http://www.geomerics.com/wp-content/uploads/2015/08/CEDEC_Geomerics_ReconstructingDiffuseLighting1.pdf. 这里不再深入讨论.

球形高斯

基于球形高斯SG的GI使用相对较少, 最出名的就是在教团:1886中SG的使用. Pettineo 写了一系列的文章 SG Series Part 1: A Brief (and Incomplete) History of Baked Lighting Representations, 详细描述了SG 在GI 中的应用.

除了这两种方法之外, 还有很多一些其他的方法:

Ambient/Highlight/Direction

顾名思义, AHD用三个值 环境光ambient, 高光hightlight, 高光方向 direction来表示Diffuse GI的效果. AHD使用这样三个数值来近似表示Diffuse GI, 每个点需要8个float值来表示(direction只需要两个float). 因为AHD的真个过程不是线性的, 因此AHD的难点在于如何寻找合适的分配方式, 将GI分成固定的ambient部分和 可变化的hightlight部分. 使命召唤中的具体实践可以参考: https://www.activision.com/cdn/research/Precomputed_Lighting_in_CoD_IW.pptx

85a3e6f041f4c882c6f947f994c4c474.png
使命召唤中的AHD烘焙

Radiosity Normal Mapping/Half-Life 2 Basis

0884bb36bf2ddda892d10f54f2e34c3d.png
RNM的三个正交基

RNM方法在切平面上指定三个正交基的方向

计算GI在三个正交基上的投影, 并进行重构.

UE4

UE4中的Diffuse GI烘焙保存最大光照度和一个二阶球谐系数. 这样每个点需要的系数个数为: 3个RGB分量+Log光强度值(压缩用)+4个二阶球谐系数 = 8, 正好可以用两张贴图保存. 个人猜想这样做的原因是:

  1. 这里仅保存Diffuse, 随方向强度变化一般很平缓, 二阶球谐的精度够用.
  2. 每个点使用8个float值, 尽量减少存储空间占用.
  3. 去掉二阶球谐系数, 也可以直接用来作为不带方向的预计算光照. 这样可以使烘焙出来的lightmap 兼容两种方案(不知道为啥, ue4没有提供不带方向lightmap的全局设置, 这也是一个手游的优化点).

Lightmap

通常, 我们使用lightmap来存储烘焙好的光照信息, 也就是存储成贴图, 这样可以方便GPU访问数据. 根据使用的GI方案不同, 数据的处理方式也不同. 譬如对于AHD, Direction可以直接存储两个方向值, 取方向时做一次标准化即可. 而对于Ambient和Hightlight 颜色值, 通常需要处理成非线性的来存储.

因为 lightmap 相对于 albedo贴图是无法复用的, 因此 lightmap的相对密度要低很多. 通常 lightmap中的一个texel对应20cm*20cm的大小, 已经是精度很高的烘焙了. 对于不同的场景, 往往需要不同的lightmap设置, 比如在室内需要高精度, 在室外使用低精度.

对于每个模型的每个三级形, 都是需要在lightmap上独占一部分区域的. 通常在开始烘焙前, 需要将模型划分为数个chunk, 对应的uv就是常说的lightmap uv. 这一步可以是手动设置的uv, 也可以是自动生成的, 自动生成lightmap uv的过程也叫做 uv unwraping.

ligtmap uv 需要保证是在 0~1之间. 且chunk之间应保留至少两个像素的间隔, 这样可以防止 blinear 采样时, 采样像素被其他 chunk 部分的像素影响, 出现漏光/bleeding.

552c769f9da01fa2ef4ffa7039104801.png
uv unwrapping

如果两个邻接面间的角度很大, 导致两个面的光照信息有很大差异, 但是却划分在同一个chunk中, 就会产生接缝/seams, 这样两个面的烘焙光照会互相影响. 这是一个需要避免的情况.

每个物体的烘焙贴图形成一个chart, 将所有场景中物体烘焙的chart进行汇总, 合并到一个或多个贴图上, 就是lightmap.

Light Probe

上面我们说的lightmap, 是针对静态光照和静态物体的常用方式. 对于静态光照和少量的动态物体, 我们通常使用光照探针(light probe)的方式计算光照. 光照探针是放置在场景中的许多位置点, 烘焙光照的方式和lightmap中基本相同. 区别点在于一些仅适用于半球面的方法不再适用. 一般我们使用球谐SH或者球形高斯SG来表示light probe的光照信息.

当移动的物体计算光照时, 在物体周围取数个light probe, 然后进行插值计算光照.

40775b15ed94ab796da14ea4877371fd.png
unity中的light probe放置

另外一种激进的light probe放置方式是volumetric lightmap, 在空间中均匀地分布light probe点, 并将计算的结果保存为 3D Texture中. 这样, 就省去了寻找周围light probe并插值的过程, 直接在GPU中对3D Texture进行trilinear采样即可. UE4从4.18开始已经将动态物体的GI方案更改为 volumetric lightmap(对于UE4来说, 刚好可以适配UE4的volumetric rendering方案).

7ed432f0e5a877f605a06f9237a888f4.png
UE4 中的volumetric lightmap, 静态物体周围的lightmap密度较高

Precomputed Radiance Transfer

很多时候, 我们希望在静态场景中不仅有烘焙的静态光照, 还希望光照可以是动态的. 一个典型的应用就是实现某个场景的昼夜变换. 简单的做法是烘焙两套静态的 lightmap, 在昼夜期间切换. 若要实现全时段的动态光照, 则可以烘焙几个关键时间点的lightmap, 根据时间进行线性插值.

PRT可以实现真正意义上的针对静态场景的动态光照. 这里来大致介绍下PRT的原理.

考虑Lambertian模型下的物体表面, radiance与观察方向无关, 只跟每个方向上的光照强度相关且是成正比的. 这样, 将周围的环境光照用球谐SH来表示, 物体表面的radiance和环境光照的相关系数, 可以用另一个球谐SH来表示, 将两个球谐相乘, 即可得到物体表面的radiance. 将相关系数(通常是3阶球谐系数)烘焙, 即可得到 PRT 的lightmap. SIGGRAPH 2005上的课程详细总结了这种PRT的原理和使用:http://www0.cs.ucl.ac.uk/staff/J.Kautz/PRTCourse/

因为这里计算的PRT是和环境光照相关的, 光源也会被用环境光照来模拟表示, 不会考虑附近物体的反射, 所以这种方式比较适用于户外场景, 用来表现随时间不断变化的昼夜环境光照.

另外一种PRT会考虑附近物体表面的光照反射, 记录物体表面间光照的互相影响. 使用这种方式最出名的PRT光照系统就是 Enlighten, 目前为止 Enlighten 算法的原理细节还未全部公开, 这里不再深入.

94fcb2f6de4186efca29fe152e855073.png
Unity中的 Enlighten光照

全动态光照

使用 lightmap烘焙光照的缺点很明显, 就是烘焙场景时间很长, 以及需要很大的存储空间. 特别是在 PRT / Enlighten 烘焙光照中更为明显. 因此目前的GI正在逐渐向全实时光照的方向发展, 在本系列文章后面, 会进一步介绍目前常用的全动态GI方案.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值