第四章 画球
已经画出了基本的背景图了,现在可以学着加一些物体进去,作者给的是画一个球。
(一个光线代表着一个像素点)
画图的基本步骤
- 确定球的位置。(球上每个像素点的位置即为光线与球的交点,所有这些交点就组成了球。所以,问题转化为找光线和球的交点)
- 设置球的颜色。(光线和球交点的颜色)
球体方程
方程等价于:
球上任一点的坐标(向量)为p,而 c 表示小球圆心, R 表示小球半径
带入到光线公式得到
转化为
由此来改写之前的代码,将公式写进代码里,我们在z = − 1 处放置一个小球
#include <iostream>
#include <fstream>
#include "Ray.h"
using namespace std;
//判断光线有没有撞上球体
bool hit_sphere(const Vec3& center, float radius, const Ray& r)
{
Vec3 oc = r.origin() - center; //向量A-C=oc
float a = dot(r.direction(), r.direction()); //a = (B·B)=dot(B,B),
float b = 2.0f * dot(oc, r.direction()); // b=2*(B·(A-C))=2*dot(B,(A-C))
float c = dot(oc, oc) - radius * radius; //c= (A-C)·(A-C) - R2=dot((A-C),(A-C)) - R2
float discrimiant = b * b - 4.0f * a * c; //判别式
return (discrimiant > 0.0f);//判别式>0,有实根,光线撞上球,返回1;
//判别式<0,没有实根,光线没有撞上球,返回0;
}
Vec3 Color(const Ray& r)
{
// 小球位于(0,0,-1),半径为0.5
if (hit_sphere(Vec3(0.0f, 0.0f, -1.0f), 0.5f, r))
return Vec3(1.0f, 0.0f, 0.0f);
//此处判断这条光线是否撞上球。如果撞上,则执行vec3(1, 0, 0),将这个像素点设置为红色。
Vec3 unit_direction = unit_vector(r.direction());
// 标准化之后的y值值域为[-1, 1], 将其映射到[0, 1]
float t = 0.5f * (unit_direction.y() + 1.0f);
return (1.0f - t) * Vec3(1.0f, 1.0f, 1.0f) + t * Vec3(0.5f, 0.7f, 1.0f);
}
int main()
{
ofstream outfile;
outfile.open("firstpicture2.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;
}
得到的图片为
可以更改小球的半径为0.8
if (hit_sphere(Vec3(0.0f, 0.0f, -1.0f), 0.8f, r))
return Vec3(1.0f, 0.0f, 0.0f);
得到
或者更改小球位置坐标
if (hit_sphere(Vec3(0.0f, 0.0f, -5.0f), 0.5f, r))
return Vec3(1.0f, 0.0f, 0.0f);
得到图片