Games202(10`第13章、第14章)
第13章
Spatial Denoising Solution空间降噪方法
~C k = —C,noisy未降噪的 被kernel滤波(卷积核)处理 得到降噪后的
高斯滤波(Gaussian filtering)
通过像素绝对距离确定权重,卷积核类似于正太分布,中心值高,向两边衰减,除去高频信息(变化剧烈的部分),整体模糊
伪代码:
- 对于每个像素i,找到周围的每个像素j
- 加权:对每个像素j,会根据绝对距离和标准差求得j权重,通过j值 * j权重 得到j对i的贡献值
- 平均:循环结束,i值 = sum_值 / sum_权重
双边滤波(Bilateral filtering)
通过像素绝对距离、颜色确定权重,以便保留低频和边界高频(变化最剧烈的部分),达到整体模糊但边界清晰的效果
如果a和b信号(颜色)差距过大,那么让b对a的贡献减少,从而就不会出现边界的模糊情况
因此我们要更改权重的计算公式(随差值衰减的函数,比如高斯函数,差值越大,贡献越小):
i和j代表第一个像素位置,k和l代表另一个像素位置,I(i,j)表示第一个像素的颜色值,I(k,l)表示第二个像素的颜色值
括号中左边是距离影响,右边是颜色影响
联合双边滤波(Joint Bilateral filtering)
我们刚才只考虑了像素绝对距离和颜色信息,如果考虑更多的特性,将得到更好的结果
我们会利用像素绝对距离和G-buffer(颜色,法线,深度……)的信息,对于每次计算b对a的贡献时,都会考虑这3者,如果某特性差距过大,那么让b对a此特性贡献减少,最后将3者贡献相乘,得到最后的权重值
实现较大的过滤器Implementing Large filters
如果有一个较大的过滤器,filter速度会变得特别慢,如何让它变快呢?
拆分实现Separate Passes
假如有一个N * N的高斯filters,我们需要计算N * N次,但现在我们把它在水平方向上的N个像素filter一遍,之后再在竖直方向上的N个像素filter一遍,将两者filter结果相乘,这样只需要N + N次,最后的结果是完全相同的
2D的高斯函数数学上本身就是可以拆分的G(x,y)=G (x) × G (y)
看这个图可以方便理解,首先在水平方向计算贡献,同样会在垂直方向计算贡献,两者相乘,相当于把水平的sum_Res,按照垂直的结果做一个乘积,也就是向上/下sum_Res会逐渐减小,最后形成了沿中心向四周逐渐变淡的效果,最后的sum_Res是一致的
逐渐增长的尺寸Progressively Growing Sizes
对于原本N*N的尺寸,做N’ * N’ * count次(N’ < N)采样,每次采样间隔为2^i(i从0开始),这样就是用一个越来越大的filters过滤count次
更大的filters可以除去低频信息
离群值删除Outlier Removal
使用filter处理一些过亮 / 过暗的噪点时会有问题,过亮的地方会更亮,解决方法就是在filter之前先去除过亮 / 过暗的噪点,如何定义这个outlier边界呢
- Detection探测:对每个像素都取一个指定范围,计算范围内的均值和方差,如果当前的像素在 均值 +- 方差的范围外,则判定它为Outlier
- Clamping限制:将这个Outlier噪点值限制到 均值 +- 方差 的范围内
第14章
Spatiotemporal Denoising Solution 时空降噪方法
Spatiotemporal Variance-Guided Filtering (SVGF)时空方差引导滤波
它不仅利用Joint Bilateral filtering的思想,考虑了spatial上的深度,法线,颜色,分别计算权重,也利用temporal accumulation的思想计算时间上差异
深度:
- exp(x)是返回以e为底的指数次方,由于指数是-x,则x越大结果越小
- 分子部分是两者的深度差值,
- 标准差用来控制指数衰减的快慢的参数,
- e避免分母为0和避免最后的数值太大,
- (深度的梯度(沿着法线方向)* 两点间的距离)避免错误判断,例如对于侧向面观察深度差异大贡献小,但同面理应贡献大,所以应考虑的是A和B在平面法线垂直方向上的深度变化
欧拉数 e
pai ~= 圆周/直径d,古人根据 外切与内接多边形的周长可以构成的估计值的取值范围上下限,来推导,它可以作为很多领域的常数
e同样类似,e欧拉数 ~=2.718……,是无理常数(无限不循环)
比如极限中:lim n→∞ (1 + n/1 )^n,当 n 趋向于无穷大时, (1 + n/1 )^n趋近于e
比如在指数函数中被作为底:EXP:单调递增,且增长率越来越快
法线:
两个点法线向量求一个点积,角度越大值越小,点积结果越小贡献越小,但是结果有可能是负值(夹角 > 90度 < 180度),使用max()把负的值给clamp到0
标准差用来修改点乘结果变化速率,越大变化率越快
颜色:
- exp(x)是返回以e为底的指数次方,由于指数是-x,则x越大结果越小
- 分子部分是两者的颜色差值,
- e避免分母为0和避免最后的数值太大
- 和Outlier Removal思想类似,为了避免不正确的采样(比如采样到一个噪声过亮点),利用中心点的标准差,来获得正确的贡献
- 时间累计(精准计算):filters范围下求出本帧variance方差,和< i的variance混合,获得正确的variance
- 那么当P点的variance过大时,让贡献值降低(分母越大,值越小)
其他过滤方法
Recurrent AutoEncoder (RAE)循环自动编码器
是深度学习模型,它结合了自动编码器和循环神经网络的特点,将G-buffer和noisy图输入,将temporal的结果累积起来
AutoEncoder,是一个漏斗形的结构,形状很像一个U字形,因此也可以称之为U型神经网络,每层都有往返的链接,因此可以复用上一帧遗留下的信息而不是通过motion vector查询
Anti-Aliasing抗锯齿/反走样 技术
当采样的分辨率不足就会出现锯齿
Temporal Anti-Aliasing(TAA) 时间域抗锯齿
像素每帧采样一次1SPP,同时会利用之前帧的采样结果,但在每一帧中,采样点位于像素内的不同位置(不随机采样,随机的效果不一定好),例如会在一个像素中指定的4个位置依次循环
其效果与在当前帧内增加样本点的效果一样甚至更好
在静止情况下我们是在一个像素里找sample的结果并复用上一帧中的样本点的结果
在运动场景中,当前帧几何的位置通过motion vector找到上一帧中对应的位置,并复用其结果
MSAA VS SSAA:
SSAA:
- 提高采样分辨率:比如宽高分辨率分别提升为原来的2倍,相当于一个像素分解为4个像素,每个像素都要做原母像素相同的操作,因此要将color和depth缓冲区扩大到原来的4倍
- 渲染所有网格:有N个网格,在渲染每个网格时,检查每个像素,执行覆盖性测试(是否在三角形内)、深度检测、计算着色
- 降采样:在所有网格渲染完成后,每4个像素颜色混合,作为母像素颜色
- 性能:因此每个子像素都要被每个覆盖的网格着色一次,计算量大,内存也要增多,因此整体效率很差,但效果更好
MSAA:
- 提高缓冲区大小:将color和depth缓冲区扩大到原来的5倍(1个中心采样点 + 4个子采样点)
- 测试:在渲染每个网格时,检查每个像素的每个采样点,执行覆盖性测试、深度检测
- 着色:对每个至少有一个采样点通过测试的像素计算一次着色(注意这里取的不一定是中心采样点位置计算颜色插值,当中心采样点没有被覆盖时,选择最近且被覆盖的子采样点)
- copy:将颜色cope到通过测试的子采样点中
- 最终颜色:在所有网格渲染完成后,每个像素内所有采样点颜色平均,作为最终颜色
- 性能:每个像素只需要被每个覆盖的网格着色一次,计算量显著降低,内存是一样的,整体效率优于SSAA,但效果次之
Enhanced subpixel morphological AA(SMAA)增强型子像素 形态学抗锯齿
建立在 MLAA(形态学抗锯齿)算法之上,图像方法会先去识别它,然后通过各种匹配的方法(每种形状模式预计算了一张查找表)找到它正确结果的样子
Deep Learning Super Sampling(DLSS)深度学习超级采样
借助深度学习神经网络,将一张低分辨率的图输入最后得到一张高分辨率的输出
2.0版本摒弃了通过神经网络猜测的结果,而是更希望去利用temporal的信息
其中不能使用clamp解决一些问题,因为最终要的是一个增大了分辨率的图,如果此时我们用上一帧的结果盲目的clamping势必会因为一些小的像素的值是根据周围的点的颜色猜测出来的,而且猜测的值很像周围的点,也就是我们得到了一个高分辨率的图但是很糊
因此我们需要一个比clamping更好的复用temporal信息的方案
Deferred Shading(延迟渲染)
传统的前向渲染中,每个通过深度测试的网格都要被光照计算,特别是从远到近处渲染 时,每次都会通过测试并被光照计算,这样会浪费很多时间,因为很多的网格根本不会通过最终的深度测试因此并不需要去计算光照
做两个pass:
- 几何处理阶段:对每个网格不包含光照计算,仅更新每个像素的位置、法线、材质等数据,分别存储在G-Buffer中
- 光照处理阶段:由于上个pass进行了深度测试,因此每个像素被更新为了那些可视网格的信息,仅对可视网格光照计算
一些问题:
- 很难实现 MSAA:
- 如果G-Buffer使用的是1SPP,则当光照处理阶段pixel着色后,由于不知道每个采样点是否通过测试(覆盖性,深度,模板),因此不知道应该将颜色copy给哪些sample
- 可以通过等量SPP获得sample测试结果,由于延迟渲染所以此时不会计算颜色,由于采样点最终也不会调用fs专门计算颜色,因此不应该存储它们的除去覆盖性外的数据,仅记录中心采样点的
- sample颜色应该在pixel着色后copy,由于pixel仅保存(以中心样本点)可视像素信息,那么所有的sample都会被赋予相同的颜色信息,也就是忽略了遍历每个网格时具体的覆盖情况(被哪个网格覆盖)被更新的那个颜色
- 如果想要支持MSAA,一种方法时把所需的几何信息记录下来,或者使用 TAA或者是imaged based AA来解决
- 如果G-Buffer使用的是1SPP,则当光照处理阶段pixel着色后,由于不知道每个采样点是否通过测试(覆盖性,深度,模板),因此不知道应该将颜色copy给哪些sample
- 透明物体渲染复杂:
- 因为延迟渲染只计算了离视野最近的物体,所以如果透明物体在前面就仅渲染透明物体,忽略了后面的物体
- 正向渲染与延迟渲染结合:先使用延迟渲染处理场景中的不透明物体,禁用深度写入,按照从后到前的顺序对透明物体进行排序,再使用正向渲染来处理透明物体
- 增加带宽:用额外的大量存储空间来存储几何信息
Tiled Shading平铺着色
虽然利用Deferred Shading可以仅对可视网格计算光照,但是这些网格仍要遍历所有的光源进行计算,很多情况下并不是每个光源都能影响到这个片段(点 / 面光源),因此仍做了很多无用的光照计算
- 将屏幕分成了若干个小块,每个切出来的小块对应场景中3D的区域
- 对每个面光源或点光源计算出立方体 / 球体的覆盖区域
- 在像素着色时,会找到对应场景中3D的区域被哪些光源覆盖,只会用这些光源光照计算
Clustered Shading集中着色
我们不仅将屏幕分成了若干个小块,还要在深度对其进行切片,因为如果只分成若干个小块区域的话,区域内的深度可能会十分大,光源不一定会对根据深度细分后的网格有贡献,因此排除了更多的不必要光源
Level of Detail (LOD)多层次细节
根据物体与相机的距离,动态地调整物体的细节程度,从而优化渲染场景性能的技术,LOD的难点在于不同层级之间的过渡,可以使用blending的方法实现手动平滑过度
- mip-map texture的多级渐远纹理,不同分辨率的纹理
- Cascaded shadow maps级联阴影映射,不同的SM分辨率
- Cascaded LPV级联式线性参数变化
- geometric LoD,顶点数量数量不同,高模和低模