这篇笔记仅仅是笔者在学习中的一些总结,并无法引导读者从零到一学会 Rendering,但其含有进一步学习 Rendering 的一些必要的知识,所以如果作为读者的你已经对渲染有了一些了解,不妨可以读一读看,或许能找到什么有趣的部分。

Surface Introduction

PBRT 中对 Path Tracing 的引导实在太过精彩和重要,以至于我一定要把它们记录下来。

第零块积木是 Radiometry,其实对于 Radiometry 也有很多可以讲的(比如许多人从未提到的,其作为一个物理量,需要一些物理的视角,比如人们通常会使用的 surface integral),不过咱们暂且跳过。

第一块积木是 Monte Carlo Integration,即

\[\int_{D} f(x) \, \mathrm{d}x \xleftarrow{\text{can be estimated}} \dfrac{1}{N} \sum_{i = 1}^{N} \dfrac{f(X_i)}{p(X_i)}\]

如此这般,我们可以计算一个积分正确的值。而 Monte Carlo Integration 最重要的是,其计算能力独立与 $x$ 的维度,只要我们能正确地计算 $p(X_i)$ 和 $f(X_i)$ 即可。关于 Numerical Integrator,还有 MC 之外的很多很多方法,它们在低维度下的收敛速度很可能高于 MC。而 MC 的好处是,对于任意维度,收敛速度都是 $O(N^{-1/2})$,并且不依赖被积函数的光滑性质(事实上,integrand 基本都不是光滑的),想要得到更多信息的读者请阅读 Veach 论文的第一章。

——于是,这块积木被放在了 Radiometry 上

\[\begin{aligned} L_{\mathrm{o}}\left(\mathrm{p}, \omega_{\mathrm{o}}\right) &=\int_{\mathrm{S}^{2}} f\left(\mathrm{p}, \omega_{\mathrm{o}}, \omega_{\mathrm{i}}\right) L_{\mathrm{i}}\left(\mathrm{p}, \omega_{\mathrm{i}}\right)\left|\cos \theta_{\mathrm{i}}\right| \mathrm{d} \omega_{\mathrm{i}} \\ & \approx \frac{1}{N} \sum_{j=1}^{N} \frac{f\left(\mathrm{p}, \omega_{0}, \omega_{j}\right) L_{\mathrm{i}}\left(\mathrm{p}, \omega_{j}\right)\left|\cos \theta_{j}\right|}{p\left(\omega_{j}\right)} \end{aligned}\]

我们有了对最简单的一个积分的 MC 的视角。但是如此就结束了吗?还早。我们还需要 LTE,才能构造出一个正确的 Integrator。这个公式不是终点,而是物理渲染的起点。

众所周知,Rendering 是在解方程。但是解了个什么方程?方程的解和我们输出的图片有什么关系?这都是需要探讨的 non-trivial 的问题。

下一个视角是,我们渲染的过程,就是求解空间中 $(n + 3) \mathrm{D}$ 场的过程,$n$ 可能为 $2$,即球面坐标的 $\theta, \phi$。其为 $L(\mathrm{p}, \omega)$。而描述这个场的方程就是 LTE,当然,也可以是一些其他的东西(笑)

这里其实可以细化一下,在 Veach 的文章中,我们有所有物体的表面为一个空间 $\mathcal{M}$(最简单的情况,就是一个平面)。虽然我不懂测度论也不懂几何,暂且就将其理解为许多点组成的集合吧。但是光有 $\mathcal{M}$ 很明显还不够,因为它并不能刻画光线的朝向。所以我们还需要一个更广的空间。即

\[\mathcal{R} = \mathcal{M} \times \mathcal{S}^2\]

暂且将 $\mathcal{S}^2$ 理解为一个单位球。我们所有的参数都在这个空间上定义,即

\[f: \mathcal{R} \rightarrow \mathbb{R}^n\]

我们需要这么一个东西。这份 $F$,并不见得是 $L$,即 radiance。它可以是更多的东西(这份考量很重要)。

稍微思考一下,我们可以得出这么一个结论。若两个点 $\mathrm{p}_1, \mathrm{p}_2$ 之间没有遮挡,若 $L$ 代表 radiance,并且没有 volume,那么 $L(\mathrm{p}_1, \omega) = L(\mathrm{p}_2, -\omega)$,这是光路可逆性。

那么,一个基本的 LTE 就出来了,

\[\begin{gathered} L\left(\mathrm{p}, \omega_{\mathrm{o}}\right)=L_{\mathrm{e}}\left(\mathrm{p}, \omega_{\mathrm{o}}\right)+\int_{\mathrm{S}^{2}} f\left(\mathrm{p}, \omega_{\mathrm{o}}, \omega_{\mathrm{i}}\right) L\left(t\left(\mathrm{p}, \omega_{\mathrm{i}}\right),-\omega_{\mathrm{i}}\right)\left|\cos \theta_{\mathrm{i}}\right| \mathrm{d} \omega_{\mathrm{i}} \end{gathered}\]

这是基于单位角的幼年 LTE。

但是各位也许会发现,如果仅仅通过 $L$ 来描述或许太过单薄,因为 $L$ 是不连续的,在很多点上甚至难以定义。比如某平面上某点 $\mathrm{p}$,我们很难定义 $L(\mathrm{p}, \omega)$,因为 $L$ 在该处是不连续的。所以,通常来说,我们会用 $L$ 在其法线上对于 $t$ 的极限来考量该处的 $L$.

\[\begin{aligned} L_{\mathrm{i}}(\mathrm{p}, \omega) &= \begin{cases}L^{+}(\mathrm{p},-\omega), & \omega \cdot \mathbf{n}_{\mathrm{p}}>0 \\ L^{-}(\mathrm{p},-\omega), & \omega \cdot \mathbf{n}_{\mathrm{p}}<0\end{cases} \\ L_{\mathrm{o}}(\mathrm{p}, \omega)&= \begin{cases}L^{+}(\mathrm{p}, \omega), & \omega \cdot \mathbf{n}_{\mathrm{p}}>0 \\ L^{-}(\mathrm{p}, \omega), & \omega \cdot \mathbf{n}_{\mathrm{p}}<0\end{cases} \end{aligned}\]

这个公式初比较奇怪,尽管光路可逆,$\omega$ 是有方向的。

然后,就要开始正式讨论如何解这个方程了,首先,第一步是展开!对,就是最简单的展开。因为注意到我们的 LTE 其实是“递归定义”的。

不过,在展开之前,我们最好还是将其转化为 Surface Integral 的形式,那样会更好理解。

One reason why the LTE as written in Equation (14.13) is complex is that the relationship between geometric objects in the scene is implicit in the ray-tracing function $t(\mathrm{p}, \omega)$. Making the behavior of this function explicit in the integrand will shed some light on the structure of this equation. To do this, we will rewrite Equation (14.13) as an integral over area instead of an integral over directions on the sphere.

(一言以蔽之,比起简化后的 $L(\mathrm{p}, \omega)$,还是求解 $L(\mathrm{p}_1, \mathrm{p}_2)$ 比较合适。比如说,我们想要求解点 $\mathrm{p}$ 的 direct lighting,想要对光源进行积分,我们就有两种积分方式。但是很显然,立体角的积分方式比起表面积分更加不显然,因为其难以描述复杂的几何关系,通常来说都必须转化为对表面积分的形式才能继续运算)

\[L\left(\mathrm{p}^{\prime} \rightarrow \mathrm{p}\right)=L_{\mathrm{e}}\left(\mathrm{p}^{\prime} \rightarrow \mathrm{p}\right)+\int_{A} f\left(\mathrm{p}^{\prime \prime} \rightarrow \mathrm{p}^{\prime} \rightarrow \mathrm{p}\right) L\left(\mathrm{p}^{\prime \prime} \rightarrow \mathrm{p}^{\prime}\right) G\left(\mathrm{p}^{\prime \prime} \leftrightarrow \mathrm{p}^{\prime}\right) \mathrm{d} A\left(\mathrm{p}^{\prime \prime}\right),\]

于是我们就有了这玩意儿。其中

\[G\left(\mathrm{p} \leftrightarrow \mathrm{p}^{\prime}\right)=V\left(\mathrm{p} \leftrightarrow \mathrm{p}^{\prime}\right) \frac{|\cos \theta|\left|\cos \theta^{\prime}\right|}{\left\|\mathrm{p}-\mathrm{p}^{\prime}\right\|^{2}}\]

这是几何项,因为我们考虑的是单位面积,单位面积会平方衰减。

这玩意儿是递归定义的,所以我们可以将其展开,

\[\begin{aligned} L\left(\mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right)=& L_{\mathrm{e}}\left(\mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) \\ +& \int_{A} L_{\mathrm{e}}\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1}\right) f\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) G\left(\mathrm{p}_{2} \leftrightarrow \mathrm{p}_{1}\right) \mathrm{d} A\left(\mathrm{p}_{2}\right) \\ +& \int_{A} \int_{A} L_{\mathrm{e}}\left(\mathrm{p}_{3} \rightarrow \mathrm{p}_{2}\right) f\left(\mathrm{p}_{3} \rightarrow \mathrm{p}_{2} \rightarrow \mathrm{p}_{1}\right) G\left(\mathrm{p}_{3} \leftrightarrow \mathrm{p}_{2}\right) \\ & \times f\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) G\left(\mathrm{p}_{2} \leftrightarrow \mathrm{p}_{1}\right) \mathrm{d} A\left(\mathrm{p}_{3}\right) \mathrm{d} A\left(\mathrm{p}_{2}\right)+\cdots \end{aligned}\]

这玩意儿就是非常 naive 的展开,没有什么技巧可言。这份展开提供了一种很值得思考的视角,即我们如何拆分这个积分

注意,拆分积分并不是一件 trivial 的事情,需要一些数学的考量。比如我们的拆分大多数时候不能在间断点上进行,考虑

\[\int_a^b{\delta(x - t)} \, \mathrm{d} x\]

就不能随意拆分为 $[a, t]$ 和 $[t, b]$。实际情况中,这份积分可能是在一个闭曲面上的积分,那对于 $\partial D$ 如何积分就需要存疑了。需要注意,Dirac Function 并不是一个在黎曼和勒贝格积分下严谨定义的一个东西。与之类似的,$u(t)$ 也不能直接拆分,比如 $\mathcal{F}{u(t)}$ 如何计算就是一个值得商榷的问题。

Quiz

你将会回答这几个问题

  1. 为什么选择 Monte Carlo 进行积分?

  2. The Rendering Equation 解出了什么函数,这个函数的定义域是什么,这个函数和我们看到的图片有什么关系?

  3. 既然我们解出了 $L: \mathcal{R} \rightarrow \mathbb{R}^n$, 它和我们定义的 $L_i$ 和 $L_o$ 有什么关系?

  4. PBRT 上 LTE 的公式如下

\[\begin{aligned} L\left(\mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right)=& L_{\mathrm{e}}\left(\mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) \\ +& \int_{A} L_{\mathrm{e}}\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1}\right) f\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) G\left(\mathrm{p}_{2} \leftrightarrow \mathrm{p}_{1}\right) \mathrm{d} A\left(\mathrm{p}_{2}\right) \\ +& \int_{A} \int_{A} L_{\mathrm{e}}\left(\mathrm{p}_{3} \rightarrow \mathrm{p}_{2}\right) f\left(\mathrm{p}_{3} \rightarrow \mathrm{p}_{2} \rightarrow \mathrm{p}_{1}\right) G\left(\mathrm{p}_{3} \leftrightarrow \mathrm{p}_{2}\right) \\ & \times f\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) G\left(\mathrm{p}_{2} \leftrightarrow \mathrm{p}_{1}\right) \mathrm{d} A\left(\mathrm{p}_{3}\right) \mathrm{d} A\left(\mathrm{p}_{2}\right)+\cdots \end{aligned}\]

简化后是

\[L(\mathrm{p}_1 \rightarrow \mathrm{p}_0) = \sum_{n = 1}^{\infty}P(\overline{\mathrm{p}}_n).\]

其中 $\mathrm{p}_n$ 可以只采样光源吗?假如除了光源都不发光。比如

\[\int_{A} L_{\mathrm{e}}\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1}\right) f\left(\mathrm{p}_{2} \rightarrow \mathrm{p}_{1} \rightarrow \mathrm{p}_{0}\right) G\left(\mathrm{p}_{2} \leftrightarrow \mathrm{p}_{1}\right) \mathrm{d} A\left(\mathrm{p}_{2}\right)\]

中的 $\mathrm{p}_2$ 可以只放在光源上吗?

并介绍在实际的 Path Tracing 中,我们是如何一一计算其中的积分的。

  1. 为什么我们使用对单位面积积分而不是对立体角积分。

  2. 为什么我们说,$L(\mathrm{x})$ 是一个稳态的函数。

    Hint: Linear Operator.


Surface Implementation

在实现过程中,数学理论是非常重要的,只要还有一点理论没有理解,实现中出现的 bug 就会非常难调。实现相对较简单的 Path Tracing,这些理论就勉强够了。

不过,我们实现中最需要参考的公式是

\[L(\mathrm{p}_1 \rightarrow \mathrm{p}_0) = \sum_{n = 1}^{\infty}P(\overline{\mathrm{p}}_n).\]

$n$ 对应的就是变量中的 bounces,也就是我们的假想粒子与平面交互的次数。这就告诉我们,实现正确的 Integrator,只需要将每一份 $P$ 不重不漏地计算正确即可。

所以,对于每一个 pixel,我们的输出可以理解为一个关于 $P$ 的向量 $[P_1, P_2, \cdots]$,分别对应 direct lighting 等等。如果没有高频的 texture,$P_1$ 大概率是平滑的而 $P_2$ 则很明显需要更多的采样。所以我们的采样可以在很多个 space 中进行。工业上人们可能会倾向于在 Image Space 上进行多重重要性的采样(有对应的论文)。我们也可以有 MIS,即在 BRDF 和 light 上使用带权重的采样策略。我们也可以在 Path Space 上采样,就有了 RESTIR。更简单的,我们也可以在 $P_1, P_2$ 等等选取不同的采样策略(比如增加 shadow sample 会在同样的时间内拥有非常离谱的效果),甚至计算策略(比如如果在 $P_1$ 使用光栅化,$P_2$ 使用 ray tracing,后面更高频的信息我们又可以如何做 approximation?这样是否能更加有效地利用硬件?)。这些分析都必须基于之前的理论基础,否则就会陷入经验的陷阱。

拆分能给人带来灵感。

好了,回到正题。我并不想谈太多的实现问题,毕竟谈起来往往会没轻没重(笑)。

第一个比较蹊跷的地方是继承的应用。虽然大部分学校课程里老师都会避免让学生用复杂的继承(比如 GAMES101 过于简化的框架,尽管是课程定位所致)。但是其存在是必要的。PBRT 中比较值得一提的实现是 Primitive 类的实现,而不管是加速结构,还是一些 Mesh,只要能求交,并且求交后能返回相关信息(比如 volume 的信息,或者材质的信息),就可以看作 Primitive。这其实是一个比较 naive 的想法,但是在一步一步的实现中帮了我很大的忙。听说 PBRT-V4 中为了兼容 OptiX 所做的 template tricks 也很有趣,不过我还没有细读。

第二个比较蹊跷的地方就是 Integrator 的实现,如果没有意识到需要上一个公式,Integrator 就会乱成一锅,关于这点,在后文的 Volume Rendering 部分还会有详细的解释。总之,要解释 Integrator 的正确性,必须从那个公式出发,不重不漏。

当然,实现方面最麻烦的就是调试。Rendering 的调试是出了名的难,而且由于高并行的特性,很多调试甚至很难进行(比如 OptiX 上的调试,基本只能靠 printf)。

不过,我们依然有几个 tricks。

  1. 将 observations 记录下来,列一个表,像侦探一样寻找问题

  2. 构造最简单的场景

    1. 在之前某 render 的开发过程中,我在调试 Environment Lighting 时(彼时普通的 Surface Rendering 还没有被验证,所以出了很多很意外的错误),发现相同场景的输出和 PBRT 完全对不上,甚至只是渲染一个 texture 的输出也和 PBRT 有很大的差距。当初我怀疑了很多东西,是我 Texture 的 2D sampling 实现出了问题,还是说 uniform sampling 我都没有写对,还是说其他什么地方比如 gamma correction出了问题?十个小时以后我才意识到,可以构造两个最简单的场景,分别含有一个球和一个正方体,其环境光照设为 $[1, 1, 1]$ 的纯白色。收敛后,应该并不能看到这个球体和立方体。

      而我们的渲染的结果是,不光能看到球体和立方体,而且立方体表面的颜色还是不同的(这个是其他的 bug),球体没有收敛为纯白色。而设置的背景依然是 $[1, 1, 1]$ 的纯白色。背景颜色的正确提示了我,这可能就是 gamma 校正的问题。后来修复的过程中才确认,是我们将 gamma 校正放在了求平均之前,这就会导致非 consistent 也非 unbiased 的错误的结果。

  3. 尽量使用 assert。这叫做防守式编程,在图形学中尤其管用(笑)。我们可以使用宏程序中每一个需要返回的地方都加上对于 isnanisinf 的判定,甚至可以加上,比如 $\le 1e5$ 的限制,这样会让你在面对许多白点时迅速找到问题的来源。在开发一个渲染器时,我就因为没有找到一个未初始化的变量调整了半天(实际情况会更加恼人,sanitizer 并不一定能解决问题)


Volume Introduction

如果我们不考虑发光介质,则 Volume Rendering Equation(VRE) 如下,

\[L_i(\mathrm{p}, \omega) = T(\mathrm{p}, \mathrm{p_e}) L_o(\mathrm{p_e}, -\omega) + \int_{0}^{t_{\text{max}}}T(\mathrm{p}, \mathrm{p} + t \omega) \mu_s L_s(\mathrm{p} + t\omega, -\omega) \, \mathrm{d} t\]

其中 $T(\mathrm{p}_a, \mathrm{p}_b)$ 定义为从 $\mathrm{p}_a$ 到 $\mathrm{p}_b$ 的透光率(transmittance). 其中 $\mu_s$ 为 scattering coefficient. 而

\[L_s(\mathrm{p}, \omega) = \int_{\mathcal{S}^2} f_p(\omega, \omega') L_i(\mathrm{p}, \omega') \, \mathrm{d} \omega'\]

如果我们要构造 Integrator,依然需要将这个公式展开,并识别出其中的表面项和其中的体积项。那,接下来就是展开的体力活儿

\[\begin{aligned} L_i(\mathrm{p}, \omega) & = T(\mathrm{p}, \mathrm{p_e}) L_o(\mathrm{p_e}, -\omega) \\ & + \int_{0}^{t_{\text{max}}} T(\mathrm{p}, \mathrm{p}') \mu_s \left[ \int_{\mathcal{S}^2} f_p(\omega, \omega') T(\mathrm{p}', \mathrm{p}_e') L_o(\mathrm{p}_e', -\omega')\, \mathrm{d} \omega'\right] \, \mathrm{d} t \\ & + \int (T \mu_s) \int_{\mathcal{S}^2} (f \, T) \int (T \mu_s) \int_{\mathcal{S}^2} (f \, T) \cdots \\ & + \cdots \end{aligned}\]

总而言之,这份结果依然可以表示为

\[L_i(\mathrm{p}, \omega) = \sum_{i = 0}^{\infty} P(\overline{\mathrm{p}}_i)\]

其中 $P(\overline{\mathrm{p}}_i)$ 为一条路径带来的贡献,这份结果最后就是一个矢量和,或者可以看成多项式,然后取 $p(1)$。

于是,在代码实现的时候需要注意,在 for 循环中,bounces 为某个特定值时,只能考虑对应次数 interaction 的路径。比如在 for 循环中不能将 interaction 直接延长到物体表面,因为产生的 interaction 数量不够。这与上文implementation部分中描述的所对应。

好了,大部分问题都解决了,接下来就是如何 sample 了!

首先我们知道,对于其中任意一个循环,我们都是在计算某一个高维的积分,即

\[\underbrace{\int (T \mu_s) \int_{\mathcal{S}^2} (f \, T) \int (T \mu_s) \int_{\mathcal{S}^2} (f \, T) \cdots}_{2i \text{ times}}\]
而考虑到这一整条路径 sample 下来的概率 $P(I_1, I_2, I_3, \cdots, I_i)$ 可以被拆分成一系列条件概率的形式,我们每次只需要考虑在当前这个点 sample 的概率即可,即 $P(I_i I_1, I_2, \cdots I_{i - 1})$. 这就是所谓 Incremental Path Construction.

这里有一点需要注意的。尽管 Monte Carlo Integration 需要 PDF,但是不一定需要获取这个 PDF 的具体的值。比如说,当我们需要采样的东西具有解析解的时候,我们就可以直接在求逆后的 CDF 上做采样。当这个需要采样的东西没有解析解时,我们就可以随意选取采样(比如使用 uniform sampling),这样的结果依然是无偏的。但是当被积分的元素中具有这个非解析的东西,就会产生一些麻烦,因为它依然需要被计算。比如我们最经典的 rendering equation 中(我们只保留变量名)

\[L_o = L_e + \int_{\mathcal{S}^2} f \cdot L_i \cdot \cos\theta \, \mathrm{d} \omega\]

大部分时候,$f$ 是解析的,$L_i$ 是非解析的。我们通常会选择 sample 一些解析的,这样当 PDF 被放在分母时,分子的解析的函数就可以消为一个常数,然后通过递归去求解这个非解析的部分。

这就带来了一个问题,如果 integrand 中有两个非解析的函数怎么办。这就是 volume rendering 需要被单独研究的原因之一。

这时候还是直接把 volume rendering equation 拿出来最清晰(复制一下)

\[L_i(\mathrm{p}, \omega) = T(\mathrm{p}, \mathrm{p_e}) L_o(\mathrm{p_e}, -\omega) + \int_{0}^{t_{\text{max}}}T(\mathrm{p}, \mathrm{p} + t \omega) \mu_s L_s(\mathrm{p} + t\omega, -\omega) \, \mathrm{d} t\]

注意,其中 $T$ 大部分时候是非解析的。而 $L_s$ 也是非解析的。因为他们为解析的情况比较容易考虑,我们需要新的算法来考虑其为非解析的情况。

首先还是来看解析的情况吧。我们说一个 Volume 可以解析求解,是指其 density 均匀。所以其 $T$ 可以解析求解(为了防止有人不知道,这个 $T$ 指的是透光率(transmittance),其为 1 减去一个 Exponential Distribution 的 CDF,$\lambda$ 为不考虑之前的情况,该光线某一处被吸收的 PDF)于是我们就可以以 $T$ 在距离上进行采样,采样出来的 PDF 为 $T/C$,则我们可以消去分子的 $T$,就免去了计算 $T$ 的烦恼(只需采样,无需计算)

既然 $\sigma_t$ 定义为在单位 distance 中发生 interaction 的 PDF,根据现有知识(常微分方程+指数分布),我们知道在 $t$ 处之前发生了 interaction 的概率是 \(P(t) = 1 - e^{-\sigma_tt}\) 所以 transmittance 就是 $e^{-\sigma_t t}$.

顺带,恰好在某处发生的概率是 $\sigma_t e^{-\sigma_t t}$(考虑指数分布的 $\lambda$)。而发生 interaction 之前 $t$ 走过距离的期望(自由程)是 $1/\sigma_t$(因为指数分布具有无记忆性)

而我们就以这个 $p(t) = \sigma_t e^{-\sigma_t t}$ 作为采样的来源,则采样结果是 $t = - \dfrac{\ln(1 - \xi)}{\sigma_t}$

这个结果可能在 volume 内也可能在 volume 之外。

而,其实只需采样无需计算还有一个好处,这个被采样的函数并不需要是解析的。通过一些概率论的知识,我们知道:我们的采样办法不止有 Inverse Method。我们还有 Rejection Sampling, Metropolis Sampling,这两者都不需要这个 PDF 是解析的,可以在线计算,即或许是每采样一次,就对该函数进行一次 evaluate,或许是根本不需要 evaluate(delta-tracking 就是如此)。

暂时并不需要完全了解这一部分,反正结论很清晰

其方法大概是构造一个随机变量,然后让这个随机变量的期望正好等于某个值。在这里有更详细的证明(类似)

嘛,先不着急,我们来看看最暴力的方法,如何用暴力的 Path Tracing 来进行计算。如此我们才能建立从纯平面的 Path Tracing 进化到带体积雾的。

那,我们随便选择一个 $X$ 作为表示距离的随机变量。然后构造我们的 Estimator 为 \(\dfrac{T(x \rightarrow 0)}{p(x)} \left(\mu_s \cdot L_s\right)\) 其中 $L_s$ 被递归计算,那我们只需要考虑前面的 $T(x \rightarrow 0)$。因为 $p(x)$ 已经被解析地算出来了,而 $T(x \rightarrow 0)$ 依然是一个积分,我们就再次对这个积分做采样。 如果只是在每个 estimator 中再 estimate 一维的积分并不会导致有偏,只是不能直接求和,因为还有 $\mathrm{exp}$ 的存在。所以,最显然的方法依然是——我们通过采样,让分母的 $p(x)$ 消去 $T(x \rightarrow 0)$(这个消去的方法甚至有自己的名字),这样我们就不需要担心如何计算它了。

那么问题就来了,如何 sample 这个 $p(x)$。delta-tracking 告诉我们

  1. 既然我们需要使用 rejection method,那么我们首先需要一个上届。

  2. 这个上届如何构造呢?其最大值是可以通过遍历描述 volume 的 grid 来找到

  3. 那么,我们需要什么来 reject?将最大值和实际值之间的差距当成一些虚拟的例子,其会产生 null-scattering,那么可以证明,一方面 null-scattering 能保证结果的正确性,一方面,其能保证 sample 出来的结果满足 $\sigma_t \cdot T$ 的分布(这是 non-trivial 的,但是证明稍微有点超纲了)

\[-\mu_{\mathrm{n}}(\mathbf{x}) L(\mathbf{x}, \omega)+\mu_{\mathrm{n}}(\mathbf{x}) \int_{\mathcal{S}^{2}} \delta(\omega-\bar{\omega}) L(\mathbf{x}, \bar{\omega}) \mathrm{d} \bar{\omega}=0\]

有了 sample 的方法,就只剩下实现了,而只用 delta-tracking 其实是可以正确估计 Tr 的。

(待续)

Appendix

这里是 Ray Space 的补充。Ray Space 相关的知识能告诉我们,为什么我们说 $L$ 是一个稳态的函数。

“$L$ is the equilibrium radiance, so what is equilibrium?”

Ray Space 通常会被定义为 $\mathcal{R} = \mathcal{M} \times \mathcal{S}^2$. 其中 $\mathcal{M}$ 为所有物体表面构成的集合,$\mathcal{S}^2$ 为方向的集合。所以对于该场景中的任意一根,不考虑 volume 的光线,其一定存在于 $\mathcal{R}$ 中。

而 radiance,就是一个 $\mathcal{R}$ 上的函数。其可以定义为 \(f : \mathcal{R} \rightarrow \mathbb{R}\) 而加上 $L_p$ norm 的限制,符合这个定义的函数也可以构成一个空间,叫做 $L_p$ space. 具体的内容我们这里不需要关注,直觉就是 $f$ 的 norm 是有限的。总之就是我们不会处理太夸张的 $f$。这些函数构成一个 Vector Space,因为很显然我们能满足 Vector Space 的各种性质(其实就是我记不住了)。

第一个 operator 是 scattering operator。

operator 是空间内一个东西到另外一个东西的映射,而 Linear Operator 就是线性的映射。具体来说,我们接下来要定义的 operator,是该 Vector Space 中一个函数到另外一个函数的映射

(待续)……