第三章
一条射线上一点的公式如下:
p
(
t
)
=
A
+
B
∗
t
p(t) = A+\boldsymbol{B}*t
p(t)=A+B∗t
p表示的是三维空间中沿着一条直线的点。
A 是光线的起点
B(向量)是光线的方向向量
参数t是一个实数(在代码中用float表示)
当 t 取不同值得时候,p(t) 表示沿着光线移动的点。
写Ray的类Ray.h
//#ifdef RAYH
//#define RAYH
//#endif
#include "Vec3.h"
class Ray
{
public:
Ray() {}
Ray(const Vec3& a, const Vec3& b) { A = a; B = b; }
//获取光源坐标
Vec3 origin() const { return A; }
//获取光的方向向量
Vec3 direction() const { return B; }
// 光线方向上通过t 求得的某一点的坐标
Vec3 point_at_parameter(float t) const { return A + t * B; }
Vec3 A;
Vec3 B;
};
光线追踪器的核心是使光线穿过像素并计算在这些光线的方向上看到的颜色,其形式为计算从眼睛到像素的光线,相交的光线并计算 该交点的颜色。
书中写了一个简易的camera,同时编写一个color方法来return背景的颜色。
把camera(相当与人眼)放在(0,0,0)这个点,然后使用坐标系,y轴正方向向上,x轴正方向向右,z轴正方向向外,同时用u、v两个偏移向量表示点距左下角的距离。光线的方向向量的变动范围既形成光线束(camera看到画面),光线中每个光子的频率(颜色)决定这画面的内容。图中交点的u,v的值即为该像素点在整个画面中的位置。
光线追踪来画图需要2步:
- 光线方向向量的范围函数(范围,大小)
- 每条光线(像素点)设置颜色
书中代码如下:
#include <iostream>
#include <fstream>
#include "Ray.h"
using namespace std;
Vec3 Color(const Ray& r)
{
Vec3 unit_direction = unit_vector(r.direction()); //对方向向量进行标准化。
float t = 0.5 * (unit_direction.y() + 1.0);
//(1-t)*白色+t*蓝色,结果是一个蓝白的渐变
return (1.0f - t) * Vec3(1.0, 1.0, 1.0) + t * Vec3(0.5, 0.7, 1.0);
}
int main()
{
ofstream outfile;
outfile.open("firstpicture1.ppm");
int nx = 200;
int ny = 100;
outfile << "P3\n" << nx << " " << ny << "\n255\n";
Vec3 lower_left_corner(-2.0f, -1.0f, -1.0f);
Vec3 horizontal(4.0f, 0.0f, 0.0f);
Vec3 vertical(0.0f, 2.0f, 0.0f);
Vec3 origin(0.0f, 0.0f, 0.0f);
for (int j = ny - 1; j >= 0; j--)
{
for (int i = 0; i < nx; i++)
{
float u = float(i) / float(nx);
float v = float(j) / float(ny);
Ray r(origin, lower_left_corner + u * horizontal + v * vertical);
//由画面中每个像素点在画面中的相对位置每个像素点对应的光线的方向向量从而确定画面的范围/大小//
Vec3 col = Color(r); //根据光线对每一个像素点上色。
int ir = int(255.99 * col[0]);
int ig = int(255.99 * col[1]);
int ib = int(255.99 * col[2]);
outfile << ir << " " << ig << " " << ib << "\n";
}
}
outfile.close();
return 0;
}
输出得到图片为
可以改为从x轴做插值 (原文是y轴)
Vec3 Color(const Ray& r)
{
Vec3 unit_direction = unit_vector(r.direction());
float t = 0.5 * (unit_direction.x() + 1.0);
//(1-t)*白色+t*蓝色,结果是一个蓝白的渐变
return (1.0f - t) * Vec3(1.0, 1.0, 1.0) + t * Vec3(0.5, 0.7, 1.0);
}
得到
可以改变做插值的颜色
Vec3 Color(const Ray& r)
{
Vec3 unit_direction = unit_vector(r.direction());
float t = 0.5 * (unit_direction.x() + 1.0);
//(1-t)*红色+t*蓝色,结果是一个红蓝的渐变
return (1.0f - t) * Vec3(1.0, 0, 0) + t * Vec3(0, 0, 1.0);
}
补充:1.交点坐标可以表示为向量:lower_left_corner + u * horizontal + v * vertical
2.光线的方向向量 = 交点的向量 - 起点向量(其实就是交点坐标,因为原点发射光线)