在过去的一个周,读完了《Ray Tracing in One Weekend》并且用Rust完整地实现了文章中的效果。对于经典的光线追踪逻辑,也有了宏观上的理解。

简单来讲,假设我们要将一个场景渲染成一张1920x1080的图片。光线追踪,就是从摄相机出发,经过每一个像素,向场景中发射一条光线,这条光线会撞到场景中某一个物体上某一个点。这条光线的强度,会产生一定的衰减,然后再次被散射出去。而散射出去后,可能又会撞到另一个物体上的某个点,再次衰减,再次被散射。不断递归这个过程。

每次撞到一个点,就可以计算这个点的颜色。在整个过程中,所有撞到的点的颜色叠加,就是这个像素最终的颜色。光线上的散射,也就是递归的过程,不会是无限的,一般由我们定义递归深度,也就是散射多少次后,就停。或者没有撞到任何物体时,也会直接停止递归,返回背景或天空盒颜色。

看下面图中的右边图示部分

raytracing.png

下面是来自维基百科光线追踪条目中的伪代码

对图像中的每一个像素 {
  创建从视点通过该像素的光线
  初始化最近T 为无限大,最近物体为空值

  对场景中的每一个物体 {
     如果光线与物体相交 {
        如果交点处的t 比最近T  {
           设置最近T 为交点的t 
           设置最近物体为该物体
        }
     }
  }

  如果最近物体为空值{
     用背景色填充该像素
  } 否则 {
     对每个光源射出一条光线来检测是否处在阴影中
     如果表面是反射面,生成反射光;递归
     如果表面透明,生成折射光;递归
     使用最近物体和最近T 来计算着色函数
     以着色函数的结果填充该像素
  }
}

上面所描述的,是光线追踪的宏观过程,真正产品中的光线追踪,还会有很多很多的细节。 例如,每一个点的颜色,是由材质决定的,不同的材质,吸收光的程度不一样,散射光的程度也不一样。例如木块和玻璃。点的颜色,还要加上场景中的灯光影响,等等。

光线追踪的计算量很大,上面的教程中,只是渲染一张图,而这只能算是一帧。在游戏中,流畅的画面至少要达到30帧,所以,需要硬件的加速。

在学习的过程中,涉及到的一些数学计算,虽然代码实现出来了,但是并没有透彻地理解,对于我来说,这一点还需要加强。

工程源代码: https://github.com/imoegirl/raytracing-rs

最终渲染图: