Whitted-style光线追踪原理及其实现细节

本篇内容主要分为两部分,第一部分会从为什么需要光线追踪入手,一步步介绍Whitted-style光线追踪的原理。第二部分则会具体介绍一些光线追踪的实现细节,包括光线的表示,光线与物体的求交,以及反射折射方向的计算。

1 Whitted-Style 光线追踪

在进入原理讲解之前,我们首先考虑一下为什么需要光线追踪呢? **因为Blinn-Phong这种局部模型无法处理全局效果!**如上图中房屋顶部的所接受到的光可不仅仅是Blinn-Phong模型考虑的直接光源,还有可能是来自窗外的光源照射到地板,再发生反射照射到了房屋顶部,而这部分光是局部光照模型没有考虑到的,而光线追踪正是为了解决这种问题所提出的一种考虑全局效果的光照模型。

1.1 光线追踪原理解释

光线追踪听名字就知道,讨论的核心是光线,因此我们首先对光线做一些假设。

1 光线一定沿着直线传播

2 光线之间无法碰撞

3 光线路径可逆,即从A发出的到B的光线,一定也可以从B发出到A(中途可发生反射和折射)

明白了光线的一些假设之后,想一想人为什么能看到不同的物体?是因为从物体表面上有光进入了人眼。那么能不能逆向思考一下,是不是也可理解为人眼发出了很多感知光线碰撞到了物体,所以可以看见呢?在古代可还真就有不少人这么想:

当然,现代物理知识已经告诉我们这种观点是错误的,但是并不妨碍从中获取一些灵感,考虑一下对光线的第三条假设:光路可逆,所有进入到人眼的光,都可从人眼发出光按照原路反方向返回,那么利用这种模拟从人眼发射光线的方法不就可以还原出所有的光路了呢?没错这就是光线追踪的核心想法,从光源出发难以模拟那就反着从摄像机发射光线! 第一步 Ray Casting

从人眼或摄像机向近投影平面上的每一个像素点发射一条光线,判断与场景物体的交点,示意图如下: 当然一条光线自然可能会与不止一个物体相交,但是考虑遮挡关系,只去找最近的交点。接着连接该交点和光源,只要判断这条连线之间是否有物体存在就可以知道该交点是否在阴影之中(怎么样,是不是比shadow mapping那一套简单了许多): 紧接着,自然可以利用Blinn-Phong模型对这个点进行局部光照模型计算,得到该像素的颜色,那么遍历所有近投影平面上的像素就能得到一张完整的图像。但如果光线追踪仅仅是在第一步Ray Casting就停止的话,那么它的效果与局部光照模型是一样的,因此我们需要第二步,真正的考虑全局效果

第二步 Recursive (Whitted-Style) Ray Tracing 考虑第一步中所做的Ray Casting,该条光线第一个与圆球物体相交,假设该圆球是一个玻璃球,那么便会发生镜面反射,如图:

当然除了镜面反射之外,自然也存在折射,同时反射与折射出去的光线会可能与场景中的物体再次碰撞,发生第二次折射与反射:

(为了图示清晰,图中仅以两次折射或反射的部分光线为例) 从图中可以见到,不仅仅是与圆球相交的那一点可以贡献光到达眼睛,折射与反射之后再与物体相交的点也可以贡献光(光路可逆原理)。简而言之,除了直接从光源照射到圆球交点再沿着 eye rays(从眼睛发射的第一条光线)到眼睛中,也可能存在这样一种情形,有光照射到其他物体,再沿着eye rays的反射或折射的光线方向传回人眼!

因此每一个交点的颜色贡献来自这样种几类型 直接光照,反射方向间接光,折射方向间接光(如果有折射的话)

下一步将这些所有交点与光源连接,称这些线为shadow rays(因为可以用来检测阴影),计算这些所有点的局部光照模型的结果,将其按照光线能量权重累加(该做法与递归过程等价,读者可以看看伪代码思考一下),最终得到近投影平面上该像素点的颜色!而这就是一个考虑全局效果的光照模型了,因为不仅仅考虑了直接光源的贡献,还考虑各种折射与反射光线的贡献。

以上就是光线追踪的整个过程了,还有额外几点要注意的 tips:

  1. 整体过程是一个递归的过程,因此需要一定的递归终止条件,比如说允许的最大反射或折射次数为10。
  2. 光线在每次反射和折射之后都有能量损耗的,由系数决定,因此越往后的折射和反射光贡献的能量越小,这也是为什么在上文中提到根据光线能量权重求和。 e.g. 反射系数为0.7,那么第一次反射折损30%,第二次反射折损1-(70%x70%),依次类推。
  3. 如果反射或折射光线没有碰撞到物体,一般直接返回一个背景色。
  4. 有一些关于光线表示,及如何求交点的实现细节在1.2节里讨论。

2 光线的表示方法

我们可以将每一条光线想象成一条射线,那么每一条光线都会由起点及方向这两个属性所固定,如下图所示:

3 光线与物体求交的方法

利用线性代数的方法

4 反射与折射

4.1 反射方向的计算

反射方向计算相对容易,如下图所示,已知 l\bold{l},n\bold{n}想要求出反射方向r\bold{r}

Note:whited-style光线追踪该如何考虑漫反射?

在Blin-Phong模型中层提到过,漫反射是光线照射到粗糙物体表面从而发生向周围均匀反射光线的一种现象,反射的光线可以说是无数的!

那么对于这种反射,在光线追踪该怎么处理呢?借鉴**RayTracingInOneWeekend** 里的做法,对于漫反射表面每次进行反射的时候,随机的选取物体表面向外半圆内的一个方向作为该次反射的方向,对其再像镜面反射及折射一样进行递归的光线追踪计算。

但对每一个像素不仅仅只发出一条感知光线,利用多条光线RayTracing的结果求均值,最终作为该像素的颜色值

比如说我每个像素sample 1000条光线,如果撞到漫反射表面那就是1000条随机方向的 RayTracing结果的均值,这样便能较为准确的模拟了漫反射表面的特性了。 (对一个像素进行多次sample,其实也就把抗锯齿也给做了)

(tips: 该方法其实更多算是path tracing,经典的whited-style光线追踪遇到漫反射表面会直接利用blinn-phong模型计算颜色值返回,而不再递归下去)

总结

至此我们已经了解了光线追踪的原理,明白了光线的表示以及光线与隐式曲面,显示曲面的求交方法,同时也介绍了折射反射方向的计算,以及菲涅尔项等细节内容,相信读者已经可以自己去尝试写一个光线追踪器的出来了,当然也可以去参考闫老师的作业以及文中所提到的RayTracingInOneWeekend里的做法。

13 加速光线追踪

15 蒙特卡洛路径追踪

(27 封私信 / 80 条消息) 孙小磊 - 知乎 (zhihu.com)

摘要

在上一篇文章中,我们通过对辐射度量学当中一系列概念的定义,引入了渲染方程,一个正确的光线传播模型,但并没有去涉及如何解出该渲染方程,或者说如何通过该渲染方程计算出屏幕上每一个坐标的像素值。在本篇文章中会利用蒙特卡洛路径追踪来完成这个目标。

1 蒙特卡洛积分(Monte Carlo Integration)

首先让我们先搞懂蒙特卡洛路径追踪的这个“蒙特卡洛”的前缀到底指什么。

蒙特卡洛积分的目的: 当一个积分很难通过解析的方式得到答案的时候可以通过蒙特卡洛的方式近似得到积分结果,如下图所示:

显然对于这样一个函数,很难去用一个数学式子去表示,因此无法用一般解析的方法直接求得积分值,而这时候就可以采用蒙特卡洛的思想了。

蒙特卡洛积分的原理及做法: 对函数值进行多次采样求均值作为积分值的近似

该做法十分容易理解,想象一下如果对上图这个函数值进行均匀采样的话,其实就相当于将整个积分面积切成了许许多多个长方形,然后将这些小长方形的面积全部加起来。没错,该做法其实就与黎曼积分的想法几乎一致。但蒙特卡洛积分更加的general,因为它可以指定一个分布来对被积分的值进行采样,定义如下: