6.2 光线算法(Ray Algorithms)
介绍
我们来谈谈 ray marching 和 ray tracing 等光线算法。光线步进 (ray marching)是 Shadertoy 中用于开发 3D 场景的最常用算法,但您会看到人们也利用光线追踪或路径追踪。
光线行进和光线追踪都是用于使用光线在 2D 屏幕上绘制 3D 场景的算法。在现实生活中,太阳等光源以光子的形式向大量不同方向投射光线。当一个光子撞击一个物体时,能量被物体的原子晶格吸收,并释放出另一个光子。根据材料原子晶格的晶体结构,光子可以沿随机方向发射(漫反射 diffuse),也可以以进入材料的角度发射(镜面反射 specular 或镜面反射 mirror-like reflection)
我可以整天谈论物理学,但我们关心的是它与光线行进和光线追踪的关系。好吧,如果我们尝试从光源开始建模 3D 场景,然后将其追溯到相机,那么我们最终会浪费计算资源。这种“前向 forward”模拟将导致大量光线永远不会照射到我们的相机上。
您主要会看到 “向后 backward” 模拟,其中光线是从相机或 “眼睛” 射出的。我们逆向工作!光通常来自太阳等光源,从一堆物体上反射,然后照射到我们的相机上。相反,我们的相机将向许多不同的方向发射光线。这些光线将从场景中的物体(包括地板等表面)反弹,其中一些光线会照射到光源上。如果光线从表面反弹并击中物体而不是光源,那么它被认为是“阴影光线”,并告诉我们应该绘制一个深色像素来表示阴影。
光线追踪图 by 维基百科
在上图中,相机向不同方向发射光线。多少条光线?画布中的每个像素对应一个像素!我们使用 Shadertoy 画布中的每个像素来生成光线。很聪明,对吧?每个像素在 x 轴和 y 轴上都有一个坐标,那么为什么不使用它们来创建具有 z 分量的光线呢?
会有多少个不同的方向?每个像素也对应一个!这就是为什么了解射线的工作原理很重要的原因。
从摄像机发射的每条光线的原点将与摄像机的位置相同。每条射线都有一个射线方向,其中包含 x 分量、y 分量和 z 分量。请注意阴影光线的来源。阴影光线的光线原点将等于相机光线照射到表面的点。每次光线撞击表面时,我们都可以通过从该点生成新的光线来模拟光线的“反弹”或反射。稍后当我们讨论照明和阴影时,请记住这一点。
光线算法之间的区别
让我们讨论一下您可能在网上看到的所有光线算法之间的区别。这些选项包括光线投射 (ray casting)、光线追踪 (ray tracing)、光线步进 (ray marching) 和 路径追踪 (path tracing)。
光线投射 (ray casting):一种更简单的光线追踪形式,用于 Wolfenstein 3D 和 Doom 等游戏,它发射单条光线并在击中目标时停止。
光线步进 (ray marching):一种使用有向距离场 (SDF) 的光线投射方法,通常是一种球体跟踪算法,该算法以增量方式“行进”光线,直到它击中最近的对象。
光线追踪 (ray tracing):光线投射的一种更复杂的版本,它发射光线,计算光线与表面的交集 (ray-surface intersections),并在每次反射时递归创建新光线。
路径追踪 (path tracing):一种光线追踪算法,每个像素发射数百或数千条光线,而不仅仅是一条。使用 Monte Carlo 方法将光线射向随机方向,最终像素颜色是通过对到达光源的光线进行采样来确定的。如果你在任何地方看到过 Monte Carlo,那么这马上就告诉你,你可能正在处理与概率和统计相关的数学。
您可能还会听到光线行进有时称为“球体追踪”。在计算机图形 Stack Exchange 上,有一个很好的讨论来讨论光线行进和球体跟踪之间的区别。基本上,球体追踪是光线行进的一种实现类型。您在 Shadertoy 上看到的大多数光线步进技术都将使用球体追踪,这仍然是一种光线步进算法。