Volumetric Path Tracing on GPU
我每次都以为自己以后再也不会写渲染了,实际上渲染总是如影随形
\text{0. Volumetric Path Tracing}
这个我想我也不用多说了,请出门左转去年的CSE-272 notes
\text{1. Wavefront Path Tracing}
了解一点儿CUDA编程的都知道,CUDA是不支持虚函数的。实际上,就算我们想办法逼它支持,无论采用什么方案,由于执行的代码是不一样的,总会
不可避免地存在线程分歧。
这就是为什么(以下简称WPT)的论文标题叫做"Megakernels Considered Harmful"。如果我们用一个大核函数把整个着色都做了,由于材质计算的高度分歧,会严重损害性能。
所以WPT的想法很简单:把不同的材质计算分到不同的小核函数里。这样,每个核函数只负责一个材质的计算,不会出现分歧。类似的思想同样可以用于其他可能存在多态的地方。
在原始论文中,分为3个阶段:
-
Logic阶段,这一部分是一个大核函数,负责结算路径贡献,NEE采样,以及根据路径打到的材质类型分发到下一阶段小核函数。
-
Material阶段,这一部分是一堆不同的小核函数,负责计算散射及采样,同时分发到下一阶段小核函数。
-
Extend阶段,这一阶段是两个小核函数,一个负责计算所有的路径求交,一个负责计算NEE路径(也就是shadow ray)求交。
我们如果仔细思考VPT的逻辑,会发现它可以用于这个框架中。第二阶段刚好就可以用来计算相函数的散射,因为本质上说相函数散射和BSDF其实可以在VPT框架下统一。
而第三阶段我们可以把原本的求交变成tracking。因为tracking是不会改变光线方向的。
这样,我们就可以把VPT的逻辑移植到WPT框架下,从而实现VPT on GPU。
但是,这样就会导致整个Extend阶段的分极其严重(均匀介质的tracking要一个while,而使用null scattering方法的tracking还要再嵌套一个while),计算非常贵。
对此,很自然地想到可以所有进入Extend阶段的光线按照某种编码(这个方法很多,比如组合了起点和方向的莫顿码编码)进行排序,这样排到一起的光线空间上也接近,求交情况也接近,可以减少分歧。
事实证明,这种方法对于普通的求交很有效,但是在考虑到tracking的时候,由于tracking本身涉及采样,就会带来分歧,这也是个很大的问题。