use std::ops::Deref; use crate::hittable::*; use crate::material::Material; use crate::vec3::*; use crate::Ray; pub struct Sphere { center: Point3, radius: f64, material: Box, } impl Sphere { pub fn new(center: Point3, radius: f64, material: Box) -> Self { Sphere {center, radius, material} } } impl Hittable for Sphere { fn hit(&self, r: &Ray, t_min: f64, t_max: f64) -> Option> { let oc = r.origin() - self.center; let a = r.direction().length_squared(); let half_b = oc.dot(&r.direction()); let c = oc.length_squared() - self.radius * self.radius; let discriminant = half_b * half_b - a * c; if discriminant < 0.0 { return None; } let sqrtd = discriminant.sqrt(); // Find the nearest root that lies in the acceptable range let mut root = (-half_b - sqrtd) / a; if root < t_min || t_max < root { root = (-half_b + sqrtd) / a; if root < t_min || t_max < root { return None; } } let p = r.at(root); let outward_normal = (p - self.center) / self.radius; let front_face = r.direction().dot(&outward_normal) < 0.0; let outward_normal = if front_face { outward_normal } else { outward_normal * -1.0 }; Some(HitRecord { t: root, p: p, normal: outward_normal, front_face, material: self.material.deref(), }) } }