diff --git a/ray-tracer/src/types/ray.rs b/ray-tracer/src/types/ray.rs index 43f6515..322f5f0 100644 --- a/ray-tracer/src/types/ray.rs +++ b/ray-tracer/src/types/ray.rs @@ -48,9 +48,10 @@ impl Ray { } pub fn intersect<'a>(&self, s: &'a Sphere) -> Intersections<'a> { - let sphere_to_ray = self.origin - Point::new(0., 0., 0.); - let a = self.direction.dot(&self.direction); - let b = 2. * self.direction.dot(&sphere_to_ray); + let r2 = self.transform(s.transformation().inverse()); + let sphere_to_ray = r2.origin - Point::new(0., 0., 0.); + let a = r2.direction.dot(&r2.direction); + let b = 2. * r2.direction.dot(&sphere_to_ray); let c = sphere_to_ray.dot(&sphere_to_ray) - 1.; let discriminant = b * b - 4. * a * c; @@ -199,4 +200,24 @@ mod tests { assert_eq!(r2.origin, Point::new(2., 6., 12.)); assert_eq!(r2.direction, Vector::new(0., 3., 0.,)); } + + #[test] + fn intersect_scaled_sphere_with_ray() { + let r = Ray::new(Point::new(0., 0., -5.), Vector::new(0., 0., 1.)); + let mut s = Sphere::new(); + s.set_transformation(scaling(2., 2., 2.)); + let xs = r.intersect(&s); + assert_eq!(xs.len(), 2); + assert_eq!(xs[0].t, 3.); + assert_eq!(xs[1].t, 7.); + } + + #[test] + fn intersect_translated_sphere_with_ray() { + let r = Ray::new(Point::new(0., 0., -5.), Vector::new(0., 0., 1.)); + let mut s = Sphere::new(); + s.set_transformation(translation(5., 0., 0.)); + let xs = r.intersect(&s); + assert_eq!(xs.len(), 0); + } } diff --git a/ray-tracer/src/types/sphere.rs b/ray-tracer/src/types/sphere.rs index 6b5eb00..153046d 100644 --- a/ray-tracer/src/types/sphere.rs +++ b/ray-tracer/src/types/sphere.rs @@ -1,13 +1,44 @@ -use crate::types::Point; +use crate::types::{Matrix, Point}; #[derive(Debug, PartialEq)] pub struct Sphere { origin: Point, + transformation: Matrix, } impl Sphere { pub fn new() -> Self { - Self{ origin: Point::new(0., 0., 0.) } + Self { + origin: Point::new(0., 0., 0.), + transformation: Matrix::identity(), + } + } + + pub fn transformation(&self) -> &Matrix { + &self.transformation + } + + pub fn set_transformation(&mut self, m: Matrix) { + self.transformation = m } } +#[cfg(test)] +mod test { + use crate::transforms::translation; + use super::*; + + #[test] + fn sphere_has_default_transformation() { + let s = Sphere::new(); + assert_eq!(s.transformation(), &Matrix::identity()); + } + + #[test] + fn change_a_spheres_transformation() { + let mut s = Sphere::new(); + let t = translation(2., 3., 4.); + s.set_transformation(t.clone()); + assert_eq!(*s.transformation(), t); + } +}