什么是光线
Abstract
我们定义光线,展示如何使用光线间隔,并且演示如何字DirectX Raytracing(DXR)中指定关系光线
2.1 光线的数学表示
对于光线追踪,非常重要的计算结构式三维的光线。不论在数学还是光线追踪中,一个光线通常指的式三维的半直线(射线)。通常将光线指定为线上的间隔。对于三维的直线来说没有隐式的方程,类似于二维的线$y=mx+b$,所以,通常我们使用参数形式。在这一章,所有的线,点,和向量都是三维的。 一个参数形式的线可以表示为两个点A,B的加权平均值。
P(t)=(1-t)A+tB \tag{2.1}
在程序中,我们可能会想到把函数$P(t)$拥有实数输入t,并且返回一个点$P$这种表示方法。对于整条线来说,参数式可以输入任何的实数,$t\in [-\infty,\infty]$,并且,随着t的变化点P沿着线连续移动,如图2.1.为了去实现这个函数,我们需要一种表示点A和B的方式。这里可以使用任何的坐标系,但是几乎都是使用笛卡尔坐标。在APIs和编程语言中,这个表示方法通常是vec3或者float3并且包含三个实数,x,y,z.相同的直线能够被这条直线上任意两个点所表示。但是悬着不同的点,会改变t的值。
通常我们使用一个点+一个方向向量的形式,而不是两个点。如图2.2,我们能旋转我们的光线方向d为$B-A$,并且,我们的原点O为A,得到
P(t)=O+td 由于各种各样的原因,一些程序发现对于计算向量之间的点集来说,限制的d为单位向量$\hat{d}$是非常有用的,normalized.归一化方向向量的结果是t直接表示距离原点的有符号距离。 更一般地,任何两个t值的差异则是点之间的实际距离
||P(t{1}-P(t{2})||=|t2-t1| \tag{2.3} 对于一般的向量d,这个形式需要扩大d的长度
||P(t{1}-P(t{2})||=|t2-t1|||d|| \tag{2.4}
光线间隔
使用2.2的光线公式,我们想象中光线的画面是一条无限长的半线。然而,在光线追踪中,光线通常伴随着额外的间隔:t值的范围.通常我们使用两个值 $t{min}$和$t{max}$来确定这个间隔,这就绑定$t\in [t{min},t{max}]$.换句话说,如果交点的t在这两个之间,说明找到了,如果小于$t{min}$,大于$t{max}$,则不会记录,见图2.3
对于给出的最大值,当超过这个距离的命中时,这个命中是无关紧要的,例如对于阴影射线。假设我们有着色点P,并且想要询问它对于灯L的可见性。我们建立一个阴影射线,原点O=P,非标准化的方向向量$d=L-P$,$t{min}=0$并且$t{max}=1$.如果交点t在[0,1],光线与阻挡光线的几何体相交。在实践中,我们通常让$t{min}=\epsilon$,$t{max}=1-\epsilon$ $epsilon$是一个小的值。这种调整帮助避免由于数值的不严谨造成的自相交,使用浮点进行数学运算时,P所在的表面可能会以小的非零值t与我们的光线相交。 对于非点光源,光源基本体不应遮挡阴影射线,因此我们使用$t_{max}=1-\epsilon$来缩短间隔。 如果使用完美的数学,在开区间取值,这个问题就会消失,因为我们精确的忽略t = 0和1的交点。由于浮点精度有限,使用因子$epsilon$是一种常见的解决方案。
在实现中我们使用标准化的方向向量,我们使得O=P, $\frac{L-P}{||L-P||}$,$t{min}=\epsilon$,$t{max}=l-\epsilon$,在这里,$l=||L-P||$时到灯光的距离。请注意,这个epsilon必须不同于以前的epsilon,因为t现在有一个不同的范围。
有些渲染器使用单位长度向量来表示全部或部分光线的方向。这样做可以通过点积与其他单位向量进行有效的余弦计算,并且可以使推理变得更容易。除了使代码更具可读性外,它还具有更高的可读性。如前所述,单位长度意味着射线参数t可以被解释为一个距离,而无需按方向向量的长度进行缩放,在任何情况下,实例的几何体都可以使用每个实例的转换来表示。然后,Ray/Object交集需要将光线转换为对象的空间,这将更改方向向量的长度。为了在这个新空间中正确地计算t,这个变换的方向应该保持非规范化。此外,对于阴影光线,规范化会花费一点性能,而且可能是不必要的。由于这些优劣势,没有通用的建议是否使用单位方向向量。
2.3 DXR中的光线
在这个部分,我们展示在 DirectX Raytracing [^ 3]中的光线的定义。在DXR,光线具有下面的结构:
struct RayDesc
{
float3 Origin;
float TMin;
float3 Direction;
float TMax;
};
在DXR中处理光线类型的方式不同,其中某个着色器程序与每种不同类型的光线相关联。 要使用DXR中的TraceRay()
函数跟踪光线,需要RayDesc
。 RayDesc::Origin
设置为我们光线的原点O,RayDesc :: Direction
设置为方向d,并且t-interval(RayDesc :: TMin
和RayDesc :: TMax
)也必须初始化。 例如,对于眼睛光线(RayDesc eyeRay
),我们设置eyeRay.TMin = 0.0
和eyeRay.TMax = FLT MAX
,这表示我们对原点前面的所有交点感兴趣。
2.4 总结
本章介绍了如何在光线跟踪器中定义和使用光线,并给出了DXR API的光线定义。 这和其他射线追踪系统,如OptiX [^ 1]和Vulkan射线追踪扩展[^ 2]有着微小的变化。 例如,OptiX明确定义了光线类型,例如阴影光线(shadow ray)。 这些系统具有其他共性,例如射线有效载荷(ray payload)的概念。 这是一种数据结构,可由用户定义以携带附加信息以及可由单独的着色器或模块访问和编辑的光线。 这些数据具有特定的应用。 在每个定义光线的渲染系统中,在核心您将找到光线的原点,方向和间隔。
References
[^ 1]NVIDIA. OptiX 5.1 Programming Guide. http://raytracing-docs.nvidia.com/optix/guide/index.html, Mar. 2018.
[^ 2]Subtil, N. Introduction to Real-Time Ray Tracing with Vulkan. NVIDIA Developer Blog, https://devblogs.nvidia.com/vulkan-raytracing/, Oct. 2018.
[^ 3]Wyman, C., Hargreaves, S., Shirley, P., and Barre-Brisebois, C.´ Introduction to DirectX RayTracing. SIGGRAPH Courses, Aug. 2018.