一张 WWDC 幻灯片

之前的 blog 里提到过,尽管早有愿望学 ray tracing,但 2018 前半年总提不起兴趣动手。六月 Apple WWDC 2018 里关于 ray tracing 的 session 成为我第一次真正接触 ray tracing。望着讲台上削减至极的幻灯片和 speaker 超快的解说,我想这似乎并不难,大概下周给同事总结 WWDC 时就可以自己解释这个问题。

实际上到现在过了十个月,才能说大致理解了这张幻灯片的数学原理。一个简单的 demo 固然能推进学习的进度,但是也可能引入误解。

渲染方程

上篇《 Wavefront OBJ 与 Monte Carlo 》第一次尝试总结对 ray tracing 的理解。其中以下面的积分式求 radiance (后面称该积分式为,其中 n 表示积分层数):

但根据渲染方程到达 camera 光线的 radiance 并非,而是:

这就是渲染方程的 light transport equation 形式。只是整个 LTE 中的单个 term,甚至没有明确的物理意义和常用名称。一般将其理解为光源经过 n 次反射/折射后对最终 radiance 的贡献。例如 n 取一时表示光源直接射入 camera,取二表示 direct lighting。

也就是说,上篇 blog 将直接作为 Monte Carlo 方法的求解对象的分析有些粗糙,需要修正为更严密的解释。

随机过程与「物理模拟」

在应用 Monte Carlo 方法分析之前,先说一下 Monte Carlo 方法的随机过程和 ray tracing 物理意义的关系。

当用简单例子 —— 比如说一元函数 —— 来说明 Monte Carlo 方法时,很明显会把它理解为一个抽象数学工具。把它应用在 ray tracing 问题时却容易误认为 Monte Carlo 方法的 sampling path 在模拟物理光线。如果在分析 ray tracing 问题之前没有把「path 不是光线」这个座右铭刻在脑子里,思维很容易走入歧途。

之所以 path 容易被误认为在模拟光线,是因为二者有些似是而非的相似性。最为显著的一点是,在定义渲染方程时,确实是以光线的物理特性为基础。但是最终定义得到的 LTE 的积分形式表明 radiance 的分布达到了 equilibrium 状态。这是统计上的确定状态,单条光线的特性已经被抛弃。之后对这个积分式采用的 Monte Carlo 方法是一种纯粹人造的随机过程,path 是纯粹抽象的随机取样。为了更准确的强调这点,本文描述的这种 Monte Carlo 求解 LTE 的方法不再被称为 ray tracing,而是叫 path tracing。

这里要提到的关于 Monte Carlo 容易被误解的最后一点是 estimator 和积分形式的对应和区别。Estimator 是随机变量,其数学期望等于它所对应的积分式的值。因此 estimator 和积分形式绝不能同时出现在一个公式中。不同随机过程产生的 estimator 也不能在一起运算。看起来很愚蠢,但我不知道反复卡在这个误解上多少次了。就在写这篇 blog 的过程中都曾经把两种形式写在一个式子中。

忽略光源位置的 Path Construction

回到之前的问题:需要通过 Monte Carlo 方法求解的是整个 LTE,而不仅是单个

在 Monte Carlo 方法中只要取样足够多,最终结果的正确性和 path 的构建方法没有关系。不妨先讨论在构建中完全不考虑光源位置,也就是单纯依靠 reflection sampling 的方式。Reflection sampling 可以采用任何随机概率分布,比如 uniform sampling,当然更常见的做法是根据 BRDF 做 importance sampling。

根据上篇 blog 中的 estimator 可以推导出 LTE 的 estimator 为:

根据常识可以假定自发光物体表面的为零 —— 光源本身不反射任何其它来源的光线。所以构建过程遇到第一个自发光物体就结束。并假定在光源之前的遇到的所有表面点的都为零 —— 普通材质不发光。在这些条件下,每条 path 的 LTE estimator 值只剩下一个 term:

其中 c 表示遇到光源时的路径长度。代码实现可以给 c 设置上限,达到上限依然没有遇到光源就认为这条 path 的 LTE estimator 为零。由此可以看到仅用 reflection sampling 构建 path 时上篇 blog 的结论依然成立,仅仅是原来的 n 被意义更加准确的 c 代替。

考虑光源位置的 Path Construction

但是,仅仅依靠 reflection sampling 构建 path 与光源相交的几率很低,结果的收敛速度很慢。因此大多实现在构建时会将最后一段 path 的终点取在光源表面上。这样的方式中 path 不是随机遇到光源终止,而是被「强制」结束,也就是说 LTE 不再作为整体在 path space 中被随机采样,只能为每个执行独立的 Monte Carlo 过程来分别近似积分。因此虽无直观的物理意义,但仍是 path tracing 中的重要概念。

每个的 estimator 如下:

这里的表示物体表面 reflection sampling 的概率分布。表示最后一段向光源表面取方向的概率分布。如果在表面积为 A 的光源上做 uniform sampling,则有:

每个的 estimator 应该由不同而且相互独立的 Monte Carlo 过程取得,各自收敛的数学期望近似值才可以相加。但在实际工程中,通常用下面的近似式作为一个整体的 estimator。

这里的「取巧」之处在于的 estimator 前 n-1 个采样点和的 estimator 的采样点相同,在本该分别采样的多个独立随机过程中引入了 correlation。但是通常认为这对结果的影响可以忽略。其 path 构建过程相当于从 camera 发出的 path 每次遇到物体表面就随机产生两条 path,一条强制射向光源表面上的随机点,另一条通过 reflection sampling 而得。

回顾和比较

经过上面的分析之后,可以看到仅仅依靠 reflection sampling 的方法数学上更简单,实现也更容易。所以有些 ray tracing 的介绍材料 —— 比如《 Ray Tracing in One Weekend 》—— 就采用了这种方式。但这种方式存在一个陷阱,就是容易让人误认为 Monte Carlo 方法是物理模拟。一些材料出于「形象化」考虑也确实如此误导解释。WWDC 的 demo 没有采用这种方式,我读过其代码之后第一件事就是误打误撞把它改成了只有 reflection sampling 方式,也是潜意识里向「物理模拟」靠拢的体现,这个思路可能歪打正着写出基本功能,但要想进一步改进代码就会缺乏理论基础。

考虑光源位置的 path construction 是高级 ray tracer 的通常做法。它的难点在于实现的近似简化。实际代码往往不会真正独立地执行多个随机过程,而是如上所说通过共享随机采样用一个随机过程近似多个 Monte Carlo 过程。本来多重积分用 Monte Carlo 方法近似就是比较难理解的过程,再把多个独立的 Monte Carlo 过程近似成一个随机过程就更增加了难度。WWDC 的 demo 采用的基本是这种方法。但是在材质和光源上都做了进一步简化。特别是光源采样时完全忽略了对的处理。所以将其改成只采用 reflection sampling 方式之后和原来的 demo 并不等价。在理解其中的数学解释之前,渲染结果的差异一直让我困惑。我曾经以为 WWDC 的 demo 起到了带初学者入门 ray tracing 的作用,其实它的用途仅仅是给真正理解 path tracing 的老手展示 GPU 加速功能。

留下评论