101 lines
2.8 KiB
Rust
101 lines
2.8 KiB
Rust
use crate::{
|
|
aabb::{surrounding_box, AABB},
|
|
hitable::{Hit, HitRecord},
|
|
material::Material,
|
|
ray::Ray,
|
|
sphere::get_sphere_uv,
|
|
vec3::{dot, Vec3},
|
|
};
|
|
|
|
pub struct MovingSphere<M>
|
|
where
|
|
M: Material,
|
|
{
|
|
center0: Vec3,
|
|
center1: Vec3,
|
|
radius: f32,
|
|
material: M,
|
|
time0: f32,
|
|
time1: f32,
|
|
}
|
|
|
|
impl<M> MovingSphere<M>
|
|
where
|
|
M: Material,
|
|
{
|
|
pub fn new(
|
|
center0: Vec3,
|
|
center1: Vec3,
|
|
radius: f32,
|
|
time0: f32,
|
|
time1: f32,
|
|
material: M,
|
|
) -> MovingSphere<M> {
|
|
MovingSphere {
|
|
center0,
|
|
center1,
|
|
radius,
|
|
material,
|
|
time0,
|
|
time1,
|
|
}
|
|
}
|
|
fn center(&self, time: f32) -> Vec3 {
|
|
self.center0
|
|
+ ((time - self.time0) / (self.time1 - self.time0)) * (self.center1 - self.center0)
|
|
}
|
|
}
|
|
|
|
impl<M> Hit for MovingSphere<M>
|
|
where
|
|
M: Material,
|
|
{
|
|
fn hit(&self, r: Ray, t0: f32, t1: f32) -> Option<HitRecord> {
|
|
let oc = r.origin - self.center(r.time);
|
|
let a = dot(r.direction, r.direction);
|
|
let b = dot(oc, r.direction);
|
|
let c = dot(oc, oc) - self.radius * self.radius;
|
|
let discriminant = b * b - a * c;
|
|
if discriminant > 0. {
|
|
let temp = (-b - (b * b - a * c).sqrt()) / a;
|
|
if temp < t1 && temp > t0 {
|
|
let point = r.point_at_parameter(temp);
|
|
let uv = get_sphere_uv((point - self.center(r.time)) / self.radius);
|
|
return Some(HitRecord {
|
|
t: temp,
|
|
uv,
|
|
p: point,
|
|
normal: (point - self.center(r.time)) / self.radius,
|
|
material: &self.material,
|
|
});
|
|
}
|
|
let temp = (-b + (b * b - a * c).sqrt()) / a;
|
|
if temp < t1 && temp > t0 {
|
|
let point = r.point_at_parameter(temp);
|
|
let uv = get_sphere_uv((point - self.center(r.time)) / self.radius);
|
|
return Some(HitRecord {
|
|
t: temp,
|
|
uv,
|
|
p: point,
|
|
normal: (point - self.center(r.time)) / self.radius,
|
|
material: &self.material,
|
|
});
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
|
let t_min_bb = AABB::new(
|
|
self.center0 - Vec3::new(self.radius, self.radius, self.radius),
|
|
self.center0 + Vec3::new(self.radius, self.radius, self.radius),
|
|
);
|
|
|
|
let t_max_bb = AABB::new(
|
|
self.center1 - Vec3::new(self.radius, self.radius, self.radius),
|
|
self.center1 + Vec3::new(self.radius, self.radius, self.radius),
|
|
);
|
|
Some(surrounding_box(&t_min_bb, &t_max_bb))
|
|
}
|
|
}
|