use super::Point3; use super::Ray; use super::Vec3; pub struct HitRecord { pub p: Point3, pub normal: Vec3, pub t: f64, front_face: bool, } pub struct Sphere { center: Point3, radius: f64, } pub trait Hittable: Sync + Send { fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool; } impl HitRecord { fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) { self.front_face = Vec3::dot(r.direction(), outward_normal) < 0.0; if self.front_face { self.normal = outward_normal; } else { self.normal = (-1.0) * outward_normal; } } pub fn new(p: Point3, normal: Vec3, t: f64, front_face: bool) -> Self { HitRecord { p: p, normal: normal, t: t, front_face: front_face, } } pub fn empty() -> Self { Self::new( Point3::new(0.0, 0.0, 0.0), Vec3::new(0.0, 0.0, 0.0), 0.0, false, ) } } impl Sphere { pub fn new(cen: Point3, r: f64) -> Self { Sphere { center: cen, radius: r, } } } impl Hittable for Sphere { fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool { let oc = r.origin() - self.center; let a = r.direction().length_squared(); // gleiches Ergebnis wie Skalarprodukt let half_b = Vec3::dot(oc, r.direction()); let c = oc.length_squared() - self.radius * self.radius; let discriminant = half_b * half_b - a * c; if discriminant < 0.0 { return false; } let sqrtd = discriminant.sqrt(); let root = (-half_b - sqrtd) / a; let normal = (r.at(root) - self.center) / self.radius; if root < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 { let root2 = (-half_b + sqrtd) / a; let normal = (r.at(root2) - self.center) / self.radius; if root2 < t_min || t_max < root || Vec3::dot(normal, r.direction()) > 0.0 { return false; } } rec.t = root; rec.p = r.at(rec.t); let outward_normal = (rec.p - self.center) / self.radius; rec.set_face_normal(r, outward_normal); return true; } }