raytracers/rtiow/renderer/src/moving_sphere.rs
2022-07-28 21:39:00 -07:00

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))
}
}