Volumetric Path Tracing on GPU

我每次都以为自己以后再也不会写渲染了,实际上渲染总是如影随形

\text{0. Volumetric Path Tracing}

这个我想我也不用多说了,请出门左转去年的CSE-272 notes

\text{1. Wavefront Path Tracing}

了解一点儿CUDA编程的都知道,CUDA是不支持虚函数的。实际上,就算我们想办法逼它支持,无论采用什么方案,由于执行的代码是不一样的,总会
不可避免地存在线程分歧。

这就是为什么Wavefront Path Tracing\text{Wavefront Path Tracing}(以下简称WPT)的论文标题叫做"Megakernels Considered Harmful"。如果我们用一个大核函数把整个着色都做了,由于材质计算的高度分歧,会严重损害性能。

所以WPT的想法很简单:把不同的材质计算分到不同的小核函数里。这样,每个核函数只负责一个材质的计算,不会出现分歧。类似的思想同样可以用于其他可能存在多态的地方。

在原始论文中,分为3个阶段:

  1. Logic阶段,这一部分是一个大核函数,负责结算路径贡献,NEE采样,以及根据路径打到的材质类型分发到下一阶段小核函数。

  2. Material阶段,这一部分是一堆不同的小核函数,负责计算散射及采样,同时分发到下一阶段小核函数。

  3. Extend阶段,这一阶段是两个小核函数,一个负责计算所有的路径求交,一个负责计算NEE路径(也就是shadow ray)求交。

2. Port VPT to WPT\text{2. Port VPT to WPT}

我们如果仔细思考VPT的逻辑,会发现它可以用于这个框架中。第二阶段刚好就可以用来计算相函数的散射,因为本质上说相函数散射和BSDF其实可以在VPT框架下统一。
而第三阶段我们可以把原本的求交变成tracking。因为tracking是不会改变光线方向的。

这样,我们就可以把VPT的逻辑移植到WPT框架下,从而实现VPT on GPU。

3. Some Optimizations and Problems\text{3. Some Optimizations and Problems}

但是,这样就会导致整个Extend阶段的分极其严重(均匀介质的tracking要一个while,而使用null scattering方法的tracking还要再嵌套一个while),计算非常贵。

对此,很自然地想到可以所有进入Extend阶段的光线按照某种编码(这个方法很多,比如组合了起点和方向的莫顿码编码)进行排序,这样排到一起的光线空间上也接近,求交情况也接近,可以减少分歧。

事实证明,这种方法对于普通的求交很有效,但是在考虑到tracking的时候,由于tracking本身涉及采样,就会带来分歧,这也是个很大的问题。