计算机图形学基础笔记(4.3)

107 阅读7分钟

Category:Higher Mathematics & Computer Graphics Application

正文

4 光线追踪(二)

4.6 光线追踪程序

我们现在知道如何为给定的像素生成视线,如何找到与对象最近的交点,以及如何对生成的交点进行着色。 这些是生成带有隐藏表面的阴影图像的程序所需的所有部分。

image.png

这里的语句“如果射线击中一个物体。 . . ”可以使用4.4.4节的算法来实现。

在实际实现中,表面相交例程需要以某种方式返回对被击中对象的引用,或者至少返回其法线向量和与着色相关的材质属性。这通常是通过传递带有此类信息的记录/结构来完成的。在面向对象的实现中,最好有一个类似于表面的类,其派生类为三角形、球体、组等。射线可以相交的任何东西都在该类下。然后,光线追踪程序将对整个模型的“表面”进行一个引用,并且可以透明地添加新类型的对象和效率结构。

4.6.1 光线追踪程序的面向对象设计

如前所述,光线追踪器中的关键类层次结构是构成模型的几何对象。这些应该是某些几何对象类的子类,并且它们应该支持命中功能(Kirk & Arvo,1988)。为了避免与“对象”一词的使用混淆,表面是经常使用的类名。使用这样一个类,您可以创建一个光线追踪器,该光线追踪器具有一个通用接口,该接口几乎不考虑对基元建模并仅使用球体对其进行调试。重要的一点是任何可以被射线“击中”的东西都应该是这个类层次结构的一部分,例如,即使是表面的集合也应该被认为是表面类的子类。这包括效率结构,例如边界体积层次结构;他们可以被射线击中,所以他们在课堂上。

例如,“abstract”或“base”类将指定命中函数以及稍后将证明有用的边界框函数:

image.png

这里 (t0, t1) 是射线上将返回命中的间隔,rec 是通过引用传递的记录;当hit返回true时,它包含诸如交点处的t之类的数据。类型框是一个 3D “边界框”,即定义一个围绕表面的轴对齐框的两个点。例如,对于一个球体,该函数将通过以下方式实现:

image.png

另一个有用的类是材料。这允许您抽象材质行为,然后透明地添加材质。链接对象和材质的一种简单方法是在表面类中添加指向材质的指针,尽管可能需要更多的可编程行为。一个大问题是如何处理纹理;他们是物质阶级的一部分,还是生活在物质阶级之外?这将在第 11 章中详细讨论。

4.7 阴影

一旦你有了一个基本的光线追踪程序,就可以很容易地添加阴影。 回忆一下 4.5 节,光来自某个方向 l。如果我们想象我们自己在表面上的点 p 被遮蔽,那么如果我们在方向 l 上“看”并看到一个物体,则该点处于阴影中。如果没有物体,则光线不会被阻挡。

如图 4.17 所示,其中光线 p tl 没有击中任何物体,因此不在阴影中。点 q 处于阴影中,因为光线 q tl 确实击中了一个物体。两个点的向量 l 相同,因为光“很远”。这个假设稍后会放宽。确定阴影内或阴影外的光线称为阴影光线,以区别于观察光线。

image.png

为了得到阴影的算法,我们添加了一个 if 语句来确定该点是否在阴影中。在一个简单的实现中,阴影射线将检查 t ∈ [0, ∞),但由于数值不精确,这可能导致与 p 所在的表面相交。相反,避免该问题的通常调整是测试 t ∈ [ , ∞) 其中是一些小的正常数(图 4.18)。

image.png

如果我们使用公式 4.3 为 Phong 光照实现阴影光线,那么我们有以下结果:

image.png

请注意,无论 p 是否处于阴影中,都会添加环境颜色。如果有多个光源,我们可以在评估每个光源的着色模型之前发送阴影光线。上面的代码假设 d 和 l 不一定是单位向量。这对于 d 至关重要,特别是如果我们希望稍后干净地添加实例化(参见第 13.2 节)。

4.8 理想镜面反射

在光线追踪程序中添加理想的镜面反射或镜面反射很简单。关键观察如图 4.19 所示,其中从 e 方向看的观察者从表面看到的 r 方向是什么。矢量 r 是使用 Phong 照明反射方程 (10.6) 的变体找到的。

image.png

在光线追踪程序中添加理想的镜面反射或镜面反射很简单。关键观察如图 4.19 所示,其中从 e 方向看的观察者从表面看到的 r 方向是什么。矢量 r 是使用 Phong 照明反射方程 (10.6) 的变体找到的。

image.png

在现实世界中,当光线从表面反射时,会损失一些能量,而且这种损失对于不同的颜色可能是不同的。例如,金色比蓝色更有效地反射黄色,因此它会改变它反射的物体的颜色。这可以通过在 raycolor 中添加递归调用来实现:

image.png

其中 km(用于“镜面反射”)是镜面 RGB 颜色。我们需要确保我们测试 s ∈ [ , ∞) 的原因与我们测试阴影射线的原因相同;我们不希望反射光线击中生成它的对象。

上面递归调用的问题是它可能永远不会终止。例如,如果光线在房间内开始,它将永远反弹。这可以通过添加最大递归深度来解决。如果仅在 km 不为零(黑色)时生成反射光线,则代码将更有效。

image.png

4.9历史笔记

光线追踪是在计算机图形学历史的早期开发的(Appel,1968),但直到有足够的计算能力可用(Kay & Greenberg,1979;Whitted,1980)才被大量使用。

光线追踪的渐近时间复杂度低于基本的对象顺序渲染(Snyder & Barr, 1987; Muuss, 1995; S. Parker et al., 1999; Wald, Slusallek, Benthin, & Wagner, 2001)。尽管传统上它被认为是一种离线方法,但实时光线追踪实现正变得越来越普遍。

经常问的问题

• 为什么光线追踪中没有透视矩阵?
z缓冲区中存在透视矩阵,因此我们可以将透视投影转换为平行投影。这在光线追踪中是不需要的,因为很容易通过将光线从眼睛中散开来隐式地进行透视投影。

• 光线追踪可以交互吗?
对于足够小的模型和图像,任何现代 PC 都足够强大,可以进行交互式光线追踪。实际上,全屏实现需要多个具有共享帧缓冲区的 CPU。计算机能力的增长速度远快于屏幕分辨率,传统 PC 能够以屏幕分辨率对复杂场景进行光线追踪只是时间问题。

• 光线追踪在硬件图形程序中有用吗?
光线追踪经常用于拾取。当用户在 3D 图形程序中的像素上单击鼠标时,程序需要确定在该像素内可见的对象。光线追踪是确定这一点的理想方法。

练习

  1. 射线(1, 1, 1) t(-1, -1, -1) 与以原点为中心、半径为1的球体的交点的射线参数是多少?注意:这是一个很好的调试案例。

  2. 射线 (1, 1, 1) t(−1, −1, −1) 与顶点为 (1, 0, 0), (0, 1, 0) 的三角形碰撞时的重心坐标和射线参数是多少) 和 (0, 0, 1)?注意:这是一个很好的调试案例。

  3. 在“nice”(非对抗性)模型上对光线追踪的近似时间复杂度进行逆向计算。将您的分析拆分为预处理和计算图像的情况,以便您可以预测静态模型的多个帧的光线追踪行为。