Chapter 4: Adding a sphere
初高中学过球体的公式:
x∗x+y∗y+z∗z=R∗R
即点p(x,y,z),若满足上方程,即在球上。
对于中心在C(cx,cy,cz)的球体:
(x−cx)∗(x−cx)+(y−cy)∗(y−cy)+(z−cz)∗(z−cz)=R∗R
上式也可根据p、C两点写作向量的形式:
dot((p−C),(p−C))=R∗R=(x−cx)∗(x−cx)+(y−cy)∗(y−cy)+(z−cz)∗(z−cz)
可以把点 p 换做 Ray 上一点 p(t):
dot((p(t)−C),(p(t)−C))=R∗R
也写作
dot((A+t∗B−C),(A+t∗B−C))=R∗R
可进一步写作
t∗t∗dot(B,B)+2∗t∗dot(A−C,A−C)+dot(C,C)−R∗R=0
分析此等式,发现其就是我们学过的一元二次方程,根据求根公式就可判断方程有无根,即射线有没有与球体相交。
修改 Main.cpp 中部分代码如下:
bool hit_sphere(const Vec3& center, float radius, const Ray& r)
{
Vec3 oc = r.origin() - center;
float a = dot(r.direction(), r.direction());
float b = 2.0f*dot(oc, r.direction());
float c = dot(oc, oc) - radius*radius;
float discrimiant = b*b - 4.0f*a*c;
return (discrimiant > 0.0f);
}
Vec3 Color(const Ray& r)
{
if (hit_sphere(Vec3(0.0f, 0.0f, -1.0f), 0.5f, r))
return Vec3(1.0f, 0.0f, 0.0f);
Vec3 unit_direction = unit_vector(r.direction());
float t = 0.5f*(unit_direction.y() + 1.0f);
//(1-t)*白色+t*蓝色,结果是一个蓝白的渐变
return (1.0f - t)*Vec3(1.0f, 1.0f, 1.0f) + t*Vec3(0.5f, 0.7f, 1.0f);
}
运行,结果如下:
(吐槽:怎么有点像霓虹国国旗呢)