光线追踪4- Adding a sphere

本文介绍了如何在光线追踪中通过数学公式计算光线与球体的相交问题,包括使用向量和二次方程的处理,以及在C++代码中的实现。作者展示了如何通过`hit_sphere`函数检查光线与球体的碰撞,并指出当前实现仅考虑了一个简单的例子,后续将涉及阴影、反射和多物体处理。
摘要由CSDN通过智能技术生成

在光线追踪中添加一个物体。人们常常在光线追踪中使用球体,因为计算光线是否击中球体相对简单。

5.1 光线与球体的相交计算

一个以原点为中心、半径为r的球体的数学方程是一个重要的数学方程:
x^2+y^2+z^2=r^2
    您可以这样理解:如果一个给定的点 (x, y, z) 在球体上,那么它满足方程
x^2+y^2+z^2=r^2
如果一个给定的点 (x, y, z) 在球体内部,那么它满足不等式 x^2+y^2+z^2<r^2
如果一个给定的点 (x, y, z) 在球体外部,那么它满足不等式 x^2+y^2+z^2>r^2
如果我们想让球体的中心可以位于任意点(Cx, Cy, Cz),那么这个方程将变得更为复杂:
    (x−Cx)²+(y−Cy)²+(z−Cz)²=r²
    在图形学中,你几乎总是希望将公式表达为向量的形式,这样所有涉及 x、y、z 的部分都可以简单地用一个 vec3 类来表示。你可能已经注意到,从中心 C=(Cx, Cy, Cz) 到点 P=(x, y, z) 的向量可以表示为 (P−C)。如果我们使用点积的定义:
(P−C)*(P−C)=(x−Cx)²+(y−Cy)²+(z−Cz)²
那么我们可以将球体的方程以向量形式重新写成:
(P−C)*(P−C)=r²
    我们可以将其理解为“满足这个方程的任意点 P 都在球体上”。我们想知道我们的光线 P(t)=A+tb 是否会击中球体的某个位置。如果它确实击中了球体,则存在某个t值,使得 P(t) 满足球体方程。因此,我们正在寻找任何满足这个条件的 t 值:
(P(t)−C)*(P(t)−C)=r²

可以通过将 P(t) 的扩展形式代入来找到该值:
((A+tb)−C)*((A+tb)−C)=r²
    在左边我们有三个向量点乘右边的三个向量。如果我们解出全部的点乘积,会得到九个向量。你可以逐项列出并计算,但我们没必要这么费力。如果记得的话,我们想要解出 t 的值,因此我们将项分为是否包含t:
(tb+(A−C))*(tb+(A−C))=r²
现在我们按照向量代数的规则来分配点乘运算:
t²b*b + 2tb*(A−C) + (A−C)*(A−C) = r²
将半径的平方移到左边:
t²b*b + 2tb*(A−C) + (A−C)*(A−C)  r² = 0
    很难确定这个方程的具体含义,但是方程中的向量和半径 r 都是常量并已知。此外,我们通过点积将所有向量化简为标量。唯一的未知数是 t,并且我们有一个 t
²,这意味着这个方程是二次方程。可以使用二次方程公式来解决二次方程:

对于光线和球体的相交,a、b、c的值是:

a = b*b
b = 2b*(A - C)
c = (A - C) * (A - C) - r²
    利用上述所有的内容,你可以解出t,但是有一个平方根部分可能是正(表示有两个实数解),负(表示没有实数解)或者零(表示有一个实数解)。在图形学中,代数几乎总是与几何直接相关的。我们有以下内容:


5.2 创建我们的第一张光线追踪图像
如果我们将这个数学公式硬编码到我们的程序中,我们可以通过在z轴上将一个小球放置在-1位,并将与其相交的像素块标记为红色来测试我们的代码。

#include "color.h"
#include "ray.h"
#include "vec3.h"

bool hit_sphere(const point3& center, double radius, const ray& r) {
	 vec3 oc = r.origin() - center; 
	auto a = dot(r.direction(), r.direction());
	auto b = 2.0 * dot(oc, r.direction()); 
	auto c = dot(oc, oc) - radius*radius; 
	auto discriminant = b*b - 4*a*c; 
	return (discriminant >= 0);
}

color ray_color(const ray& r) {
if (hit_sphere(point3(0,0,-1), 0.5, r)) 
	return color(1, 0, 0);
	vec3 unit_direction = unit_vector(r.direction());    
	auto a = 0.5*(unit_direction.y() + 1.0);    
	return (1.0-a)*color(1.0, 1.0, 1.0) + a*color(0.5, 0.7, 1.0);
}

运行得到: 

现在这个场景缺少了很多东西,比如阴影、反射光线和多个物体,但我们离目标完成的一半要比刚开始时更接近!需要注意的一点是,我们正在测试光线是否与球体相交,通过求解二次方程并判断是否存在解来进行判断,但含有负值的解同样完全有效。如果您将球体的中心位置改为 z=+1,您将得到完全相同的图像,因为该解并不能区分相机前方的物体和相机后方的物体。这并不是我们想要的结果!接下来我们将修复这些问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值