保持前一章的其他头文件不变,在main.cpp添加如下代码:
#include"vec3.h"
#include"ray.h"
#include"color.h"
#include<iostream>
//设球心为C = (Cx,Cy,Cz)
//球的一般表示公式:(x - Cx)^2 +(y - Cy)^2 +(z - Cz)^2 = r^2
//球上取任一点P(x,y,z) ,则有(P -C)(P -C) = r^2
//带入光线方程P(t) = A + tb,P是沿着这条线的3d位置,A是光线原点,b是光线方向,则有:(A + tb - C)(A + tb - C) = r^2
//解开方程得到:b*bt^2 + (2b * (A - C))t + (A - C)*(A - C) -r^2 = 0,t为未知数,只需要求根公式大于0,则得到光线是击中球的
bool Hit_Sphere(const point3& center, float radius, const ray& r)
{
auto lightSourceToSphereCenter = r.origin() - center;
auto a = dot(r.direction(), r.direction());
auto b = 2 * dot(r.direction(), lightSourceToSphereCenter);
auto c = dot(lightSourceToSphereCenter,lightSourceToSphereCenter) - radius * radius;
auto rootFunction = b * b - 4 * a * c;
return(rootFunction > 0);
}
color ray_color(const ray& r)
{
if (Hit_Sphere(point3(0, 0, -1), 0.5, r))
{
return color(1,1,0);
}
vec3 unit_direction = unit_vector(r.direction());
auto t = 0.5f * (unit_direction.y() + 1.0f);
//(1−t)×c1 + t×c2 线性插值
return (1.f - t) * color(1.f, 1.f, 1.f) + t * color(0.5f, 0.7f, 1.f);
}
int main()
{
//定义了一个关于图像和相机的基本参数:
//图像部分:定义了图像的宽高比,以及宽度和高度。宽高比是在之前的代码中定义的,宽度为400像素,高度根据宽高比计算得出。
//相机部分:定义了视口的宽高以及焦距。视口是指相机能够看到的范围,这里的视口宽度是根据宽高比和视口高度计算得出的;
// 焦距表示了相机的聚焦程度,这里设为1。还定义了相机的位置,以及一个水平方向向量、垂直方向向量和左下角的位置,这些都是
// 计算相机拍摄视角时需要用到的基本参数。
//image
const auto aspect_ratio = 16.f / 9.f;
const int image_width = 400;
const int image_height = static_cast<int>(image_width / aspect_ratio);
//camera
auto viewport_height = 2.f;
auto viewport_width = aspect_ratio * viewport_height;
auto focal_length = 1.f;
auto origin = point3(0, 0, 0);
auto horizontal = vec3(viewport_width, 0, 0);
auto vertical = vec3(0, viewport_height, 0);
auto lower_left_corner = origin - horizontal / 2 - vertical / 2 - vec3(0, 0, focal_length);
//render
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
//由于PPM文件格式规定像素行是从文件的底部开始写入的,而每一行的像素是从左向右依次排列的,
//因此在遍历时需要先从最后一行开始循环遍历,再往上逐行遍历,以保证输出的像素数据符合PPM文件格式的要求
for (int i = image_height - 1; i >= 0; --i)
{
//通过一个外层循环,从图像的最后一行开始,往前逐行扫描。
//在内层循环中,对于每行中的每个像素,计算出其在图像中的位置(即相对于左下角的水平和垂直方向上的偏移量),从而确定了该像素对应的射线方向。
//使用 ray_color() 函数计算出该射线的颜色,即该像素的颜色。
//将该像素的颜色输出到标准输出流中,以便最终能够将其保存为图像文件。
std::cerr << "\r Scanlines remaining: " << i << ' ' << std::flush;
for (int j = 0; j < image_width; ++j)
{
auto u = float(j) / (image_width - 1);
auto v = float(i) / (image_height - 1);
ray r(origin, lower_left_corner + u * horizontal + v * vertical - origin);
color pixel_color = ray_color(r);
write_color(std::cout, pixel_color);
}
}
std::cerr << "\nDone.\n";
}
得到如下图: