0%

RayTracing.vol4

Github Repo


接下来是在原有图像上增加球体。一个球心为原点且半径为 R 的球,球上点的坐标$(x,y,z)$满足$x^2+y^2+z^2 = R^2$,球内点坐标满足$x^2+y^2+z^2 < R^2$,球外点坐标满足$x^2+y^2+z^2 > R^2$,如果球心C为$(C_x,C_y,C_z)$的话,则球体用$(x-C_x)^2+(y-C_y)^2+(z-C_z)^2 = R^2$表示,设某点 P 坐标$(x,y,z)$,则$\boldsymbol{P-C} = (x-C_x,y-C_y,z-C_z)$,不难看出$$(\boldsymbol{P-C}) \cdot (\boldsymbol{P-C})=(x-C_x)^2+(y-C_y)^2+(z-C_z)^2$$
所以用向量表示球体等式为
$$(\boldsymbol{P-C}) \cdot (\boldsymbol{P-C})=R^2$$
任何满足等式的点 P 都在球面上,更进一步,对于射线 $\boldsymbol P(t) =\boldsymbol A + t\boldsymbol b$(即 vol3 提到的 orig + dir*t),如果 P(t) 与球有交点,则
$$(\boldsymbol P(t)-\boldsymbol C)(\boldsymbol P(t)-\boldsymbol C) = R^2$$

$$(\boldsymbol A + t\boldsymbol b)(\boldsymbol A + t\boldsymbol b) = R^2$$
将等式以 $t$ 为因变量展开
$$
t^2\boldsymbol b \cdot \boldsymbol b
+2t \boldsymbol b \cdot (\boldsymbol A - \boldsymbol C)
+(\boldsymbol A - \boldsymbol C)(\boldsymbol A - \boldsymbol C)
-R^2
=0
$$
这是关于 $t$ 的一元二次方程,根据$\boldsymbol A,\boldsymbol b,\boldsymbol C,R$的值会有零个实根(无交点)、一个实根(一个交点)、两个实根(两个交点)三种情况

我画的示意图稍微与原版有出入,原版看上去像是在 $\boldsymbol b$ 不动的情况下移动 $\boldsymbol A$,但是我认为保持起点 $\boldsymbol A$ 不动更加有利于接下来的理解。
根据上文所述,对 main.rs 进行更改,增加一个 hit_sphere() 方法,在 ray_color() 中修改返回值。

[main.rs]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn hit_sphere(center: Point3, radius: f32, r: &Ray) -> bool {
let oc: Vec3 = r.origin() - center;
let a = dot(r.direction(), r.direction());
let b = 2.0 * dot(oc, r.direction());
let c = dot(oc, oc) - radius * radius;
let discriminant = b*b - 4.0 * a * c; //二次方程解的情况讨论
return discriminant > 0.0;
}
fn ray_color(r: &Ray) -> Color {
if hit_sphere(Vec3(0.0,0.0,-1.0), 0.5, r){
return Vec3(1.0, 0.0, 0.0);
}
let unit_direction = unit_vector(r.direction());
let t = 0.5 * (unit_direction.y() + 1.0);
(1.0 - t) * Vec3(1.0, 1.0, 1.0) + t * Vec3(0.5, 0.7, 1.0)
}


图像上的圆被红色(255,0,0)覆盖,像是反射或者光影都没有,而且还有一些问题,当圆心为(0,0,1)时,程序输出的结果与上图一致,但是现实中并非如此,在观察点观察方向相反方向的物体是不会呈现在画面上的。