LOFTER for ipad —— 让兴趣,更有趣

点击下载 关闭
一周学会光线追踪:理论和实战(一)

学习知识,要从底层开始,这篇博客用以记录我学习《Ray Tracing in One Weekend》的过程。主要是实现它和自主翻译(并不是完整翻译,只是我认为重要的)。

1. 前言

        本系列博客采用C++语言实现,尽可能的多使用C++的“现代特性”。这里不使用图形库API例如OpenGL,DirectX等,只是渲染在一张图片上。使用了glm的向量库(GitHub: g-truc/glm)来进行向量运算和svpng(GitHub: miloyip/svpng)来显示渲染结果。

2. 输出一张图片

2.1. ppm图像格式

        我们这里将渲染的结果展示到一张图像上,但图像的格式非常之多,这里使用PPM格式的图像作为输出的结果。Wikipedia上的介绍如下图:

实现的要点和代码如下:

1. 像素的顺序是从左到右从上到下。

2. 长256像素单位,宽256像素单位。

3. 规定在RGB图像中红,绿,蓝的数值为0-1。之后可以映射到0-255的范围内。

4. 准备创建一个记录自左向右红色从无(黑色)到有(完全红色),绿色自底向上从无到有,蓝色为常数的过程。所以可以得出这张图片左下是黑色的右上是红和绿的混合的黄色。

5. 为了方便显示,我使用了svpng库,来记录渲染的图像。

代码如下:

运行后可以在工程根目录看到结果,结果如下:

太棒了!这就是一个“hello world”程序,如果你无法看到这个结果,那意味这步骤可能出错了。

2.2. 添加渲染知识进度:

        如果进行复杂的渲染时,在程序中添加一些指示性的标语,我们就可以知道现在渲染到哪一步了,并且也有利于我们检查深层的问题。例如在循环中添加上std::cout或是std::cerr,std::flush等。

3. 向量类

        这里介绍了向量类,比如点乘和叉乘等向量的数学运算。可以自己动手实现,但我在这里用了glm库,省去了这一麻烦。还有可以使用using指令来创造Color,Point这些可以近似用向量来表达的类,这些都写在RTWeekend.h中:

        之后可以建立一个工具函数来完成将颜色写入缓冲区的操作:

        然后我们的main函数可以变成如下所示的样子:

4. 光线,一个简单的相机和背景

4.1. 光线类:

        光线类是光线追踪器的基本类,它的作用是用来计算光线路径上看到的颜色。光线的方程为P(t)=A+tb,其中P是3d空间位置,A是光源点3d空间位置,t是一个实数(在代码中一般用double类型),可以是正的也可以是负的。正值为A前面部分,可以理解为3d空间的一条射线,再加上负值,A后面部分,就可以研究这条线的任意位置。

        我将这个方程改写为名为Ray::At(t)的函数:

        这里的ray_color暂且留到下文讨论。

4.2. 在场景中发射光线

        有了光线类,我们要关心的就是如何进行光线追踪。主要来讲,光线追踪就是在场景中发射一些光线,然后从它们的方向出发来计算这些光线所看到的颜色。

        相关的步骤如下:

        1. 计算从眼睛到像素的光线

        2. 确认光线和哪些物体相交

        3.计算该交点的颜色

        在第一次光线追踪中,通常使用摄像机来当作人的眼睛,从摄像机发射出一条光线来开始程序的运行。这里使用ray_color函数来返回背景的颜色(一个简单的从上到下的蓝色渐变)。

        这里没有使用正方向的图像,而是使用了常见的16:9屏幕宽高比。

        处理渲染图像的大小,我们还需要一个虚拟视口,用来传递场景光线。对于矩形的像素空间,视口的宽高比应该与渲染图象相同。这里使用两个单位长度作为视窗的高。同时,我们将投影平面和投影点之间的距离称为“焦长(focus length)”为一个的单位长度,这个概念要和“焦距(focus distance)”区别开,下文中会提及。

        接下来,将“眼睛”(即相机中心)放在(0,0,0)位置上。自该点建立执教坐标系,y轴自下而上,x轴自左向右,根据常用的左手坐标系,z轴自屏幕上向屏幕外。我们将从屏幕的左上角开始遍历,同时,使用了两个偏移向量来表示光线投射到投影面上(即屏幕)的位置。请注意,我们没有将光线方向设置为单位长度的向量,这样可能会加快运算速度。

        在下面的代码中,光线r大致指向像素的中心(现在不必要担心精确与否,因为一会还需要抗锯齿)。

        ray_color函数,在代码在4.1.可以看到,将光线方向置为单位长度后,该函式会在y轴方向线性混合蓝色和白色(即 -1.0 < y < 1.0)。因为在单位化后,我们可以观察到的除了垂直渐变还有水平渐变。

        我们设置这样一个规则,将变量t的取值置为0.0到1.0,当t取0.0时颜色是白色,取1.0时颜色是蓝色,中间值则是白色和蓝色的混合。混合采用“线性混合”或者叫做“线性插值”亦或是在两者之间的“过渡”。它遵从的规则为:

    结果如下:

    

推荐文章
评论(0)
分享到
转载我的主页