truster/shape/
sphere.rs

1//! Holds the [Sphere] struct;
2
3use std::rc::Rc;
4
5use crate::intersection::Intersection;
6use crate::material::Material;
7use crate::matrix::Matrix;
8use crate::ray::Ray;
9use crate::tuple::Tuple;
10
11use super::Shape;
12
13/// A 3D ellipsoid (spheroid).
14#[derive(Default, Clone)]
15pub struct Sphere {
16    transform: Matrix,
17    transform_inverse: Matrix,
18    material: Material,
19}
20
21impl Sphere {
22    /// Returns a new sphere with radius 1, centered at the origin.
23    /// Use [Sphere::set_transform] to transform it. Give it a material with [Sphere::set_material].
24    pub fn new() -> Self {
25        Self::default()
26    }
27}
28
29impl Shape for Sphere {
30    /// Returns a sorted vector of all distances where `ray` intersects `self`.
31    ///
32    /// # Examples
33    ///
34    /// A ray intersects a sphere at two points.
35    /// ```
36    /// # use truster::shape::{Shape, sphere::Sphere};
37    /// use truster::ray::Ray;
38    /// use truster::tuple::Tuple;
39    ///
40    /// let ray = Ray::new(Tuple::point(0.0, 0.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
41    /// let sphere = Sphere::new();
42    /// let intersections = sphere.intersect(&ray);
43    /// assert_eq!(intersections.len(), 2);
44    /// assert_eq!(intersections[0].t(), 4.0);
45    /// assert_eq!(intersections[1].t(), 6.0);
46    /// ```
47    ///
48    /// A ray intersects a sphere at a tangent.
49    /// ```
50    /// # use truster::shape::{Shape, sphere::Sphere};
51    /// use truster::ray::Ray;
52    /// use truster::tuple::Tuple;
53    ///
54    /// let ray = Ray::new(Tuple::point(0.0, 1.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
55    /// let sphere = Sphere::new();
56    /// let intersections = sphere.intersect(&ray);
57    /// assert_eq!(intersections.len(), 2);
58    /// assert_eq!(intersections[0].t(), 5.0);
59    /// assert_eq!(intersections[1].t(), 5.0);
60    /// ```
61    ///
62    /// A ray misses a sphere.
63    /// ```
64    /// # use truster::shape::{Shape, sphere::Sphere};
65    /// use truster::ray::Ray;
66    /// use truster::tuple::Tuple;
67    ///
68    /// let ray = Ray::new(Tuple::point(0.0, 2.0, -5.0), Tuple::vector(0.0, 0.0, 1.0));
69    /// let sphere = Sphere::new();
70    /// let intersections = sphere.intersect(&ray);
71    /// assert_eq!(intersections.len(), 0);
72    /// ```
73    ///
74    /// A ray originates inside a sphere.
75    /// ```
76    /// # use truster::shape::{Shape, sphere::Sphere};
77    /// use truster::ray::Ray;
78    /// use truster::tuple::Tuple;
79    ///
80    /// let ray = Ray::new(Tuple::point(0.0, 0.0, 0.0), Tuple::vector(0.0, 0.0, 1.0));
81    /// let sphere = Sphere::new();
82    /// let intersections = sphere.intersect(&ray);
83    /// assert_eq!(intersections.len(), 2);
84    /// assert_eq!(intersections[0].t(), -1.0);
85    /// assert_eq!(intersections[1].t(), 1.0);
86    /// ```
87    ///
88    /// A ray is behind a sphere.
89    /// ```
90    /// # use truster::shape::{Shape, sphere::Sphere};
91    /// use truster::ray::Ray;
92    /// use truster::tuple::Tuple;
93    ///
94    /// let ray = Ray::new(Tuple::point(0.0, 0.0, 5.0), Tuple::vector(0.0, 0.0, 1.0));
95    /// let sphere = Sphere::new();
96    /// let intersections = sphere.intersect(&ray);
97    /// assert_eq!(intersections.len(), 2);
98    /// assert_eq!(intersections[0].t(), -6.0);
99    /// assert_eq!(intersections[1].t(), -4.0);
100    /// ```
101    fn local_intersect(&self, ray: &Ray) -> Vec<Intersection> {
102        let oc = ray.origin() - Tuple::point(0.0, 0.0, 0.0);
103
104        let a = ray.direction().norm_squared();
105        let b = ray.direction().dot(oc);
106        let c = oc.norm_squared() - 1.0;
107
108        let d = b * b - a * c;
109
110        if d < 0.0 {
111            return Vec::new();
112        }
113
114        let sqrtd = d.sqrt();
115        let t1 = (-b - sqrtd) / a;
116        let t2 = (-b + sqrtd) / a;
117
118        vec![
119            Intersection::new(t1, Rc::new(self.clone())),
120            Intersection::new(t2, Rc::new(self.clone())),
121        ]
122    }
123
124    /// Returns the surface normal of `self` at `point`.
125    ///
126    /// # Examples
127    ///
128    /// The normal on a sphere at a point on the X axis.
129    /// ```
130    /// # use truster::shape::{Shape, sphere::Sphere};
131    /// use truster::tuple::Tuple;
132    ///
133    /// let sphere = Sphere::new();
134    /// let normal = sphere.normal_at(Tuple::point(1.0, 0.0, 0.0));
135    /// assert_eq!(normal, Tuple::vector(1.0, 0.0, 0.0));
136    /// ```
137    ///
138    /// The normal on a sphere at a point on the Y axis.
139    /// ```
140    /// # use truster::shape::{Shape, sphere::Sphere};
141    /// use truster::tuple::Tuple;
142    ///
143    /// let sphere = Sphere::new();
144    /// let normal = sphere.normal_at(Tuple::point(0.0, 1.0, 0.0));
145    /// assert_eq!(normal, Tuple::vector(0.0, 1.0, 0.0));
146    /// ```
147    ///
148    /// The normal on a sphere at a point on the Z axis.
149    /// ```
150    /// # use truster::shape::{Shape, sphere::Sphere};
151    /// use truster::tuple::Tuple;
152    ///
153    /// let sphere = Sphere::new();
154    /// let normal = sphere.normal_at(Tuple::point(0.0, 0.0, 1.0));
155    /// assert_eq!(normal, Tuple::vector(0.0, 0.0, 1.0));
156    /// ```
157    ///
158    /// The normal on a sphere at a point on the non-axial point.
159    /// ```
160    /// # use truster::shape::{Shape, sphere::Sphere};
161    /// use truster::tuple::Tuple;
162    ///
163    /// let sphere = Sphere::new();
164    /// let normal = sphere.normal_at(Tuple::point(
165    ///     (3.0 as f64).sqrt() / 3.0,
166    ///     (3.0 as f64).sqrt() / 3.0,
167    ///     (3.0 as f64).sqrt() / 3.0,
168    /// ));
169    /// assert_eq!(normal, Tuple::vector(
170    ///     (3.0 as f64).sqrt() / 3.0,
171    ///     (3.0 as f64).sqrt() / 3.0,
172    ///     (3.0 as f64).sqrt() / 3.0,
173    /// ));
174    /// ```
175    fn local_normal_at(&self, point: Tuple) -> Tuple {
176        (point - Tuple::point(0.0, 0.0, 0.0)).normalized()
177    }
178
179    /// Sets `self`'s transform to be `transform`.
180    fn set_transform(&mut self, transform: Matrix) {
181        self.transform_inverse = transform.inverse();
182        self.transform = transform;
183    }
184
185    /// Returns `self`'s transform.
186    fn transform(&self) -> &Matrix {
187        &self.transform
188    }
189
190    /// Returns `self`'s transform's inverse.
191    fn transform_inverse(&self) -> &Matrix {
192        &self.transform_inverse
193    }
194
195    /// Returns `self`'s material.
196    fn material(&self) -> &Material {
197        &self.material
198    }
199
200    /// Sets `self`'s material to be `material`.
201    fn set_material(&mut self, material: Material) {
202        self.material = material;
203    }
204}