SSGI Implementation Summary

pipeline

Alt text

代码目录

  • ssgi_common.hlsl 一些ssgi和ssgi_cs的共用函数,比如对gbuffer的处理等
  • ssgi.hlsl 非compute shader实现的pass
  • ssgi_cs.hlsl compute shader 实现的pass
  • monte_carlo.hlsl 关于mote carlo importance sampling的一些utility函数实现
  • ray_cast.hlsl ray marching的实现,包括linear和hi-z
  • ssgi_spatial_filtering.hlsl ssgi denoising的spatial实现
  • ssgi_temporal_filtering.hlsl ssgi denoising的temporal实现

generate hi-z & hi-color mip map

用一个compute pass 生成 一张1/2 resolution(考虑ray marching的性能)的 depth 和 deferred shading 结果的多 mip level 贴图。

  • hi-z depth map 每四个像素计算最小的depth存入下一个mip level的对应像素 Alt text 看了ue的源码里有ClosestHZB和FurthestHZB,一开始不太理解,后来看到别的方案才明白过来,他们的depth图应该有存最小的几个depth,然后在求里面的最大最小(还未验证)。 Alt text
  • hi-color map Alt text Alt text 原理是根据采样点的linear_depth和四个点最小的linear_depth差值来作为权重对color做filtering.

tile classification

就是希望通过一些前期的预判减少实际ray marching的无用rays.

ray marching

分别对于diffuse 和 specular 进行不同的ray marching算法,ray marching提供最大的rays num和steps的配置。

importance sampling

跟采样相关的实现都放在monte_carlo.hlsl.

diffuse

  • sampling 通过rendering equation可以得出,diffuse使用cosine分布的importance sampling是比较合适的 Alt text 为了使得结果更快的收敛,对一开始的单位圆盘随机采样的结果乘以了一个小于1的bias,使得更多的往normal方向采样。 采样得到的结果就是light direction.
  • rendering Alt text cosine sampling最后计算lighting的时候,需要把所有采样到的color求和除以N,然后乘以当前材质的albedo,这个放到最后apply to final 的时候做。

    specular

    Alt text
  • sampling 分两种情况
    • roughness < 0.1 基本近似于镜面反射,所以直接调reflect函数计算反射方向
    • roughness >= 0.1 使用的是visible normal GGX importance sampling来采样得到half vector的方法。 http://jcgt.org/published/0007/04/01/ Alt text 大致原理是根据normal的tangent space下的view vector方向做投影,然后在投影平面区域做均匀随机采样,再映射回去
  • rendering Alt text 每个采样到的color要乘以fresnel项和G_SMITH_L项再除以N才是最终的rendering result,这个放在ray marching的时候计算。

doubts

这里的采样结果除以的N都是hit==true的点的个数,这个就会造成一个问题就是rays越多越亮,使用总发射的rays个数整体又会太暗,而且感觉也有点不合理,所以这里是有点疑惑的。

before ray marching

关于screen space 和 view space 下的插值换算需要搞搞清楚,要做perspective correct interpolation,不然之后的ray marching 计算交点会有问题。 Alt text chrome-extension://cdonnmffkdaoajfknoeeecmchibpmkmg/assets/pdf/web/viewer.html?file=https%3A%2F%2Fwww.comp.nus.edu.sg%2F~lowkl%2Fpublications%2Flowk_persp_interp_techrep.pdf 简单的说就是

  • 屏幕空间的uv插值的scale和view space下的不一样,如图中的s和t
  • 屏幕空间的uv线性插值并不等于view space下的linear depth线性插值,是linear_depth倒数的线性插值

diffuse linear ray marching

diffuse为了性能考虑,且diffuse不需要很精确的hit result,所以采用view_space下linear ray marching的方式。

计算ray的view space下的起点,终点,步长

给定一条ray的方向

  • 先根据max_ray_trace_distance, camera的near plane distance 和 far plane distance计算出ray的终点
  • 然后计算ray的终点是否超出camera frustum的范围,如果超出要clip到frustum的边界 注意这里的clip scale需要做perspective-correct interpolation
  • 最后根据steps num算出每一步的步长

    linear ray marching

    linear的算法比较简单,就是在view space下每一步走一个固定的步长,通过比较每一步的depth和hi-z采样得到的depth来判断是否打到物体。
  • 和 camera look-at 相同方向的 ray 如果ray的depth比hi-z采样得到的depth大超过一个thickness threshold就算打到。
  • 和 camera look-at 相反方向的 ray 一般刚开始的时候ray的depth都比hi-z depth小一些,所以当ray的depth比hi-z depth大且在没有超过一定threshold的就算打到。
  • 走的越远,mip map level越大 越远会在更大的范围上取color,所以相应的求交的范围也越大。 Alt text diffuse ray marching的结果

specular ray marching

specular 因为需要更加精确的hit result,所以采用hi-z ray marching的方式。

计算ray在screen space下的一些数据

主要是根据ray的world space下的方向计算起点和一定步长下的一个终点的screen space uv 和 linear depth,然后根据perspective-correct interpolation对ray marching的点进行插值。

hi-z ray marching

  • principle Alt text Alt text 大致的原理是根据是否hit来不断增大或者缩小hi-z texture的mip level.
  • code Alt text 重点解释下是如何实现每次只前进一个pixel(不同mip level的pixel大小不同) Alt text Alt text Alt text
    • 先根据当前mip level计算出resolution是多少
    • 再根据screen space的ray方向将当前点挪到当前pixel的corner上 eg. u<0, v<0, 就是归到左上角去,于是cross_step = (0, 0), cell_id就是左上角的点
    • 再根据screen space的ray方向计算一个挪动到下一个pixel的offset值
    • corner加上一个offset,然后除以screen direction取u,v中最小的步长得到下一步应该走到哪里
    • 得到了下一步的uv,再根据perspective-correct interpolation计算下一步的linear depth

denoising

chrome-extension://cdonnmffkdaoajfknoeeecmchibpmkmg/assets/pdf/web/viewer.html?file=https%3A%2F%2Flink.springer.com%2Fcontent%2Fpdf%2F10.1007%252F978-1-4842-7185-8_49.pdf 参考的是NVIDIA Real-Time Denoisers library (NRD) 里的ReBLUR算法的两步 :

  • REBLUR_Diffuse_PreBlur.cs.hlsl
  • REBLUR_Diffuse_TemporalAccumulation.cs.hlsl

    spatial filtering

    主要作用是将一些outliers弱化。
  • 8个采样点满足每一帧做随机旋转的poisson分布
  • 加权的权重是一系列因素的合集
    • view space 上的几何权重
    • 是否在屏幕内
    • screen uv 偏移的guassian权重
    • normal
    • 对于specular的材质还有roughness(我们的specular暂时没考虑spatial filtering)

temporal filtering

diffuse

  • 判断上一帧是不是在屏幕内
  • 判断当前帧的物体上一帧有没有被遮挡 之前用过normal做判断发现会在边缘点闪烁,所以改用roughness 实际NV的实现用了别的方式,但是目前roughness效果也还可以
  • 对history采用catmullrom的算法作filtering
  • 根据当前像素temporal累计的帧数进行累加,最多64 其实本质是求平均

specular

目前采用和diffuse一样的算法,但累计的帧数要少一些,diffuse是64帧,specular是16帧 当然对变化比较快的地方,会有一点lag, 但目前的场景感觉还可以。 之后可以考虑用NV的两种方案做下改进。

apply to final

  • diffuse 和 specular的结果叠加到原来deferred shading的结果上
  • diffuse项要乘一个albedo, 是要把importance sampling的结果求rendering的结果

future work

性能上

  • color resolve 之前resolve的方案是把多个ray的hit uv做平均,觉得不是合理,所以暂时舍弃。 但是之前有结果显示,resolve对于性能的提升是比较大的,毕竟复用了周围pixel的rays. 之后会考虑把多个ray的hit uv都保存下来,再加上importance sampling等计算看下结果。
  • compute shader 中间也试过把ray marching的步骤改成compute shader来实现,发现结果并没有很好。 虽然有一点提升,但结果很受thread group size的影响,这个在不同配置的电脑上是不是也会不一样也有待验证。 所以现在基于debug的便利性和考虑所有配置的适配性还是用vertex, pixel shader去实现。 denoising的pass也可以改成compute shader都试一试。

denoising

https://github.com/NVIDIAGameWorks/RayTracingDenoiser/tree/master/Source 现在的denoising只是借鉴了NV实现的两步,但是NV REBLUR的方案性能上也是比较费的。 这个之后有时间要把NV REBULR,SVGF包括shadow去噪的方案再好好实现下,之后可以直接用在RT或者其他GI算法的去噪上。

Copyright © tingxia.top 2021 all right reserved,powered by Gitbook该文件修订时间: 2022-10-05 11:25:14

results matching ""

    No results matching ""