GAMES101-13-01-Ray Tracing - Basics & Methods


光线追踪和光珊化是两个不同的成像方法。

为什么用Ray Tracing

  • 在rasterization中一些事情不能很好的处理:
    1. 不能很好地处理global effect
      • 如上一节中提到的shadow mapping, 只能实现hard shadow;
      • glossy reflection 光滑的反射;
      • indirect illumination 间接光照
      特别是,当光经过多次反射才能到达人眼的场景下,光栅化的效果都不太好; 光珊化做不好的事情
    2. 光栅化很快,但是质量相对较低;
  • Ray tracing 很准确,但是非常慢 光栅化可以realtime,而ray tracing一般是offline。 一般下,在实际场景中渲染一帧需要10k CPU core hours.

基本Ray Tracing算法

Light Rays定义

在图形学中一些假设:

  • 光线直线传播;
  • 两个光线相遇时,不会发生碰撞;
  • reciprocity: 光线是可逆的, 实际是从光源经过各种反射到眼睛,但是我们可以认为是从眼睛发出回溯到光源;

首先——Ray Casting 光线投射

光线投射从眼睛开始,望向物体,假设在眼睛面前存在一个屏幕,里边被分为各种像素点。

  1. 将眼睛和物体连接起来的光线与屏幕相交的地方形成一个点,多个点形成一个image;
  2. 并将投射到物体上的光线回溯到光源,以确定光源能看见物体上的该点,从而验证有无投影;

💡 在光线追踪中,使用的是Pinhole camera model,即眼睛视为点光源。

第一步:generate eye rays

从眼睛开始,望向物体,得到最近的物体上的点。一条eye ray可以与很多点相交,但是这一步只取最近的点,相当于做了深度测试

生成光线

第二步:Shading pixels

将获得的距离屏幕最近的点与光源相连,确定该点是否可见。然后对于该最近的点而言,其得到了两条线,从而可以确定法线,以便利用着色模型(Blinn Phong Model等)完成颜色的计算,然后写会到屏幕对应的像素上。

Shading pixels

上述简单的光线追踪:

  • 基本可以达到光栅化一样的效果;
  • 但是光线只能bounce一次;

Recursive(Whitted-Style) Ray Tracing

为了解决上述模型中光线只能弹射一次的问题。

原理

当eye ray射出来后,照到一个玻璃球上,会出现反射和折射,在一个点上可以无限地bounce。

在这种情况下,计算着色值的方式与上述模型不同。在上边只会计算一个最近点与光源相交后得到的着色值,现在需要计算所有的点与光源相连后的着色值,因此whitted-style下,需要将每个弹射点计算得到的着色只加到一起写到对应的像素上(除了阴影下的点)。

对每一个弹射点都需要首先确定是否能被光源看见,来确定是否包含其贡献的着色值。

Recursive(Whitted-Style) Ray Tracing

几个定义:

  • primary ray: 与第1个弹射点对应的ray
  • secondary ray: 除了第1个弹射点对应的其他ray
  • shadow ray: 与光源连接的ray;

Ray-Surface Intersection

Ray equation

光线在数学上的定义如下,

Ray is defined by its origin and a direction vector.

  • 光线起点 $\mathbf{o}$;
  • 沿着方向的单位向量;

$$
\mathbf{r}(t) = \mathbf{o} + t\mathbf{d}; \quad 0 \le t \le \infty
$$

  • 其中,$t$为时间;

Ray Intersection With Sphere

对于球的表达:

  • 定义球心 $\mathbf{c}$;
  • 球上任意一点 $\mathbf{p}$;

则对于球面上的任意一点表示如下,

$$
(\mathbf{p} - \mathbf{c})^2 - R^2 = 0
$$

当求解光线与球体的交点时,需要满足:

$$
(\mathbf{o} + t\mathbf{d} - \mathbf{c})^2 - R^2 = 0
$$

求解t即可,二次函数求解,要保证t为正实数。根据解的数量的不同可以有3种情况:

  • 相离:无解;
  • 相切:一个解
  • 相交:两个解

Ray Intersection With Implicit Surface

将情况推广到任意的隐式平面,对于任意平面,根据之前的几何部分的知识,表示如下:

$$
f(\mathbf{p}) = 0
$$

因为为了求解交点,得到如下表示:

$$
f(\mathbf{o} + t\mathbf{d}) = 0
$$

下一步就是利用各种数值计算的方法和软件完成计算即可。

Ray Intersection With Triangle Mesh(显式表示)

简单的方法

  • 将光线与每个三角形分别计算,带来的问题必然很慢。
  • 这里我们,我们只考虑光线和三角形有0或者1个交点的情况,不涉及平行的情况。

对于一个mesh,我们首先考虑针对一个三角形的交点求解,然后迭代即可。

将光线与三角形求交分解为2部分:

  1. ray-plane intersection;
  2. test if hit point is inside triangle;

根据高数中平面方程,可以通过平面的法线和面上的一点来确定平面本身。

Plane is defined by normal vector and a point on plane.

对于平面上的任意一点 $\mathbf{p}$,给定法线 \mathbf{N}和给定一点 $\mathbf{p}^{\prime}$,得到以下表示:

$$
(\mathbf{p} - \mathbf{p}^{\prime}) \cdot \mathbf{N} = 0
$$

得到表示,就可以求解交点了,满足如下条件:

$$
(\mathbf{p} - \mathbf{p}^{\prime}) \cdot \mathbf{N} = (\mathbf{o} + t\mathbf{d} - \mathbf{p}^{\prime})\cdot \mathbf{N} = 0
$$

得到:

$$
t = \frac{(\mathbf{p}^{\prime} - \mathbf{o}) \cdot \mathbf{N} }{\mathbf{d} \cdot \mathbf{N}}
$$

最后别忘了一步,判断t对应的交点是不是在三角形内部。

Möller Trumbore Algorithm
上面的方法所有简单,容易理解,但是过于繁琐。

有一种快速的方法,可以一下得到答案。

📌 一种思考方式:三角形内部一点可以使用重心坐标表示,因此判定光线与三角形相交,就可以将其表示为重心坐标的形式。

$$
\mathbf{o} + t\mathbf{d} = (1- b_1-b_2) \mathbf{p}_0 + b_1\mathbf{p}_1 + b_2\mathbf{p}_2
$$

这个方程本质上是求解线性方程组,使用Cramer’s rule完成求解(还记得这是当初学线性代数时第一个主要内容)。

完成求解后需要验证:

  • t为正实数
  • $b_1, b_2, 1-b_1 - b_2$ 为正实数,保证在三角形内部;

文章作者: alex Li
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 alex Li !
  目录