著名的渲染方程并未将传播路径中的介质考虑在内,因而无法处理雾、牛奶等物质,也不能算出我最喜欢的丁达尔效应。本文讨论带有吸收、散射等性质的介质中的光线传输方程,以及基于它的路径追踪算法。

光线传输方程(LTE)

原始的渲染方程是:

而带介质的版本就装逼多了:

其中各项的含义会在后文中逐个解释。

吸收与外散射

考虑一束方向为的光在空间中的点因介质吸收而减弱的情形,若衰减的比例仅与这一点的介质性质以及光束本身的方向、波长有关,那么衰减量为:

其中是单位距离被吸收的光强比例,表示这束光进入该传播距离微元的方向是,这和BSDF所使用的“入射”“出射”符号习惯是一致的。容易证明,一束从处传播到处的光剩下的辐射亮度比例为:

除去吸收,介质也可能将光散射到其他方向,从而造成光强的衰减,这种散射称为外散射(out-scattering)。单位距离因外散射而损失的光强比例记作,在只考虑外散射时,有:

既然吸收和散射都会使光减弱,且具有统一的定义形式,不妨将它们合起来,称为衰减系数(Attenuation Coefficient):

另外,外散射与衰减的比例被称为反照率(albedo),没错,就是BSDF里也常见到的albedo:

利用可以计算出一束光在穿过一段介质后还剩多少,剩余量和一开始的辐射亮度之比称为透射比,记作

自发光与内散射

介质本身可能会因为内部的一些物理/化学过程而称为光源,我们将一束光在介质中传播单位距离后因介质自发光而增加的光强记作,即若仅考虑介质自发光,那么:

在外散射中被散射到其他方向的光理所当然地会增强其他方向的光的强度,这种增强叫做内散射。不同方向上的散射量也是不同的,这一分布与介质性质有关。对一束方向为的光,设它被散射掉的部分为,那么方向上的密度为:

被称为相函数(Phase Function)。

光在介质中传播时可能因介质的自发光和内散射而增强,我们把单位距离增加的辐射亮度记作,即:

根据上面对自发光和内散射的讨论,易知可以通过下式计算:

从出射到入射

到目前为止,一开始放上的大坨公式中除了第二个(用来计算)外,其他的都已经在上面的一系列定义中给出了。设是从的射线与场景的第一个交点,在普通版本的渲染方程中,辐射亮度不会在空间传播过程中衰减,因而有;而在有介质的情况下,我们需要把传播过程中光与介质发生的所有交互都纳入计算中。首先是被吸收和外散射导致的衰减:

然后在传播过程中的每一点,都会因为自发光和内散射而得到一些增量,且这一部分增量在后续的传播中也要受到吸收和外散射的影响:

上得到的增量在传播路径上积分,再加上上面的,就得到了

其中间的距离。

相函数

本文仅考虑介质是各向同性的情况,即可以被简写为,其中是入射方向和出射方向间的夹角。根据能量守恒,必须满足:

据此,最为平凡的相函数——将入射光均匀散射到所有方向的相函数,是将常数1在上归一化后的结果:

1941年,Henyey & Greenstein提出了一个能够仅用一个参数就很好地拟合现实中许多物质测量结果的相函数公式,称为HG函数:

其中是反对称参数(asymmetry parameter),可负可正。越大,介质越倾向于把更多的光散射到和相近的方向。

路径追踪

框架

要将这一大坨LTE转换为可以用蒙特卡洛方法来估值的形式,还要融入MIS等采样技术,就需要把LTE细致地分解开来。首先我们约定:用表示表面(其实也就是不同介质的分界面)上的位置,用表示介质内部的位置,于是就有了完全不同的含义。在这一符号约定下,LTE变成了:

此时,我们将表面上某点的出射光分解为自发光和散射光:

其中表示点散射其他入射光而产生的出射光,其定义为:

由于介质的参与,的计算相当不平凡。为了书写简便,后文不再列出不存在时的情形(即LTE中的“”)。现令:

则:

于是也可以对应地分解为两项:

对应的估计量是:

是所谓的直接照明项,和前文一样使用MIS技术来采样,只不过计算辐射亮度时都要乘上一个透射比罢了。的采样则要复杂一些,因为它的里面出现了介质发光和内散射产生的增益。

间接照明

在计算时,设想我们用概率密度进行BSDF采样,选取了入射方向,且存在(不存在的情形更加简单,因此这里略过),那么的估计量是:

要计算,我们首先需要在线段上以概率密度采样点,然后根据的定义:

的计算又涉及到对相函数进行重要性采样。设概率密度函数为,采样得到的方向为,则:

在形式上一样,其估计量的计算也完全相同,这里就不再赘述了。

透射比

根据定义,有:

因此,我们可以在中以概率密度函数选取,然后令:

路径追踪算法通常把设置为1。如果是在均匀介质中,那么处处相等,可以这样计算:

小结

总结上面的讨论以及过去MIS的文章(用来计算,就得到了以下的一系列估计量,其中涉及到采样的地方都将采样的概率密度和随机变量标注在式子后方:

实现

实现见Atrc中的VolumetricPathTracer。随便画了点东西:

此外,我现在有点不知道该如何处理室外场景中雾和太阳光这样的光源的关系,后面再慢慢探究吧。