world: implement World::color_at

This commit is contained in:
Bill Thiede 2021-07-17 16:12:30 -07:00
parent 86d052d38b
commit b37398ac40

View File

@ -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,
}
}
}