diff --git a/rtchallenge/src/spheres.rs b/rtchallenge/src/spheres.rs new file mode 100644 index 0000000..6ed4b58 --- /dev/null +++ b/rtchallenge/src/spheres.rs @@ -0,0 +1,59 @@ +use crate::{ + rays::Ray, + tuples::{dot, Tuple}, +}; + +#[derive(Default)] +pub struct Sphere {} +pub struct Intersection {} + +/// Intersect a ray with a sphere. +/// +/// # Examples +/// ``` +/// use rtchallenge::{ +/// rays::Ray, +/// spheres::{intersect, Sphere}, +/// tuples::Tuple, +/// }; +/// +/// // A ray intersects a sphere in two points. +/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.)); +/// let s = Sphere::default(); +/// let xs = intersect(&s, &r); +/// assert_eq!(xs, vec![4., 6.]); +/// +/// // A ray intersects a sphere at a tangent. +/// let r = Ray::new(Tuple::point(0., 2., -5.), Tuple::vector(0., 0., 1.)); +/// let s = Sphere::default(); +/// let xs = intersect(&s, &r); +/// assert_eq!(xs, vec![]); +/// +/// // A ray originates inside a sphere. +/// let r = Ray::new(Tuple::point(0., 0., 0.), Tuple::vector(0., 0., 1.)); +/// let s = Sphere::default(); +/// let xs = intersect(&s, &r); +/// assert_eq!(xs, vec![-1., 1.]); +/// +/// // A sphere is behind a ray. +/// let r = Ray::new(Tuple::point(0., 0., 5.), Tuple::vector(0., 0., 1.)); +/// let s = Sphere::default(); +/// let xs = intersect(&s, &r); +/// assert_eq!(xs, vec![-6., -4.]); +/// ``` + +pub fn intersect(_sphere: &Sphere, ray: &Ray) -> Vec { + let sphere_to_ray = ray.origin - Tuple::point(0., 0., 0.); + let a = dot(ray.direction, ray.direction); + let b = 2. * dot(ray.direction, sphere_to_ray); + let c = dot(sphere_to_ray, sphere_to_ray) - 1.; + let discriminant = b * b - 4. * a * c; + if discriminant < 0. { + vec![] + } else { + vec![ + (-b - discriminant.sqrt()) / (2. * a), + (-b + discriminant.sqrt()) / (2. * a), + ] + } +}