面向开发人员的体积渲染:基础(下)

本文翻译自Volume Rendering for Developers: Foundations,如有错误,欢迎指正。

从辐射传递方程(Radiative Transfer Equation)到体绘制方程(Volume Rendering Equation)

在本章中,我们将学习控制体绘制的方程。如果你对理论一点也不感兴趣,那么你可以跳过这一章(坚持阅读本课的前四章,它们只是关于实践的)。

光如何与参与介质相互作用并在体积中传播?

大多数书籍和论文在一般渲染和特别渲染参与媒介(介质的复数形式)时使用相同的约定。所以最好熟悉一下这些约定。体积通常表示为小的微分圆柱体(differential cylinders)。观察者从一端向下看这个圆柱体,我们在另一端照射准直光束,如下图所示。我们要寻找的是光束穿过体积后的强度(多少光到达观看者的眼睛)。

在这里插入图片描述

  • 他的光量的技术术语是 radiance ,我们将用字母 L L L 表示。 L i L_i Li 是入射radiance:照在圆柱体上的光束的强度。 L o L_o Lo 是出射radiance:另一端的光量还剩多少。
  • 视图方向表示为 ω \omega ω (希腊字母omega)。在我们的代码中,这是摄影机光线方向。

这是我们的基本设置。我们的窄(准直)光束通过圆柱体可以以四种不同的方式与介质相互作用(假设我们的小圆柱体当然不是空的,而是充满了一些粒子):

  • 吸收(Absorption):部分光线被吸收。我们的光束会减弱。辐射降低。
  • 外散射(Out-scattering):构成我们的窄波束的光子在直接朝向眼睛的方向 ω \omega ω 上行进,然而,它们可能不会到达眼睛,因为其中一些将在另一个(随机)方向上沿着该路径散射。向外散射的光子不再在光束中,因此在这种情况下,它也失去了强度。辐射(Radiance)降低。
  • 内散射(In-scattering):散射还可能导致落在该体积上的一些光沿着我们的光束的路径被重定向。然后,光束获得强度。辐射增加。
  • 自发光(Emission):气体在达到一定温度时会发光。然后电子获得以光子形式释放的能量。这些光子的方向是随机的,但最终,其中一些将沿着光束的路径行进。因此,由于发射,我们的光束的强度也会增加。

重要的是要注意,外散射和吸收都会导致光能损失,而内散射和发射会导致窄准直光束在朝向眼睛行进时获得能量。理解内散射和外散射是同一现象的一部分也很关键:光子与构成介质的粒子“碰撞”。
在这里插入图片描述
辐射率 d L dL dL 沿着 d s ds ds 的变化等于入射辐射率 L i L_i Li 和出射辐射率 L o L_o Lo 在沿方向 ω \omega ω 的点 x x x 处的差。这种辐射率的变化也等于吸收、散射(向内和向外)和发射的效果的净和:
在这里插入图片描述
这不是一个“正确的”方程,但在本章的后面,我们将看到这最终是如何导致所谓的辐射传递方程(RTE)和体积渲染方程(VRE)。但是在我们到达那里之前,我们需要学习吸收和散射系数,比尔定律,和相函数。

吸收、散射和消光/衰减系数

最好在使用吸收(和散射系数)的方程的上下文中介绍它们,但是将方程和这些系数的定义混合在一起可能会有点混乱,所以现在让我们介绍它们。

吸收系数(Absorption coefficient)

吸收系数(absorption coefficient,或吸收截面), σ a \sigma_a σa 表示光在介质中行进的每单位距离被吸收的概率密度(probability density that light is absorbed per unit distance)。吸收系数的单位是倒数距离(即,mm^{-1}、cm ^{-1} 或 m^{-1})。概率密度可以被解释为随机事件(例如,吸收事件)发生在给定点。假设您选择了一个系统,其中1个测量单位代表1米,并且具有吸收系数为0.5的体积。光子在穿过该体积1米后被吸收的概率为0.5。发射1000个光子,并测量其中有多少光子将离开另一侧的体积:“平均”你会得到500个光子。换句话说,在通过这个体积时,由于吸收,你的光强度损失了一半。

无论入射光强度如何,被吸收的光的比例都是相同的。无论进入体积的光子数如何,进入体积的光子数与离开体积的光子数之间的比率保持相同(平均)。入射辐射(incoming radiance)与吸收效应无关。此外,在 σ a \sigma_a σa d s ds ds 之间也存在线性关系。无论是将吸收系数加倍还是将光通过体积的距离加倍,吸收都同等地增加。

详细信息
因为吸收系数的单位是倒数距离,所以系数的倒数是距离。这个距离称为 平均自由程(mean free path) 。您可以将其视为光子和介质相互作用(导致散射或吸收事件)之前光子穿过体积的平均距离。平均自由程是模拟多次散射的关键(我们将在单独的课程中讨论该主题)。 mean free path = 1 σ \text{mean free path} = \frac{1}{\sigma} mean free path=σ1注意,平均自由程和吸收系数之间也存在线性关系。如果将吸收系数加倍,那么光子在与介质相互作用之前穿过体积的距离将减半。

散射系数(Scattering coefficient)

散射系数 σ s \sigma_s σs 类似于吸收系数,但当然表示光子被每单位距离的体积散射的概率。内散射和外散射对辐射率的变化具有不同的影响。这就是为什么我们区分它们。内散射将光添加到沿着 ω \omega ω 方向矢量朝向眼睛行进的光束。当光束朝向眼睛行进时,但向外散射,会导致能量损失。然而,两者都是相同散射现象的一部分。因此,光子被散射进或散射出的概率是相同的,并且由单个系数定义:散射系数表示为 σ s \sigma_s σs(希腊字母sigma)。

详细信息
在一些文献中,散射和吸收系数用希腊字母“mu”定义: μ \mu μ。这似乎是物理学和研究中子等粒子如何穿过物质的领域的惯例。在计算机图形学中,字母 sigma 似乎已被公认为惯例。

消光系数(Extinction coefficient)

如前所述,从外散射和吸收对辐射变化的影响的角度来看,两者是不可区分的。当光束沿着 - ω \omega ω 方向矢量传播时,它们都导致辐射损失。观众唯一能看到的是光线强度的下降。无论这种能量衰减是光子被吸收还是散射/反射的效果,都不会改变观看者的体验和观察。

详细信息
当然,你可以通过设置一个探测器来测量光子离开的方向,而不是 - ω \omega ω ,来找到吸收和散射的结果。当我们以后引入相函数的概念时,这将变得方便和有意义。

这就是为什么当计算光通过介质时的辐射损失时,我们将散射和吸收系数结合在一个称为消光或衰减系数(extinction or attenuation coefficient)的系数中。它表示为:
在这里插入图片描述
下标 t t t 代表总衰减。你也可以看到它写为 σ t \sigma_t σt

Beer-Lamber定律的推导

我们从本课的第一章开始介绍比尔-朗伯定律。从它开始是一个好主意的原因是,当你关心计算光线透射率值(ray transmittance value,而不是辐射率radiance)时,你只需要比尔定律。透射率与有多少光穿过特定体积对象有关,您可以将其重新表示为对象的“不透明程度”。而你可以看到辐射作为定义体积对象亮度的量。稍后我们将更正式地介绍透射率的概念。

为了了解比尔-朗伯定律从何而来,我们将从观察从 x x x 开始沿着 ω \omega ω 方向行进的光束的辐射率的导数开始。从技术上讲- ω \omega ω ,但为了简洁起见,我们使用 ω \omega ω ,其中应理解 ω \omega ω 是观察者观看的方向,并且光束沿相反方向行进。你可以把辐射率的导数写成:

在这里插入图片描述
我们前面提到,外散射和吸收都有助于辐射的损失,但为了简单起见,我们将仅假设辐射的损失是由于吸收开始。我们将在后面(通过引入散射项)扩展和概括推理。

这表示由于吸收(在沿着方向 ω \omega ω 的点 x x x 处)而损失辐射的速率。您可以将其视为沿着河流剖面(如下图所示)任何点的河床坡度的测量值,或者使用更专业的术语,河流从源头流向河口时的坡度变化。
在这里插入图片描述

详细信息
这个等式告诉我们什么?它告诉我们,辐射率变化的速率在某种程度上与点x处的辐射率本身成比例(到目前为止还不错),其中比例因子是吸收系数 σ a \sigma_a σa 。这对你来说有意义吗?如果没有,请尝试再次阅读该句子,直到理解)。

这里有一些重要的细节,来帮助了解正在发生的事情。 L ( x , ω ) L(x, \omega) L(x,ω) 告诉我们光束在沿着方向矢量 ω \omega ω 的点 x x x 处的辐射率是多少。正因为如此,人们往往忽略了 L ( x , ω ) L(x, \omega) L(x,ω) 是一个函数的事实。这个函数就是Beer-Lambert定律本身。我们所追求的函数。如果我们要绘制这个函数,我们会看到一个随着光通过介质的距离增加而减小的函数(随着x远离光束进入介质的点)。下图显示了该函数(对于给定的吸收系数)相对于x的曲线图。蓝线表示变化率,即函数 L ( x , ω ) L(x, \omega) L(x,ω) 在一个特定位置的斜率:

在这里插入图片描述
因此,我们的使命是使用等式 d L = − σ a L ( x , ω ) dL = -\sigma_aL(x, \omega) dL=σaL(x,ω) 来计算出 L ( x , ω ) L(x, \omega) L(x,ω) 是什么。为了解决这个问题,我们首先将这个方程重写为 s s s 而不是 x x x 的函数,其中 s s s 表示光束穿过介质的距离。等式变为:
在这里插入图片描述
这里的导数(等式的左侧)是用莱布尼茨符号形式写的。分母中的项非常重要。你应该把左边的部分读作“函数 L(s) 相对于 s s s 的导数”。在人类语言中,这意味着 “L(s) 随着 s s s 的变化而变化的速率是多少”。

详细信息
要了解有关导数的更多信息,请参阅课程“The Mathematics of Shading”。

要找到L(s),可以这样写:
在这里插入图片描述
但这并没有给予我们更多关于L(s)是什么的信息,因为正如你所看到的,L(s)出现在等式的两边:有L(s)项,函数,和dL(s)项,函数的导数。那么我们如何解决这个问题呢?

在数学中,这是一种众所周知的方程类型,称为常微分方程(ordinary differential equations)或ODE(这里是一阶类型,因为它在这种特殊情况下处理一阶导数)。我们现在不会讲什么是ODE以及如何解决它们。互联网上有大量的文件可以深入讨论这个话题。在本课的上下文中,我们需要知道的是,它是一种方程,在其中你会找到函数及其导数。例如,函数y=f(x)关于x的导数可以写为:
在这里插入图片描述

详细信息
在这里插入图片描述
Or:
在这里插入图片描述
这是数学中一阶齐次线性微分方程的更一般的形式。这里要注意,术语“均匀”与均匀介质无关。还有一种一阶微分方程,如 y ′ + p ( x ) y = q ( x ) y' + p(x)y = q(x) y+p(x)y=q(x) ,被称为非齐次方程。

导数和导数的函数出现在同一个方程中,这是一个常微分方程,正如你所看到的,函数 y y y 的导数 d y dy dy 等于函数 y y y 本身。有趣?注意,这不是ODE的一般定义。导数不需要等于导数的函数才是常微分方程。它可以是任何函数,只要它是x的函数。但在我们的特殊情况下,在辐射率方程的情况下,导数恰好等于导数的函数(这对于常微分方程也是可以的)。

我们求解常微分方程的方法是把所有的 y y y 移到方程的一边(比如左边),把所有其他的东西(最明显的是所有的 x x x 项,还有常数)移到另一边。将 c c c 作为我们方程中的常数,我们得到:
在这里插入图片描述
在这里插入图片描述
记住 d y dy dy 是一个导数,所以要找到反导数的函数,也就是 y y y ,我们接下来需要做的是对方程的两边进行积分。
在这里插入图片描述
你可能会觉得奇怪,我们把导数 d y dy dy 的积分除以函数 y y y 。从数学上讲,这没有任何意义,所以永远不要这样做。正确的理解方法是对 1 / y 1 / y 1/y 求关于 y y y 的积分。我们将其表示为:
在这里插入图片描述

详细信息
我们总是求函数关于某个变量的积分。例如,如果我们想写我们想取函数 f ( x ) f(x) f(x) 关于 x x x 的积分,我们应该使用以下符号: ∫ f ( x ) d x \int f(x)dx f(x)dx积分算子有一个左符号 ∫ \int 和一个右符号 d x dx dx 。如果你仍然不熟悉衍生,我们建议你阅读课程的着色数学。你也会在互联网上找到很多非常好的地方来学习衍生。

l n ( y ) ln(y) ln(y) 的导数是1除以 y y y 。因此, 1 / y 1/y 1/y 相对于 y y y 的积分是函数 y y y l n ( y ) ln(y) ln(y) 的自然对数:
在这里插入图片描述

详细信息
你也可以找到很多关于log()函数的导数的参考资料,所以我们在这里不再详细介绍这一部分。

所以我们得到:
在这里插入图片描述
我们可以将常数 x x x 从积分中移出,而 d x dx dx 的积分就是x本身。因此,我们现在有:
在这里插入图片描述
最后,为了删除左侧的 l n ln ln ,我们可以这样写:
在这里插入图片描述
如你所知:
在这里插入图片描述
我们得出最终结果:
在这里插入图片描述
数学是美丽的。我们在这里学到的是,当我们有一个方程 d y / d x = c y dy/dx = cy dy/dx=cy 时,解为 y y y 提供了方程 e c x e^{cx} ecx 。这对我们来说很棒,因为这个等式是我们可以转换成代码的东西。让我们看看这如何应用于我们的辐射方程:

在这里插入图片描述

详细信息
我们在计算中省略了常数 C C C ,但检查以下VRE方程的完整推导以获得更完整的解。形式为y’ = -p(x)y的一阶齐次线性微分方程的通解为:
在这里插入图片描述
其中 P ( x ) P(x) P(x) p ( x ) p(x) p(x) 的反导数。

其中结果是比尔-朗伯定律的方程。如果介质是均匀的,这个方程就成立。 对于非均匀介质,请参见下面的完整透射率方程。希望你已经能够看到 d L ( s ) dL(s) dL(s) 代表 d y dy dy d s ds ds 代表 d x dx dx L ( s ) L(s) L(s) 代表 y y y − σ a -\sigma_a σa 代表 c c c 。如前所述,到目前为止,我们只考虑了吸收。但是,我们可以通过用消光系数 σ t \sigma_t σt 代替 σ a \sigma_a σa ,来将由于外散射引起的衰减包括在比尔定律中:
在这里插入图片描述
σ t = σ a + σ s \sigma_t = \sigma_a + \sigma_s σt=σa+σs
在这里插入图片描述
上图显示了消光系数对体积不透明度的影响,以及随着系数值的增加,光线如何被吸收。

比尔定律、透射率和光学深度(Beer’s law, transmittance, and optical depth)

这就引出了透射率的概念。可以将透射率视为体积不透明度的度量,或者换句话说,可以将透射率视为多少光可以通过体积的度量。更正式地,透射率是透射通过体积的光的分数:
在这里插入图片描述
其中,如前所述, L i L_i Li 是入射辐射, L o L_o Lo 是出射辐射。这也可以是通过两点之间的体积的光的分数。 T T T 可以使用Beer定律计算:
在这里插入图片描述
其中 s s s 是体积中这两个点之间的距离。你经常会发现这个等式写为:
在这里插入图片描述
其中 τ \tau τ(希腊字母tau)称为光学深度或光学厚度。有两种类型的透射比:仅考虑吸收的透射率被称为内透射率,而考虑吸收、外散射等的透射率被称为总透射率。

对于非均匀体积,其中消光系数(我们现在将把密度的概念放在一边)在空间中变化的体积,我们需要沿着射线积分消光系数,我们可以写为:
在这里插入图片描述
其中 d d d 是射线穿过体积的距离。比尔定律的最后和最普遍的形式可以写为:
在这里插入图片描述
如果你读过前面的章节,你可能记得我们在3D密度场的体绘制一章中遇到过术语“tau”。在本章中,我们使用它来累积光线通过非均匀介质时的消光系数值。

内散射与相函数(In-scattering and the phase function)

最后,我们需要把定义光能如何通过介质传播的全局方程放在一起的最后一块拼图是相位函数。我们已经在“ Ray Marching: Getting it Right! ”一章中介绍了相位函数的概念。

在这里插入图片描述

图1:只有一小部分入射光向眼睛散射。多少取决于灯光和观察方向之间的角度。

当来自光束的光子与构成介质的粒子相互作用时,它们可以被散射而不是被吸收。它们分散在随机的方向上。我们知道它们来的方向,但我们无法预测它们会向哪个方向分散。当来自准直光束的光子被散射时,光束失去能量。然而,如果一些其他光源从 − ω -\omega ω 上方的方向照射到我们的圆柱体上,则来自该光源的穿过圆柱体的一些光子可能沿着 − ω -\omega ω 方向散射。因此,沿着 − ω -\omega ω 方向行进的光束将获得能量。这就是我们所说的内散射。问题是,为了知道我们的光束由于向内散射而获得多少能量,我们需要知道来自以某个倾斜角度穿过圆柱体的光束的能量中有多少将在 − ω -\omega ω 方向上散射。这个小数由我们称为 相位函数(phase function) 的函数给出。

相位函数给出沿着方向 ω ′ \omega' ω 行进的入射光的比例(注意这里的撇号),其在 − ω -\omega ω 方向上散射。请记住,这个过程是三维的,因此光线会在一个方向球上散射。散射光的分布当然取决于介质的性质以及光方向矢量 ω ′ \omega' ω 和视图方向矢量 ω \omega ω 之间的角度 θ \theta θ (希腊字母theta)(这些是文献中使用的惯例)。

请注意,您应该在这里超级小心的符号。当涉及到相位函数时,约定如下: ω \omega ω 矢量从 x x x 指向眼睛,而 ω ′ \omega' ω 矢量从 x x x 指向光(如图1所示)。经验法则:当计算两个矢量之间的角度时,我们总是假设 ω \omega ω 指向眼睛,而 ω ′ \omega' ω 指向光。在您的代码中,当您使用灯光和相机方向向量(可能指向与预期约定相反的方向)计算角度 θ \theta θ 时,您可能必须格外注意这一点。

总而言之,相位函数描述了介质内任何点x处光散射的角分布。

相位函数(表示为 f p ( x , ω , ω ′ ) f_p(x, \omega, \omega') fp(x,ω,ω) )为:

  • 相互的(Reciprocal): f p ( x , ω ′ , ω ) = f p ( x , ω , ω ′ ) f_p(x, \omega', \omega) = f_p(x, \omega, \omega') fp(x,ω,ω)=fp(x,ω,ω) 。交换向量,结果是一样的。这就是为什么相位函数经常被写为 f ( x , θ ) f(x, \theta) f(x,θ) 的原因,其中 θ \theta θ 是两个矢量之间的角度。
  • 归一化为1(Normalized to 1):它们在方向球(通常表示为 § 2 §^2 §2 )上的积分需要为1,否则,他们将增加或减少散射事件的辐射:
    在这里插入图片描述

参与介质可以表现出两种类型的散射行为:

  • 各向同性(Isotropic):方向球中的所有方向被选择的可能性相等。
  • 各向异性(Anisotropic):方向球中的一些方向比其他方向更有可能被优先选择为向后或向前方向,如下图所示。例如,云表现出强的前向散射行为。

在这里插入图片描述
下面是各向同性介质的相位函数:
在这里插入图片描述
在“ Ray-Marching: Getting it Right! ”部分中,我们已经介绍了Henyey-Greenstein或HG相函数,它是最常用的各向异性相函数之一。该函数仅取决于角度 θ \theta θ ,并且被定义为:
在这里插入图片描述

详细信息
为了证明这个方程是归一化的,请参见 Ray-Marching: Getting it Right!

它最初被设计用于模拟星系间尘埃对光的散射(Henyey, L.C. and J.L. Greenstein. 1941. Diffuse radiation in the galaxy. Astrophysical Journal 93, 70-83),但由于其简单性,它也被应用于模拟许多其他散射材料。出于生产目的,虽然简单,但该函数通常足够好(此外,为了模拟多次散射,需要反转相位函数,并且这可以很容易地用该方程完成)。

其中 − 1 < g < 1 -1 < g < 1 1<g<1 被称为不对称参数。当 g g g 低于0时,光优先向后散射(向后散射),当 g = 0 g = 0 g=0 时,介质是各向同性的(光在所有方向上均匀地散射),并且当 g > 0 g > 0 g>0 时,光优先向前散射(向前散射)。在上图中,我们展示了g = -0.2和g = 0.2的示例。 g g g 越大,越多的光被散射回光或向前朝向相机/眼睛。云表现出强烈的前向散射效应,其值为 g ≈ 0.8 g ≈ 0.8 g0.8 (J. E. Hansen. 1969. Exact and Approximate Solutions for Multiple Scattering by Cloudy and Hazy Planetary Atmospheres)。这会导致在背光时云的边缘产生条纹效应。

在这里插入图片描述
可以使用其他相位函数,例如Schlick、Mie或Rayleigh相位函数。查看我们将来关于应用于参与介质的多重散射的课程,以了解有关这些其他模型的更多信息。

辐射传递方程与体绘制方程

现在我们已经把所有的拼图拼在一起,形成了最后的方程式。我们要看的第一个方程叫做辐射传递方程(Radiative Transfer Equation)或RTE。它的现代形式是由一个叫Subrahmanyan Chandrasekhar的人在1950年出版的一本名为“辐射转移”的书中定义的,从那时起,这本书已经成为标志性的(至少是关于主题的参考)。现在我们不会花太多时间在这上面,因为这本书本身很好。但相当复杂,你可以看这个来快速窥视这本书。
在这里插入图片描述
我们最终可能会在本课的未来修订版或单独的课程中深入研究辐射传递方程(如果您感兴趣,请查找有限元方法或光能传递方法以及这篇论文“Modeling the Interaction of Light Between Diffuse Surfaces”和/或这本书“Radiosity and Realistic Image Synthesis”- Cohen,1993)。现在,我们将从这本书中给予一个小的努力,我们认为这是一个很好的总结(或介绍)到目前为止我们所学到的一切:

在这一章中,我们将定义辐射传递的基本量,并推导出基本方程–传递方程–它支配着吸收、发射和散射辐射的介质中的辐射场。

好了,足够的话。RTE考虑了我们已经列出的对能量流方向 w w w 上的辐射变化有贡献的不同元素:吸收、内散射和外散射以及发射,我们将在本课中省略这些。请记住,该等式定义了辐射率沿着方向 w w w 的变化(导数):
在这里插入图片描述
蓝色的项说明了由于吸收和外散射引起的损耗。橙色项是内散射项,有时也称为源项(source term)。注意积分前面的 σ s \sigma_s σs 项。这在概念上类似于我们在本章前面介绍的吸收和外散射引起的能量损失方程:
在这里插入图片描述
内散射的量与光被散射的概率成比例。该概率由散射系数 σ s \sigma_s σs 给出。上面描述了内散射项的其余部分。在方向 S 2 S^2 S2 的球面上的积分意味着对于内散射项,我们需要考虑来自每个方向( w ′ w' w )的光,由相位函数 f p ( x , w , w ′ ) f_p(x, w,w') fp(x,w,w) 加权。

为了简洁起见,让我们这样写:
在这里插入图片描述
我们已经多次强调了这一点,但RTE方程是一个积分微分方程。它表示一个方向导数: x x x 处的辐射 L L L 相对于 w w w 的导数。在文献中,您还将看到以以下形式编写的此等式:
在这里插入图片描述
其中 ∇ \nabla (数学中称为Del或nabla符号)可以解释为函数的梯度(类似于导数的概念)。当你向 w w w 方向移动时,辐射会以与吸收和散射项成正比的速率局部变化(减少或增加)。与我们接下来将介绍的体绘制方程相反,这个积分微分方程告诉我们,当我们在光流动方向上“迈出一步”时,辐射的变化率是多少。

现在,这个微分方程对我们来说不是很有用,因为作为计算机图形开发人员,我们需要的是一种测量体积物体边界处的辐射率的方法。该辐射将是光沿着光线或眼睛方向穿过物体的结果,通过吸收和/或外散射而减少,并且通过内散射而增加,如现在熟悉的下图所示。

在这里插入图片描述
如已经多次提到的,辐射传递方程是一阶微分方程,其标准形式可以定义/写为:
在这里插入图片描述
在数学中,这个方程被称为一阶非齐次线性微分方程。我们需要求解一个方程,其中函数 y y y 及其导数 y ′ y' y 都存在。其中(现在我们将重新定义辐照度函数为距离 s s s 的函数也就是从 s s s 到光束上任意一点的距离沿矢量方向 w w w ):
在这里插入图片描述
在这里插入图片描述

以及:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

请记住,我们说过术语 L s L_s Ls 有时被称为源术语(source term)。这是因为你可以把它看作是沿着光线在某些地方“出现”的光,并被添加到光束的辐射中。这是一个“源”的辐射。

这个标准形式的ODE有一个已知的解决方案(如果你感兴趣,请参阅下面的推导),它是:
在这里插入图片描述

详细信息
推导:
可以使用几种方法来导出一阶非齐次微分方程的解。我们将使用积分因子法。它开始于我们可以将ODE y ′ + p ( x ) y = q ( x ) y' + p(x)y = q(x) y+p(x)y=q(x) 乘以函数 I ( x ) I(x) I(x) 的想法。如果我们这样做,那么我们得到:
在这里插入图片描述
我们把这个方程称为修正的常微分方程。要理解为什么它是相关的,你需要知道两个函数的乘积的导数等于:
在这里插入图片描述
这在数学中被称为乘积法则。现在我们知道了这一点,我们可以注意到,如果我们选择 I ′ ( x ) = I ( x ) p ( x ) I'(x) = I(x)p(x) I(x)=I(x)p(x) ,那么我们的ODE乘以 I ( x ) I(x) I(x) 的左侧看起来可能是由乘积规则计算的导数。
在这里插入图片描述
然后注意 I ′ ( x ) = I ( x ) p ( x ) I'(x) = I(x)p(x) I(x)=I(x)p(x) 本身是一个一阶齐次微分方程,我们在本章前面已经给出了这类方程的通解。一般的解决方案是:
在这里插入图片描述
Q ( x ) = ∫ p ( x ) d x Q(x) = \int p(x)dx Q(x)=p(x)dx 。注意 Q ( x ) = − P ( x ) Q(x) = -P(x) Q(x)=P(x) P ′ ( x ) = − p ( x ) P'(x) = -p(x) P(x)=p(x) (有关详细信息,请参见上面的齐次ODE推导)。现在让我们用齐次常微分方程的通解替换项 I ( x ) I(x) I(x) 来重写我们修改过的常微分方程:
在这里插入图片描述
最后,我们知道:
在这里插入图片描述
因此,将前面等式中的左项替换为右项,我们得到:
在这里插入图片描述
我们只剩下整合双方:
在这里插入图片描述
在其一般形式中(考虑到我们在上面的积分中省略的积分成本),解决方案变为:
在这里插入图片描述
要得到VRE,您所要做的就是分别将项 p p p q q q 替换为 σ t \sigma_t σt σ s L s ( x ) \sigma_sL_s(x) σsLs(x)

如果我们用RTE方程中的对应项替换 q q q p p p 项,我们得到:
在这里插入图片描述
正如你所猜测的,这就是我们所说的体积渲染方程。

详细信息
请注意,虽然我们不知道谁是第一个提出这个术语的作者,但体积渲染方程这个术语是在21世纪初很晚才引入的。它可以在Pixar Research于2017年发布的题为Volume Rendering for Production的文档中找到,但之前已经使用过。如果你有关于这方面的一些信息,让我们知道。

右侧的 L 0 L_0 L0 项对应于来自潜在地在体积对象后面的对象的辐射(从观看者的角度来看)。如果体积对象被放置在实体对象的前面,物体沿 w w w 矢量“反射”的亮度 L 0 L_0 L0 将被体积在整个距离 s s s 上的透射率衰减。如上图所示。

还应注意,如果我们考虑发射,我们将像这样在内散射项旁边添加发射项 L e L_e Le (注意发射源旁边的 σ a \sigma_a σa 项):
在这里插入图片描述
体绘制方程对我们计算机图形学的人来说更有用,因为它将RTE转化为一个积分,即使它没有一个封闭的形式解决方案,至少可以使用诸如黎曼和之类的技术来解决(我们在前面的章节中基本上已经做了)。

有:
在这里插入图片描述
如你所知,它现在提供了介质在距离 s s s 上的透射率,我们可以将VRE写为:
在这里插入图片描述
一般来说,在这一点上,人们说这个方程可以直观地理解。让我想想这个想法是这样的:可以看到用于计算点 x x x 处的辐射率的过程是沿着射线收集辐射率的过程,其中沿着该射线的任何点处的辐射率(例如朝向x(在方向 w w w 上)行进的 x ′ x' x )被从该点到 x x x 的透射率所消除(并且其中 s ′ s' s 是从 x ′ x' x x x x 的距离)。

如果你已经走了那么远,恭喜你。你已经通过了计算机图形学文献中最复杂的方程之一。请注意,虽然一些较老的论文确实提供了一些关于如何从RTE到VRE的线索,但Scratchapixel是第一个也是唯一一个提供完整推导的来源(据我们所知)(特别感谢SP))。

详细信息
一点历史
如果有一个文件,我们应该提到这个介绍体绘制,这将是由James T. Kajiya在1984年发表了题为“Ray-Tracing Volume Density”的论文。这告诉你渲染体积对象肯定不是最近的事情,但是当时的硬件还不够强大,甚至不能将光线跟踪应用于固体表面,因此更不能应用于光线行进体积对象。直到20世纪末到21世纪初,我们才开始在制作中使用体渲染(因为成本比大预算制作电影的成本要低)。下图是他的论文的截图,其中Kajiya展示了光线行进体积对象的第一个结果。
在这里插入图片描述
这篇论文可能是整个计算机图形学研究史上最重要的10篇论文之一。如果你不同意,让我们知道。

现在最大的问题是:我们如何计算这个积分(不,答案不是42)?在本课中,我们已经使用光线推进方法展示了一种解决方案,但还存在其他方法。光线行进曾经是一种规范,现在被认为是相当过时的(但我们认为它仍然是学习体渲染的一个很好的起点)。今天的规范是使用跟踪算法和随机采样方法。我们将在本课的最后一章简要地讨论这个话题。

从方程到代码

我们理解这些公式可能会让人不知所措,有些读者只关心它们如何转换为代码。本课的前四章将带你走过这段旅程,所以我们不会在这里再次进行这个练习。如果你还没有完成本课的第一章,我们建议你完成。但是这里有一些指针可以帮助你把等式的不同部分和各个章节联系起来。

  • L(0)T(s)项 暗指我们在本课第一章中学到的内容。L(0)简单地解释了被固体物体反射的光,例如下图中的红色墙壁,穿过体积。光(物体的颜色)简单地衰减了T(s),其中s是光通过体积的距离,T是简单的比尔定律。如果对象是同质的,这只是 T ( s ) = e x p ( − s ∗ σ t ) T(s) = exp(-s * \sigma_t) T(s)=exp(sσt) 。本部分见第1章。如果体积是非均匀的,则需要按照第3章所述计算体积光学厚度。公式为 T ( s ) = e x p ( − ∫ t = 0 s σ t ( x t ) d t ) T(s) = exp(- \int_{t=0}^s \sigma_t(x_t) dt) T(s)=exp(t=0sσt(xt)dt) 。如果我们只考虑这一项,体积球仍然是黑色的,如下图所示。该项仅负责来自背景并穿过体积的光。
    在这里插入图片描述
  • 等式右手侧的第一项(该位 ∫ t = 0 s T ( t ) [ σ s ( x t ) L s ( x t , ω ) ] d t \int_{t=0}^s T(t)\big[\sigma_s(x_t) L_s(x_t,\omega) \big]dt t=0sT(t)[σs(xt)Ls(xt,ω)]dt )简单地说明了单个散射项。要了解如何将其转换为代码,请阅读第1章到第3章。此项负责球体照明。
    在这里插入图片描述

下一步是什么?蒙特卡洛随机方法

我们接下来要研究的

本课的大部分内容都致力于研究光线行进算法,但您应该知道,虽然该算法几乎只用于体渲染,直到最近(至少在2010年代中期),但现代渲染引擎现在通常使用基于随机蒙特卡洛的方法来渲染体。既然这个算法已经被取代了,我们为什么还要花这么多时间来研究它呢?由于历史原因,并且因为通过光线行进算法比通过随机方法更容易引入体渲染(和体渲染方程)的主题,而随机方法明显更复杂(特别是从几乎没有数学背景的CGI编程新手的角度来看)。

为什么射线推进算法被取代了?主要有两个原因:

  1. 因为当光线与体积相互作用时,它不能很好地模拟光线在真实的世界中的行为。我们稍后会详细介绍这一点。第二,因为随机方法在模拟真实的事物方面做得更好。
  2. 我们可以从一开始就使用随机方法(这种方法自20世纪60年代以来就众所周知),但是你看,这种方法的问题是它需要比射线行进方法多无数倍的计算,并且你必须等待无限长的时间才能用它生成图像(至少感觉是这样)。光线行进是计算密集型的,但没有随机方法那么多,这就是为什么它直到最近才成为体绘制的首选解决方案(即使如此,我们也不得不等到20世纪90年代末才开始看到光线行进在生产中使用,直到21世纪末才开始看到它无处不在)。值得庆幸的是,随着计算能力的不断提高,我们现在可以在合理的时间内使用随机方法产生结果,并且由于它可以产生更好的结果,因此光线步进方法已经被淘汰,取而代之的是基于随机的方法。

现在让我们来看看为什么光线步进做得相当差。

为了回答这个问题,我们需要了解光是如何通过介质传播的。这是光子进入一个体积后发生的情况。它以直线行进一定的距离,直到它最终与介质相互作用(例如,组成体积的颗粒)。正如我们所知,它可以被散射(在这种情况下,它会改变方向)或被吸收。如果它被散射,则它将继续行进通过体积,但在随机方向上,至少是非常可能不同于它在与体积的粒子相互作用之前所遵循的方向的方向。只要粒子被吸收或最终离开体积,这种“旅行-相互作用”循环就会持续下去。我们已经在下图中说明了这个想法,在那里你可以看到三个光子从顶部进入体积立方体的命运。

在这里插入图片描述
其中两个(红色)最终被吸收,而只有一个(绿色)逃离了体积(与进入立方体时的方向不同)。

光子的运动可以被描述为一种随机游走。毫不奇怪,这就是它的名字。随机漫步我们还可以看到,颗粒在被吸收或逸出体积之前与介质多次相互作用。它分散了很多次。而这正是光线步进做得不好的地方:它只考虑光子和体积之间的单个相互作用。

单散射与多散射。低反照率(Albedo)体积对象与高反照率体积对象。

这称为单次散射。我们只考虑了在与介质的一次交互之后被重定向到观察者的光。虽然一些体积具有强烈的单散射项(例如从溪流或火山中冒出的黑烟),但许多其他类型的体积,最明显的是云,表现出强烈的多重散射行为。光子在逃逸(或被吸收)之前与物体多次相互作用。这就是为什么云是明亮的或白色的,如果你喜欢的话,而蒸汽火车或火山冒出的烟是黑暗的。我们说白色的反照率高,而黑烟羽的反照率低。下图显示了低反照率和高反照率体积之间的差异(左边的烟雾含有大量颗粒,而云是由水滴组成的,这主要解释了两者之间的视觉差异)。当然,黑烟之所以是黑的,是因为它也吸收了大量的光线。

在这里插入图片描述
总之,光线步进算法为低反照率物体(如烟雾)提供了一个可接受的近似值,其外观是单散射项占主导地位的结果(下图中所示的橙色射线),而它提供了一种糟糕的方式来模拟高反照率物体的外观。它的出现是多次散射优于单次散射的结果(大多数逃离体积的光子是在多次与体积相互作用之后才这样做的,而不是像单次散射假设的那样只有一次)。
在这里插入图片描述
顺便说一下,由于我们是在比较烟雾和云的主题上,还需要注意的是,烟雾通常是各向同性的,而云则表现出强烈的(前向)散射行为。

在某种程度上,可以将光线步进与直接照明进行比较。直接照明比完全没有照明好(显然),但肯定不如直接和间接照明渲染的场景。使用光线步进,我们完全忽略了间接照明部分。如下面的示例所示,间接照明对于创建照片级逼真的图像至关重要。因此,光线步进算法不能捕获这种效果的事实是一个大问题。

在这里插入图片描述
这具有具体的实际意义:您将必须将更多的光(如在场景中创建附加光源)泵入体积中以模拟例如云的外观,并且因此欺骗而不是使计算机进行物理上准确的并且因此正确的事情。但问题是还有什么选择,如何做正确的事?

基于随机或跟踪的方法

正确的做法是让计算机模拟光子与介质相互作用的方式。换句话说,模拟光子的随机游走行为。该方法旨在跟踪光子在体积中行进时的路径。这就是为什么这些方法被称为跟踪方法。这不是一个“新”的方法。它是在20世纪60年代开发的,用于模拟粒子(例如中子)通过板材的辐射。虽然通用且非常强大,但该方法在计算上也非常昂贵。

如果您有兴趣了解更多关于您自己的主题,在互联网上搜索蒙特卡洛粒子输运(MCPT)或蒙特卡罗光或光子输运。我们不会在这里详细介绍这种技术。首先,我们已经在本页提供了该方法的实际实现,作为Monte Carlo模拟的示例:Monte Carlo Simulation。我们也计划写一个教训,希望很快(2022年)。检查“Advanced 3D Rendering”部分以获取更新(该课程应称为“Volumetric Path Tracing”)。

我们现在只说这个想法是模拟光子通过体积的路径。目标仍然是求解体绘制方程:
在这里插入图片描述

使用Monte Carlo(请参阅Mathematical Foundations of Monte Carlo MethodsMonte Carlo Methods in Practice,以了解有关此主题的更多信息)。与光线追踪一样,我们不会通过模拟和跟踪光子前进(从光源到观察者或传感器)的路径来做到这一点,而是通过从观察者到光源的反向运动来实现。粒子通过介质的路径可以用光子所采取的一系列步骤来表征,其中该路径中的每一步都由长度和方向定义。我们将随机采样光子方向的长度来解释这种行为,基本上使用我们对介质本身的知识,特别是它的散射和吸收系数以及它的相函数。

如前所述,基于随机的蒙特卡洛模拟或积分的方法在计算上是昂贵。您可能听说过的诸如delta tracing之类的技术可以用于改进流程(以增加代码的复杂性为代价)。delta tracing也将在专门介绍volumetric path tracing的课程中进行研究。

源代码(外部链接GitHub)

源代码地址

猜你喜欢

转载自blog.csdn.net/weixin_43789369/article/details/132917575