前言
本节中实现了通过光源向背景投射光线的效果,借助光线对画布进行着色。
正文
1. 实现一个简单的光线类
依据公式
其中 A表示光源坐标, B表示光线方向。
#ifndef RAY_H
#define RAY_H
#include "vec3.h"
class ray
{
public:
ray() {}
ray(const vec3& a, const vec3& b) { origin = a; direction = b; }
// 获取光源坐标
vec3 getOrigin() const { return origin; }
// 获取光的方向向量
vec3 getDirection() const { return direction; }
// 光线方向上通过t 求得的某一点的坐标
vec3 getPointAtParameter(float t) const { return origin + t * direction; }
vec3 origin;
vec3 direction;
};
#endif
2. 在背景上做投射
其中光线与屏幕交点的坐标可以表示为
#include <iostream>
#include <fstream>
#include "vec3.h"
#include "ray.h"
vec3 color(const ray& r) {
vec3 unit_direction = unit_vector(r.getDirection());
float t = 0.5 * (unit_direction.x() + 1.0);
return (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
}
void main() {
int nx = 200;
int ny = 100;
std::ofstream outfile("PPMTest.ppm", std::ios_base::out);
outfile << "P3\n" << nx << " " << ny << "\n255\n";
std::cout << "P3\n" << nx << " " << ny << "\n255\n";
// -------- 位置参数 -------- //
vec3 lower_left_corner(-2.0, -1.0, -1.0);
vec3 horizontal(4.0, 0.0, 0.0);
vec3 vertical(0.0, 2.0, 0.0);
vec3 origin(0.0, 0.0, 0.0);
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";
std::cout << ir << " " << ig << " " << ib << "\n";
}
}
}
运行结果
将输出文件改为ppm格式,图片结果如下:
(书中代码生成的图片沿y轴方向做渐变,这里稍微改动了下,沿x轴做渐变)