diff --git a/rtchallenge/src/world.rs b/rtchallenge/src/world.rs index 4991a2b..c9ec9ad 100644 --- a/rtchallenge/src/world.rs +++ b/rtchallenge/src/world.rs @@ -1,11 +1,12 @@ use crate::{ - intersections::{Intersections, PrecomputedData}, + intersections::{prepare_computations, Intersections, PrecomputedData}, lights::PointLight, materials::{lighting, Material}, matrices::Matrix4x4, rays::Ray, spheres::{intersect, Sphere}, tuples::{Color, Tuple}, + BLACK, }; /// World holds all drawable objects and the light(s) that illuminate them. @@ -118,6 +119,8 @@ impl World { /// assert_eq!(c, Color::new(0.90498, 0.90498, 0.90498)); /// ``` pub fn shade_hit(&self, comps: &PrecomputedData) -> Color { + // TODO(wathiede): support multiple light sources by iterating over all + // the light sources and summing the calls to lighting. lighting( &comps.object.material, &self.light.as_ref().expect("World has no lights"), @@ -126,4 +129,51 @@ impl World { comps.normalv, ) } + /// Compute color for given ray fired at the world. + /// + /// # Examples + /// ``` + /// use rtchallenge::{ + /// intersections::{prepare_computations, Intersection}, + /// lights::PointLight, + /// rays::Ray, + /// tuples::{Color, Tuple}, + /// world::World, + /// }; + /// + /// // The color when a ray misses. + /// let w = World::test_world(); + /// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 1., 0.)); + /// let c = w.color_at(&r); + /// assert_eq!(c, Color::new(0., 0., 0.)); + /// + /// // The color when a ray hits. + /// let w = World::test_world(); + /// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.)); + /// let c = w.color_at(&r); + /// assert_eq!(c, Color::new(0.38066, 0.47583, 0.2855)); + /// + /// // The color with an intersection behind the ray. + /// let w = { + /// let mut w = World::test_world(); + /// let mut outer = &mut w.objects[0]; + /// outer.material.ambient = 1.; + /// let inner = &mut w.objects[1]; + /// inner.material.ambient = 1.; + /// w + /// }; + /// let inner = &w.objects[1]; + /// let r = Ray::new(Tuple::point(0., 0., 0.75), Tuple::vector(0., 0., -1.)); + /// let c = w.color_at(&r); + /// assert_eq!(c, inner.material.color); + /// ``` + pub fn color_at(&self, r: &Ray) -> Color { + match self.intersect(r).hit() { + Some(hit) => { + let comps = prepare_computations(&hit, r); + self.shade_hit(&comps) + } + None => BLACK, + } + } }