rtwlib/hittable/
sphere.rs1use crate::{
4 hittable::{HitRecord, Hittable},
5 material::Material,
6 utils::RangeExtensions,
7 vec3::*,
8};
9use std::{ops::Range, rc::Rc};
10#[derive(Clone)]
11
12pub struct Sphere {
14 center: Point3,
15 radius: f64,
16 mat: Rc<dyn Material>,
17}
18impl Sphere {
19 pub fn new(center: Point3, radius: f64, mat: Rc<dyn Material>) -> Self {
21 Sphere {
22 center,
23 radius: f64::max(radius, 0.0),
24 mat,
25 }
26 }
27}
28
29impl Hittable for Sphere {
30 fn hit(&self, r: &crate::ray::Ray, ray_t: Range<f64>, rec: &mut HitRecord) -> bool {
31 let oc = self.center - r.origin;
33 let a = &r.direction.length_squared();
34 let h = dot(&r.direction, &oc);
35 let c = oc.length_squared() - self.radius * self.radius;
36 let discriminant = h * h - a * c;
37
38 if discriminant < 0.0 {
39 return false;
41 }
42
43 let sqrtd = discriminant.sqrt();
44
45 let mut root = (h - sqrtd) / a;
46 if !ray_t.surrounds(root) {
47 root = (h + sqrtd) / a;
49 if !ray_t.surrounds(root) {
50 return false;
51 }
52 }
53
54 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); rec.set_material(Rc::clone(&self.mat));
60
61 return true;
62 }
63 fn as_string(&self) -> String {
64 format!(
65 "[ Sphere ] Radius: {}, Position: ({}x, {}z, {}z), material: {:?}",
66 self.radius, self.center.x, self.center.y, self.center.z, self.mat
67 )
68 }
69 fn as_info_vec(&self) -> Vec<String> {
70 vec![
71 "Sphere".to_string(),
72 self.radius.to_string(),
73 self.center.x.to_string(),
74 self.center.y.to_string(),
75 self.center.z.to_string(),
76 format!("{:?}", self.mat),
77 ]
78 }
79}