光线追踪

在光线追踪中,假设相机是个点而不是个矩形。
然后将每个像素和相机相连并延长这条线,作为光线,这条线被称为“眼睛光线”。
这根光线会和场景中的物体相交,记录下最近的交点。
将交点与光源相连,判断能否被光源直接照到。
使用着色器进行着色,写入该像素点的颜色值。

Whitted风格光线追踪

当光线与物体相交时,计算该光线的反射光、折射光。同时不断递归反射光、折射光,计算每一个反射光、折射光与场景的交点、产生的反射光、折射光,并与光源相连,判断是否能被光源直接照射到。然后使用着色器进行着色,并将最后将得到的所有颜色值相加。

光线与模型的交点

定义光线

对于任意一条光线,可以用[latex]r(t)=o+td (0 \le t < \infty [/latex]来表示。
其中r为光线,t为时间,o为光源,d为光线方向。

光线与球体的交点

球体p的定义[latex](p-c)^2-R^2=0[/latex]

将光线带入球体的公式中:[latex](o+td-c)^2-R^2=0[/latex]
[latex]a t^2+b t+c=0, \text { where }[/latex]
[latex]a=\mathbf{d} \cdot \mathbf{d}[/latex]
[latex]b=2(\mathbf{o}-\mathbf{c}) \cdot \mathbf{d}[/latex]
[latex]c=(\mathbf{o}-\mathbf{c}) \cdot(\mathbf{o}-\mathbf{c})-R^2[/latex]
[latex]t=\frac{-b \pm \sqrt{b^2-4 a c}}{2 a}[/latex]

利用△可知与球体的交点个数,用求根公式即可得出交点

光线与隐式表面的交点

定义隐式表面p:[latex]f(p)=0[/latex]
将光线带入公式[latex]f(o+td)=0[/latex]
解出方程的根即可

光线与显式表面的交点

求光线与显式表面的交点,即为求光线与三角形求交点。

定义平面:

定义平面的法线N,再定义平面上任意一点[latex]p^{\prime}[/latex],如果有一点在平面内,这个点与p'的连线与法线垂直。

即平面p: [latex](p-p') \cdot N=0[/latex]

令[latex]p=r(t)[/latex]
[latex]\left(\mathbf{p}-\mathbf{p}^{\prime}\right) \cdot \mathbf{N}=\left(\mathbf{o}+t \mathbf{d}-\mathbf{p}^{\prime}\right) \cdot \mathbf{N}=0[/latex]

即可求出t:
[latex]t=\frac{\left(\mathbf{p}^{\prime}-\mathbf{o}\right) \cdot \mathbf{N}}{\mathbf{d} \cdot \mathbf{N}}[/latex]
[latex]0 \leq t<\infty[/latex]

Möller Trumbore算法

该算法可以快速求出光线在三角形内的交点。

如果光线与平面的交点在三角形内,那这一点也就能够用重心坐标表示,即:
[latex]\overrightarrow{\mathbf{O}}+t \overrightarrow{\mathbf{D}}=\left(1-b_1-b_2\right) \overrightarrow{\mathbf{P}}_0+b_1 \overrightarrow{\mathbf{P}}_1+b_2 \overrightarrow{\mathbf{P}}_2[/latex]

令:
[latex]\begin{aligned}
& \overrightarrow{\mathbf{E}}_1=\overrightarrow{\mathbf{P}}_1-\overrightarrow{\mathbf{P}}_0 \\
& \overrightarrow{\mathbf{E}}_2=\overrightarrow{\mathbf{P}}_2-\overrightarrow{\mathbf{P}}_0 \\
& \overrightarrow{\mathbf{S}}=\overrightarrow{\mathbf{O}}-\overrightarrow{\mathbf{P}}_0 \\
& \overrightarrow{\mathbf{S}}_1=\overrightarrow{\mathbf{D}} \times \overrightarrow{\mathbf{E}}_2 \\
& \overrightarrow{\mathbf{S}}_2=\overrightarrow{\mathbf{S}} \times \overrightarrow{\mathbf{E}}_1
\end{aligned}[/latex]

利用Cramer 法则:
[latex]\left[\begin{array}{l}
t \\
b_1 \\
b_2
\end{array}\right]=\frac{1}{\overrightarrow{\mathbf{S}}_1 \cdot \overrightarrow{\mathbf{E}}_1}\left[\begin{array}{c}
\overrightarrow{\mathbf{S}}_2 \cdot \overrightarrow{\mathbf{E}}_2 \\
\overrightarrow{\mathbf{S}}_1 \cdot \overrightarrow{\mathbf{S}} \\
\overrightarrow{\mathbf{S}}_2 \cdot \overrightarrow{\mathbf{D}}
\end{array}\right][/latex]

即可求出上述方程的解,其算力开销非常低。

加速算法

包围盒

使用包围盒将每一个模型包围起来,如果光线与包围盒相交,才计算光线和包围盒内模型的每个三角形是否相交。

将包围和理解为3组对面形成的交集:

轴对齐包围盒AABB

Axis-Aligned Bounding Box,每个面都和坐标轴的面平行。

在二维中,判断一个长方形和一条直线是否有交集,可以先求出其和线x0,x1的两个交点,再求出和线y0,y1的两个交点

因为当光线进入到所有的面,才能确定光进入到包围盒中,而当光线离开任意一个面,即为离开包围盒。所以求出其中最大的[latex]t_{min}[/latex]和最小的[latex]t_{max}[/latex]即为光线实际进入和离开盒子的时间。

即[latex]t_{enter}=max(t_{min}),t_{exit}=min(t_{max})[/latex]。在三维空间中同理。

如果[latex]t_{enter}<t_{exit}[/latex],即为光线经过了包围盒(光线在包围盒中待了一段时间)。

但是光线是射线,不是直线,所以当[latex]t_{exit}<0[/latex],说明物体在光线的背后,即不可能有交点。
当[latex]t_{exit}>=0,t_{enter}<0[/latex],即光线的起点在包围盒内部。

所以当且仅当[latex]t_{enter}<t_{exit},t_{exit}\ge0[/latex]时,光线穿过包围盒。

计算光线与面何时相交:
[latex]t=\frac{\left(\mathbf{p}^{\prime}-\mathbf{o}\right) \cdot \mathbf{N}}{\mathbf{d} \cdot \mathbf{N}}[/latex]
而这里的面是与坐标轴平面平行的,所以可以简化运算:
对于yz平面平行,即为垂直于x轴:
[latex]t=\frac{\mathbf{p}_x^{\prime}-\mathbf{o}_x}{\mathbf{d}_x}[/latex]


循之际,如星夜般的幻想。