BlueRoseNote/03-UnrealEngine/Rendering/RenderFeature/Lumen学习笔记(2)——原理笔记.md

122 lines
12 KiB
Markdown
Raw Normal View History

2023-06-29 11:55:02 +08:00
---
title: Lumen学习笔记2——代码分析
date: 2023-02-12 10:50:24
excerpt:
tags: Lumen
rating: ⭐
---
本文的内容为丛越的知乎文章的知识点浓缩。
## Lumen相关可视化命令
- r.Lumen.Visualize.CardPlacement 1开启Lumen Card的显示。
- r.Lumen.RadianceCache.Visualize 1开启World Space Probe。
- r.Lumen.ScreenProbeGather.VisualizeTraces 1开启屏幕空间探针追踪可视化。
## Software Lumen的加速结构(距离场)
使用SDF(Signed Distance Field)作为存软件方案的加速结构。分为Mesh DF与Global DF。
## Surface Cache
Surface Cache 是一系列运行时生成的图集(Atlas),以很低的分辨率存储了整个场景物体表面的材质属性。
Lumen 采用 Cube Map 理念仅生成**6 个轴对齐方向**(上、下、左、右、前、后)的 **Material Attribute**,在 Tracing 时将 Hit Point 简单的投影到这 6 个方向,对 Surface Cache 执行采样,就可以以极高的性能获取 Material Attribute 进行 Lighting。
在UE5中被称之为**Card**。
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230212113939.png)
## Radiance Cache
对于 Surface Cache 上的每个 Texel 来说Direct Lighting 的结果就是该点的 Radiance如果把 Surface 上的所有 Texel 的 Radiance 保存下来,这样就包含了整个场景的光照信息,这就是 Radiance Cache。有了 Radiance Cache就可以在 Tracing 时直接进行采样作为 Tracing 方向对应的 Radiance将这些 Radiance 收集起来积分计算出 Irradiance从而得到最终的光照值。还可以基于此生成 Indirect Lighting 并与历史帧累积起来,这样就实现了 Lumen 所宣称的无限反弹Infinite Bounces的全局光照能力。
从左到右分别为 Albedo、Normal、Depth、RadianceDirect Lighting 以及最终的渲染画面。
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230212110227.png)
## Lumen Scene
可以在`ViewMode-Lumen-LumenScene`中查看。
Lumen Scene 包含了 DF 描述的场景几何表达以及 Surface Cache 描述的场景材质表达,是一个完整的系统。
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230212112912.png)
## Screen Space Probe(针对MF Tracing)
Lumen 是一个基于 Probe 的 RTGI 系统,通过 Probe 执行 Ray Tracing。
Screen Space Probe 仅用于**DF Tracing**,在**1.8** 米范围内进行**Mesh DF Tracing**,那么对于更远的距离会使用**Global DF Tracing**(以及屏幕空间外的区域)。但是却**无法**同 Mesh DF 一样从 Surface Cache 上**获取 Material Attribute**,原因正如上所述,**Global DF** 是由 **Mesh DF** 合并而来,全局只有一份,缺少了 **Mesh DF** 信息,而 Surface Cache 又与 Mesh 相关,因此无法通过 Global DF 获取 Mesh 对应的 Surface Cache 数据。
Lumen作者解释时还说了下图中的东西。我个人理解为
>首先进行屏幕空间的追踪即直接获取到SurfaceCache的材质与照度数据如果失败则依次追踪**Mesh DF**与**Global DF**。
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230212114305.png)
那么 Lumen 又是如何对 Global DF 进行 Lighting 的呢?这就要引入 [[#Voxel Lighting]]。
### Screen Space Probe放置方法
首先每隔 16 个像素均匀的放置,然后进行自适应放置,检查 Probe 网格中的像素是否可被插值,即 4 个 Corner Probe 是否被当前像素遮挡,如果是则在当前像素位置上增加一个 Probe如此迭代每次迭代增加一倍分辨率直到插值差值失败的像素很少或达到指定的分辨率阈值。如下图所示橘红色为差值失败的像素
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230212113224.png)
## Voxel Lighting
Lumen的**Voxel Lighting**存储的是较粗颗粒度的**空间光照信息**应该6轴向的光照信息。从采样**Radiance Cache**获得。为了精确,采用了和**Surface Cache**一样的世界坐标6轴向对齐方案。最后通过采样3轴向的光照数据再根据Ray方向进行权重插值取得结果。
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214145323.png)
为了进一步优化性能减少内存Lumen 还为 Voxel Lighting 生成了 Clipmap用于覆盖不同范围这样可以根据采样点所在的 Clipmap 获取光照。通过 ClipmapVoxel Lighting 可以覆盖从最小 50 米到最大 6.4 公里的范围,默认最大覆盖 400 米。
**Voxel Lighting**的另一个用途是用于生成 **Indirect Lighting**,这就是**Radiosity Indirect Lighting**。
## Radiosity Indirect Lighting
实际上严格来说 Lumen 并不是 Ray Tracing而是 Ray Casting因为光线在与 SDF 相交后并没有再次 Bounce因此最多只能产生一次 Bounce 的 Indirect Lighting为了弥补这一点Lumen 使用 Radiosity 来生成 Indirect Lighting。
传统的 Radiosity 方法需要将场景划分为 Patch而 Lumen 已经拥有了粗粒度的 Global DF 以及粗粒度的 Voxel Lighting因此可以**直接从Surface Cache 上射出光线**,与 **Global DF 进行 Ray Tracing 求交**,交点采样**上一帧的 Voxel Lighting** 后转换为**二阶球谐**,最后再根据 Normal 计算**Diffuse Transfer 球谐系数**,计算出最终的 Indirect Radiance。
这个**Indirect Radiance也保存在Radiance Cache中**,称为**Indirect Lighting**并与Direct Lighting 合并计算得到最终的 Final Lighting而下一祯的 Voxel Lighting 又来自于这一祯的 Radiance Cache因此后续所有的 Lumen 光照流程自然具有了间接光照。
## World Space Probe当Global DF求交失败时进行采样
尽管 Voxel Lighting 可以Trace到更远距离的光照但对于远光**Distant Lighting**)会更容易出现噪点,因为**小而亮**的特征产生的噪声会随着该特征的距离增加而增加,另外还存在着长距离 Tracing 的性能问题,并且距离的长短不均匀变化也会导致 Tracing 性能的不稳定。
Lumen 使用了单独的采样方案来解决这个问题,这就是**Word Space Probe**。通过在世界空间中布置 Probe向各个方向上对 **Global DF Tracing**,对 Voxel Lighting 进行采样并缓存下来,这样就得到了 **Word Space Probe 的 Radiance Cache**
乍看起来这与传统的 Irradiance Field 很相似,但不同之处在于 Word Space Probe 在**Screen Probe 周围分布 8 个 Probe**,因此是稀疏的放置的,另外由于 World Space Probe 与视角相关,为了优化性能也使用了 Clipmap每个 Clipmap 的 World Probe 数量相同,但范围不同,默认 4 级最大可设置为 6 级。下图为 World Space Probe 的可视化视图,可以明显看到 Probe 在 Clipmap 中的稀疏分布:
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214153405.png)
**Global DF Tracing 失败时**,可以快速查找 Screen Space Probe 周围的 8 个 Word Space Probe在 Ray 方向上**对 Word Space Probe Radiance Cache 采样,三线性插值混合这些 Radiance**,从而得到最终的 Distant Lighting这种方式使光照更加稳定大大缓解了噪声。此外还可以与采样的 Voxel Lighting 进行插值混合,使光照过渡更加平滑。下图是 Radiance Cache 对比图,左图关闭,右图开启:
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214163930.png)
## Importance Sampling
Lumen 引入了业界降噪常用的方法重要性采样Importance Sampling通过使用上一帧的 Radiance Cache 作为生成当前帧的光线方向的引导,使光线尽可能朝向光源方向追踪,这样就可以在不增加光线预算的情况下实现了降噪,如下所示:
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214165242.png)
## Shadow
阴影的本质就是光照的可见性。Lumen 为 Surface Cache 标记 Shadow Mask这样在 Lighting 时直接乘以这个 Mask 即可。Shadow Mask 可以直接使用之前已经生成的Virtual Shadow Map。
但是这并不够完整,原因在于 **VirtualShadow Map 的生成是 Camera Visibility相关**的,而 **Surface Cache 与 Camera Visibility 无关**,这会 Surface Cache 的 Shadow Mask 缺失,因此**需要对那些没有 Mask 的 Surface 再执行一次 Ray Tracing 来判断光源的可见性**。因为 Lumen Scene 已经具有 SDF 表达,因此可直接使用 Mesh Global DF Ray Tracing其实本质上就是在**Surface Cache 上进行 DF Shadowing**。
## 降噪
同目前主流的 RTGI 一样Lumen 也采用了基于 Temporal Spatial Filter 来降噪Lumen 的 Temporal Filter 发生在整个 Lumen Pipeline 的最后阶段,而 Spatial Filter 则在各个流程之中已经进行。例如 Screen Space Radiance Cache访问时在 Probe 空间执行 3x3 的滤波,由于 Radiance Caceh 是 1/16 屏幕大小的,因此 3x3 的 Kernel 相当于屏幕空间 48x48 的 Kernel 大小,这样就以很低的成本实现大 Kernel 的 Filtering。下面是仅使用 Spatial Filter 的对比图,降噪效果明显:
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214165813.png)
## Reflections
为了优化性能 Lumen 实现两种 Reflections 机制,当 **Roughness 大于 0.4 时**重用**Screen Space Radiance Cache**的结果,因为这时高光的 GGX Lobe 已经汇聚到 Diffuse 上,而且会自动利用已经做完的 Sample 和 Filtering 结果。当**Roughness < 0.4 的反射使用额外的光线进行 Tracing**过程与Indirect Diffuse 类似,也包含了三种 Trace
1. Screen Ray Marching采样上一帧的 Scene Color。
2. Mesh DF Tracing ,采样 Screen Space Radiance Cache。
3. Global DF Tracing ,采样 Voxel Lighting 和 World Space Radiance Cache。
最后使用双边滤波器进行降噪输出 。
## Translucency Volume GI
Lumen 还为半透明材质及体积雾的 Light Scattering 提供了低分辨率的 GI。
Lumen 将 Frustum 体素化为 Froxel对可见的 Froxel 执行 Global DF Ray Tracing采样当前帧的 Voxel Lighting 和 World Space Radiance Cache 获取 Radiance使用 3D Texture 存储每个 Froxel 的 Radiance然后使用一定次数的 Spatial Filtering 降噪,最后进行积分转换为二阶球谐系数,用于半透明材质及体积雾来计算 Lighting。
## 丛越整理的的流程
1. Lumen Scene Update
1. 根据**Mesh Cards**生成**Surface Cache**。
2. Lumen Scene Lighting
1. Surface Cache Direct Lighting
2. Radiosity Indirect Lighting
3. Direct Lighting + Indirect Lighting 合并生成**Screen Space Probe Radiance Cache**。
4. 体素化相机范围内场景并根据**Surface Cache Lighting**生成**Voxel Lighting**
5. 根据 Voxel Lighting 生成 Translucency Volume Lighting。
3. Final Gather
1. 根据**G-Buffer**放置**Screen Space Probe**
2. 在每个**Screen Space Probe**周围放置 **World Space Probe** 并根据 **Voxel Lighting** 生成 **World Space Probe Radiance Cache**
3. **Screen Tracing**,采样前一帧的 Scene Color。
4. 在近距离范围内对每个**Screen Probe**执行 **Mesh DF Ray Tracing**,采样**Screen Space Probe Radiance Cache**。
5. 在中远距离范围内对每个**Screen Probe** 执行**Global DF Ray Tracing**,采样**三个方向的 Voxel Lighting**,并同时采样 **8 个 World Space Probe Radiance Cache** 与**Voxel Lighting** 混合。
6. 插值、积分和时序过滤,最终得到 **Scene Indirect Diffuse**
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214170223.png)
![image.png](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20230214170237.png)