use crate::hittable::{Hit, Hittable}; use crate::material::Material; use crate::ray::Ray; use cgmath::prelude::*; use cgmath::{dot, Vector3}; use core::borrow::Borrow; pub struct Sphere { center0: Vector3, center1: Vector3, time0: f64, time1: f64, radius: f64, material: Box, } impl Sphere { pub fn new( center: Vector3, time0: f64, time1: f64, radius: f64, material: Box, ) -> Sphere { Sphere { center0: center, center1: center, time0, time1, radius, material, } } pub fn new_moving( center0: Vector3, center1: Vector3, time0: f64, time1: f64, radius: f64, material: Box, ) -> Sphere { Sphere { center0, center1, time0, time1, radius, material, } } pub fn center(&self, time: f64) -> Vector3 { self.center0 + ((time - self.time0) / (self.time1 - self.time0)) * (self.center1 - self.center0) } } impl Hittable for Sphere { fn is_hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option { let oc = ray.orig - self.center(ray.time); let a = ray.dir.magnitude2(); let b = dot(oc, ray.dir); let c = oc.magnitude2() - self.radius * self.radius; let discriminant = b * b - a * c; if discriminant > 0.0 { let soln = (-b - discriminant.sqrt()) / a; if soln < t_max && soln > t_min { return Some(Hit::new( ray, soln, (ray.at(soln) - self.center(ray.time)) / self.radius, self.material.borrow(), )); } let soln = (-b + discriminant.sqrt()) / a; if soln < t_max && soln > t_min { return Some(Hit::new( ray, soln, (ray.at(soln) - self.center(ray.time)) / self.radius, self.material.borrow(), )); } } None } }