MIAW:实现笔记(3)

内容纲要

战略转进,战略转进!

有如鸡肋

已经结束哩!

ReSTIR的效果不如我想象的好,性能也不如我预计的好(尽管它确实不错),种种实验让我大幅度降低了对于光追硬件性能的期望(又或许只是我的GPU太烂了...),总而言之,想要做到1080p,60帧,每个像素每帧顶天5ray均摊。而ReSTIR本身在质量上也有一些问题,尤为严重的是Temporal Reuse的Cheating一般的质量增益实际上靠其它降噪手段也能达成(论文中展示的渲染结果其实也是多帧叠加的结果,结果和单帧比自然是有很大差距的),而只使用Spatial Reuse实际上在性能上并不是很Novel,而且提升其实不是那么大。同时它在场景不断变化时也有一些固有问题需要增加算法复杂度才能解决。而且更加搞的一点是,ReSTIR和某些常用光追优化的结合实际上不好做(比如Manylights),但是这些优化在实际应用中又尤为重要。我逐渐开始理解为啥现代商业引擎对于ReSTIR使用不多了(确实是很好的算法与思想,但在实际使用中却总感觉有如鸡肋,难蚌啊)。

总而言之没那么理想,其思想大可借鉴,但光靠这玩意作为主力算法搞GI是不太可能的。

在过去的一年之间,我学习了Vulkan(现在大概比较熟练了),重写了MIAW,然后实现/学习了传统的渲染管线和一跳光照计算、不光追的GI(Sparse Octree Voxel Cone Tracing),光追的ReSTIR,并因此对于他们的优缺点、性能都有了比较直观的理解。唯一没实现过的方向只有Radiance Cache和Path Guiding之类的基于缓存的东西了。

时间过得很快,转眼之间2022年就要结束了,但MIAW的进度不容乐观,我甚至仍然没有决定GI的主要结构...而基于以上经验和考量,我觉得有必要重新考虑GI方法的设计,然后在近期拍板定型,以推进毕业设计的工程进度。

准备工作

任何一个单独的GI算法都必然有其局限性,而真正成熟的引擎一般会使用多种GI方法混合而成,取长补短并避免众多层次的Artifact。想要单靠一种算法完成良好的GI其实并不实际,而只靠光追做GI对于目前的硬件而言更是要求过高。

我觉得目前就开始设计GI方法似乎还是有点早了,需要多读几篇论文,不必实现,读懂作为参考即可。而且我也深深感受到了论文的展示效果和算法实际价值之间是存在一定差距的...所以在阅读论文(尤其是阅读其结果时)一定要不断地质疑:这个算法在所有情况下都Work吗?它为什么会不Work?它的缺陷是什么?论文并不是教材,很多描述、Figure都是有倾向的,它夸得天花乱坠的东西实际上可能并没有那么强大,要对其有清晰且客观的认知才能不被误导或者抱有过高期望(然后复现出来发现这也不好那也不好,就很失望了)。

  • A Survey on Gradient-Domain Rendering (CGF 1029),感觉Gradient Domain Rendering或许有用(在重建L1时可以尝试,但不能考虑Visibility项,毕竟那样会增加额外的射线。)
  • Optimal MIS(大概没什么用)
  • Real Time Neural Radiance Caching
  • Cosine Transformations

GI方案讨论

目标

首先,MIAW的GI主要目标是全动态、全路径、高性能1一定的材质支持,次要目标才是包含Delta函数的表面散射函数的材质、焦散、Glint等复杂光学效果,而且对是否有偏并不任何要求。

更加准确地,以C、D、G、S、E分别代表相机、散射、光滑、纯光滑交点与发光体,MIAW的GI将能处理的光路包含CE,CD(D)E,CS(D)E,C

接下来,分步骤探讨GI的具体方式

MIAW材质模型

出于性能、兼容性与材质自由度的折中考虑,在一些调研后,我决定让MIAW的所有延迟渲染的材质将由五个参数描述:

  • albedo,吸收率(光谱)
  • metallic,金属度(标量)
  • roughness,表面粗糙度(标量)
  • transmissive,折射度(标量)
  • specular,高光(标量)

物理描述

当然这个模型是Disney BSDF的超级简化版,这些参数(除开alpha)都支持无缝插值,参数数量相对少,对于G-Buffer的负担也不会那么大。

MIAW将支持折射的透明材质,我们假定介质只有两种:内介质和外介质,内介质在几何体内部,折射率总为1.5,外介质在几何体外部折射率总为1,于是在遇到计算折射的任意表面时,用该表面几何法向判断当前是从内看到外还是从外看到内即可。由于假定了电介质相对折射率是固定的,和Disney BSDF以及UE4等的做法类似,所有非导体的菲涅尔系数都使用Schlick的公式进行近似(且F_0固定为0.04),导体也使用该公式进行近似,为了省G-Buffer参数不多增加其它值了,不同金属之间的差别纯粹是用$albedo$参数伪装出来的(无法物理解释)。

我们假定材料表面是许多基于同一个微面分布的模型混合起来的,当一束光打到模型上时,有metallic的概率选取普通的导体微表面模型,有1-metallic的概率选取非导体模型,而非导体模型开始套娃,其有1-transmissive的概率选取非导体散射模型,该散射模型实际上就是OrenNayar散射模型和参数$specular$所控制的一层非导体微表面反射的加和specular为散射乘子),而其余情况下则会选择微表面反射加透射模型,所有微表面模型的分布参数都是一样的,由roughness统一控制。

上一段落中的加粗的加和操作会破坏这套模型理论上自圆其说的可能,不过无所谓,好用就行。

常见材质都可以使用这套系统进行表达,比若:

  • Metallic-Roughness体系的材质可以通过设置roughness, metallic, transmissive=0来表达。
  • 玻璃或水面通过设置roughness = 0, metallic = 0, transmissive = 1来表达。
  • 上蜡木地板通过综合设置metallic=0, transmissive=0, roughness, specular来表达。

但各向异性材质和一些Retro Reflective的材质(比若一些布料)在这个体系下是做不出来的。

Delta分布材质

为了提高渲染质量,对于直接可见的、BSDF包含Delta分布的材质需要特殊考虑。显然,在以上的材质模型之下,BSDF最多只包含两个不同的Delta分布(分别为折射和反射)。我们定义一个直接可见的材质包含Delta分布的像素关于该Delta分布的“对应点”为从该像素按照Delta分布方向进行光追,第一次遇见拥有包含超过一个Delta分布或者包含非Delta分布的材质的物体时,该位置应该生成的G-Buffer。

显然一个屏幕像素只有最多只会产生两个“对应点”。我们可以根据经验假设,相同Delta分布的对应点在相机胶卷上在位置维度上是连续的(这在许多情况下都为真,比若以免直接可见的镜子,镜子中反射的相邻像素往往在世界坐标下是相近的),那么我们仍然可以使用空间采样复用的方式优化渲染结果。

既然如此,对于直接可见的BSDF含有Delta分布的像素,我们将胶卷复制两份并光追出所有“对应点”,然后使用类似方式Shade。

一个像素包含30 byte,那么HD分辨率30帧单读一次就有1.8GBps的显存带宽,而我的RTX2060理论带宽是336GBps,似乎还有充分的带宽分配给几何与光追。

G-Buffer生成

使用Halton序列调整Projection Matrix,生成G-Buffer,以此节约一次光追的开销。使用某些好的采样序列可以为之后做TAA做准备。

针对没有折射的材质,若该材质有菲涅尔反射和很低的粗糙度(镜面),则多追踪一跳,在一个哈希表保存的新胶卷上对该像素生成一块全新的G-Buffer。类似的,若该材质包含折射分量,多追踪一跳并类似的生成独立的G-Buffer,这些G-Buffer将会被单独Shade并最终融合回渲染结果中。

这样之后,直接可见的表面上的材质中的Delta分布就被彻底去掉了,之后的讨论中将不会再讨论Delta分布带来的问题。

L0

零跳,即为Emission,直接从G-Buffer读取Emission项即可。

L1

一跳,可见表面的直接光照。可见表面的直接光照需要支持面元光,一些实时渲染引擎的解决方案包含Cosine Transformations等,但我决定直接上光追——原因在于,直接光照是最引人注目的光学现象之一,而且当代先进图形硬件完全是可以支撑这一部分的光追开销的(同时也有我对帧率只有30fps的要求的原因)。

首先直接ReSTIR肯定是不科学的(实践已经证明如此),而ReSTIR和Manylights其实不好结合,又考虑到Manylights采样其实有一定开销,那么可以考虑借鉴ReSTIR思想在屏幕空间复用Manylights采样,这实际上和直接上降噪器几乎差不多(不过MIAW的这个“降噪器”在一跳的路径空间上运行)。同样的,L1不应该有大量延迟,因此不在这一步干其他时域上的事情。

为了加速可见性测试,考虑使用Probe上的几何与VSM信息,找到周遭比较近的在同一表面上的Probe,利用其上存储的深度分布信息看看它和光采样之间可见性的误判率,使用一个数学上最小化采样贡献的方差的方式来决定是否光追(还是直接信了这个利用Probe得出的结果)。

简单的方法可能才是最好的方法。

这样的话每像素每帧开销是X ray + 1 call(X和周围几何复杂度有关),结果存储在单独的Buffer中准备TAA。

L2与L2+

两跳以及以上,通过直接查询Radiance Cache (Surfel)实现。MIAW并不准备使用DDGI类似的存储方式以支持更丰富的材料类型,但如此便在Shading中要对Probe多次查询,为了节约查询次数,类似地,在屏幕空间上复用查询结果,然后在另一个Buffer中单独进行TAA。

然而Probe Based的方法有两大问题,第一是糊的Bias,这种Bias非常严重,且源来自于稀疏的Probe放置,是Probe一类方法的根本性问题之一。Surfel一定程度上缓解了这个问题——但还不够,需要思考使用某种方式补偿或者尝试消除这种Bias

许多Bias都和Surfel / Probe无法捕捉某些地方的几何陡变与局部几何信息有关——我在想,能不能利用Surfel缓存一点这些位置的几何信息来进行优化,或者使用小开销的短距离光追直接渲染短距离光照效果呢?

Probe Based的第二大问题便是对于Glossy材质不友好——即便是UE5的Lumen在技术演示中,地上的水光反射也出现了很明显的Artifact。对于Glossy材质,可以考虑使用Ray Measure + ReSTIR来直接多光追一跳以优化渲染结果。

12.4:实际上这可能会引入过多开销,因此暂不考虑

维护Surfel

Surfel的维护大量借鉴(抄袭)了GIBS的思想,比如Surfel Generation / Surfel Injection / Importance Sample / Variance Detection等,这里不再赘述了。

MIAW将对其进行一系列的改进:

Surfel的存储结构

首先,Surfel使用OCT格式保存照度、深度以及方差信息,(格式分别为R111G11B10和R16G16),一个Surfel存储一个球面而非半球面(为了应对模型的移动需要存储冗余信息),但在更新Surfel时只会生成在其法向正面的射线。与GIBS不同的是,Surfel不会绑定在一个MIAW Render Command上,它的坐标系是完全的世界坐标。每个Surfel会保存两个Surfel位置:存储位置与实际位置。存储位置定义了Surfel的球面,而实际位置定义了进行Surfel Injection与查询、更新Surfel生成光追射线时的位置。当存储位置与实际位置偏差超过一定阈值时,存储位置会被更新到实际位置,而Surfel材质在这个过程中使用Reprojection的方式进行更新。这样做的好处是能减少Surfel频繁位移时造成的信息损失。

Surfel的Relocation

那么如何根据场景的变化确定Surfel位置呢?每一帧,MIAW会选取一部分Surfel发射射线进行更新,在更新后,这些Surfel会对射线所采样的三维点的动量(Motion)进行一次简单的主成分分析,保存在Surfel数据结构内。然后所有Surfel会根据主成分Motion对Surfel进行位移。位移后的Surfel会在下一帧Shading前被吸附到最近的Shading Point上,它的法向和实际位置会被更新为该Shading Point的几何法向与位置。在每一帧之中,MIAW会对三维空间上的数千万点进数千万次Shade,为了性能考虑,我们保存其中的一小部分用于吸附Surfel,称之为Sample Points。而未被吸附的Surfel会被随机回收。这么做的目标是在场景变动的情况下,尽量地复用Surfel的信息(为每个Surfel找到其材质可信度最高的最优位置)。

Surfel的Importance Sample

如何选择急需更新的Surfel需要一定设计,这里借鉴了GIBS的思想(不过有些改进)。每个Surfel保存了每个Pixel的Variance,在其被更新后,其Variance与Luminance与存储位置和实际位置之间的投影雅克比权重与Sample Point的点积会被统计并定义为其被选中更新的权重。使用一个单独的Compute Shader统计并选取需要更新的Surfel到一个数组中。

接着,在生成更新Surfel的射线时,使用Variance点积Luminance点积存储位置和实际位置之间的投影雅克比权重来生成每个Pixel的Importance,再次进行重要性重采样来生成这些用于更新Surfel的射线。

Surfel Correlation与Surfel上的Sample Reuse

Surfel与Surfel之间可以产生很大的相关性,通过假设二次光照后材质函数的一些性质,可以尝试使用一条更新Surfel的射线更新多个Surfel的数据。

其它

一个非常值得创新的部分是Surfel针对“动态场景、光源”的延迟优化,上面多数是针对动态场景的优化,而对于动态光源的优化也很值得尝试。但是这部分需要更多试验,首先要思考变化直接光照的一般特点,然后从在Surfel上缓存与利用更多场景信息入手。


  1. 指720p 30fps,如果我显卡更新了可以考虑一下做1080p 30fps 

此条目发表在小项目分类目录,贴了标签。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注