use std::sync::Arc;
use crate::hit::{HitRecord, Hittable};
use crate::material::Material;
use crate::ray::Ray;
use crate::vec3::Vec3;
pub struct Sphere {
pub center: Vec3,
pub radius: f32,
pub material: Arc<dyn Material>,
}
impl Sphere {
pub fn new(center: Vec3, radius: f32, material: Arc<dyn Material>) -> Self {
Self { center, radius, material }
}
}
impl Hittable for Sphere {
fn hit(&self, ray: &Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
let oc = ray.origin - self.center;
let half_b = oc.dot(ray.dir);
let c = oc.length_squared() - self.radius * self.radius;
let discriminant = half_b * half_b - c;
if discriminant < 0.0 { return None; }
let sqrt_d = discriminant.sqrt();
let mut root = -half_b - sqrt_d;
if root <= t_min || root >= t_max {
root = -half_b + sqrt_d;
if root <= t_min || root >= t_max { return None; }
}
let p = ray.at(root);
let outward_normal = (p - self.center) / self.radius;
let mut rec = HitRecord {
p,
normal: outward_normal,
t: root,
front_face: true,
material: self.material.clone(),
};
rec.set_face_normal(ray, outward_normal);
Some(rec)
}
}