use crate::{ aabb::{surrounding_box, AABB}, hitable::{Hit, HitRecord}, material::Material, ray::Ray, sphere::get_sphere_uv, vec3::{dot, Vec3}, }; #[derive(Debug)] pub struct MovingSphere where M: Material, { center0: Vec3, center1: Vec3, radius: f32, material: M, time0: f32, time1: f32, } impl MovingSphere where M: Material, { pub fn new( center0: Vec3, center1: Vec3, radius: f32, time0: f32, time1: f32, material: M, ) -> MovingSphere { 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 Hit for MovingSphere where M: Material, { fn hit(&self, r: Ray, t0: f32, t1: f32) -> Option { 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 { 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)) } }