chapter 3:光线,一个简单的相机和背景
文章翻译
所有的光线追踪器都有一个ray class,并且能计算出沿着光线所能看见的颜色。让我们把光线当成一个函数,P(t)=A + tB*. 这里的 P 是三维空间中沿着光线的一个三维坐标点,A 是光线起始点,B 是光线的方向。光线函数的参数 t 是一个真实值(在代码里面是float类型)。输入不同的 t ,P 就会沿着光线运动,使用 -t,你就可以达到3维空间中直线的任何位置。对于 +t 来说,你只能得到点 A 的前面部分,这也就是经常说的线的一半或光线,例子 C = P(2) 如下:
函数 P(t) 用更详细的代码来表示,我称其为 "point_at_parameter(t) "
ray.h
#include "vec3.h"
#pragma once
class ray
{
public:
ray();
ray(const vec3 &a, const vec3 &b);
vec3 origin() const;
vec3 direction() const;
vec3 piont_at_parameter(float t) const;
public:
vec3 A;
vec3 B;
};
ray.cpp
#include "ray.h"
ray::ray()
{
}
ray::ray(const vec3 &a, const vec3 &b)
{
this->A = a;
this->B = b;
}
vec3 ray::origin() const
{
return A;
}
vec3 ray::direction() const
{
return B;
}
vec3 ray::piont_at_parameter(float t) const
{
return A + B * t;
}
现在我们准备转个弯开始做光线追踪器了,光线追踪器的核心是对每个像素点发射光线并计算出在这些光线的方向上所看见的颜色。即这样一种形式:光线从眼睛发射至像素点,计算出与光线相交处,并计算出相交点的颜色。 当第一次开发光线追踪器的时候,为了方便代码的启动和运行,我总是制作一个简单的相机。我也制作一个简单的 color 函数,执行这个函数能够返回该像素点的背景颜色。
我经常因使用正方形的图片而陷入找程序错误的麻烦,因为我太频繁的转置x和y坐标了,因此我将坚持使用200*100大小的图片。我将把眼睛(相机中心,如果你认为是相机的话)放在坐标(0,0,0),我让y轴竖直向上,让x轴朝向右边,为了尊重右手坐标系统,我让像素屏幕在-z轴。我将从屏幕的左下角开始遍历,并且使用两个偏移向量(分别在x和y上偏移),移动光线来横扫整个屏幕。记住,我并没有把光线的方向当成一个单位向量,因为我认为这并不能使代码更简洁和快速。
光线通过眼睛出发,射向像素屏幕,从左下角开始,通过修改两个偏移量来横扫整个像素屏幕
由于项目已经完成,前面vec3 class 内容比较多,就贴上源码了,后面只对书中的代码进行解释,会贴上书中对应的代码图片,但是源码就不展示了,重点在于理解书中的代码思路
color 函数依靠 y 的偏移,线性混合了白色和蓝色,我首先将光线的方向单位化(眼睛在原点,方向就是屏幕上的像素坐标),因此 -1.0 < y < 1.0 ,然后我进行了一个标准的图形技巧(即 线性差值 ),当 t = 1.0 时,我想要蓝色,当 t = 0.0 时,我想要白色。t 在两者之间时,我想要混合颜色,这种形式称为线性混合 或 线性差值,用 "lerp "来称呼会简短一些,线性差值通常是这样的形式 : blended_value = (1-t) x start_value + t x end_value,t:0~1,在我们的示例中,将会产生:
简单解释
因为眼睛在原点(0,0,0),而方向就是屏幕上的像素点,这里要有颜色渐变,实际上就是模仿天空的颜色,白色和蓝色的混合色,先让方向向量单位化,则向量中每个坐标都在-1~1之间了,我们根据y来渐变颜色,让其在 0~1之间,操作就是先 +1,再*0.5