From 1d5e5a164bb0aa78af4ced74aeaa17e35a69a703 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Fri, 30 Jul 2021 21:21:51 -0700 Subject: [PATCH] materials: move tests from doctest to unit. --- rtchallenge/src/materials.rs | 263 ++++++++++++++++++++--------------- 1 file changed, 150 insertions(+), 113 deletions(-) diff --git a/rtchallenge/src/materials.rs b/rtchallenge/src/materials.rs index e963d86..729677d 100644 --- a/rtchallenge/src/materials.rs +++ b/rtchallenge/src/materials.rs @@ -24,26 +24,6 @@ pub struct Material { impl Default for Material { /// Creates the default material. - /// - /// # Examples - /// ``` - /// use rtchallenge::{materials::Material, tuples::Color, WHITE}; - /// - /// let m = Material::default(); - /// assert_eq!( - /// m, - /// Material { - /// color: WHITE.into(), - /// ambient: 0.1, - /// diffuse: 0.9, - /// specular: 0.9, - /// shininess: 200., - /// reflective: 0.0, - /// transparency: 0.0, - /// refractive_index: 1.0, - /// } - /// ); - /// ``` fn default() -> Material { Material { color: WHITE.into(), @@ -59,99 +39,6 @@ impl Default for Material { } /// Compute lighting contributions using the Phong reflection model. -/// -/// # Examples -/// ``` -/// use rtchallenge::{ -/// lights::PointLight, -/// materials::{lighting, Material}, -/// patterns::Pattern, -/// shapes::Shape, -/// tuples::{point, vector, Color}, -/// Float, BLACK, WHITE, -/// }; -/// -/// let in_shadow = false; -/// let m = Material::default(); -/// let position = point(0., 0., 0.); -/// let object = Shape::sphere(); -/// -/// // Lighting with the eye between the light and the surface. -/// let eyev = vector(0., 0., -1.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 0., -10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, Color::new(1.9, 1.9, 1.9)); -/// -/// // Lighting with the eye between the light and the surface, eye offset 45°. -/// let eyev = vector(0., (2. as Float).sqrt() / 2., -(2. as Float).sqrt() / 2.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 0., -10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, WHITE); -/// -/// // Lighting with the eye opposite surface, light offset 45°. -/// let eyev = vector(0., 0., -1.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 10., -10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, Color::new(0.7364, 0.7364, 0.7364)); -/// -/// // Lighting with the eye in the path of the reflection vector. -/// let eyev = vector(0., -(2.0 as Float).sqrt() / 2., -(2.0 as Float).sqrt() / 2.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 10., -10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, Color::new(1.63639, 1.63639, 1.63639)); -/// -/// // Lighting with the light behind the surface. -/// let eyev = vector(0., 0., -1.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 0., 10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, Color::new(0.1, 0.1, 0.1)); -/// -/// // Lighting with the surface in shadow. -/// let in_shadow = true; -/// let eyev = vector(0., 0., -1.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 0., -10.), WHITE); -/// let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); -/// assert_eq!(result, Color::new(0.1, 0.1, 0.1)); -/// -/// // Lighting with a pattern applied. -/// -/// let m = Material { -/// color: Pattern::stripe(WHITE, BLACK), -/// ambient: 1., -/// diffuse: 0., -/// specular: 0., -/// ..Material::default() -/// }; -/// let eyev = vector(0., 0., -1.); -/// let normalv = vector(0., 0., -1.); -/// let light = PointLight::new(point(0., 0., -10.), WHITE); -/// let c1 = lighting( -/// &m, -/// &object, -/// &light, -/// point(0.9, 0., 0.), -/// eyev, -/// normalv, -/// false, -/// ); -/// let c2 = lighting( -/// &m, -/// &object, -/// &light, -/// point(1.1, 0., 0.), -/// eyev, -/// normalv, -/// false, -/// ); -/// assert_eq!(c1, WHITE); -/// assert_eq!(c2, BLACK); -/// ``` pub fn lighting( material: &Material, object: &Shape, @@ -197,3 +84,153 @@ pub fn lighting( ambient + diffuse + specular } } + +#[cfg(test)] +mod tests { + use crate::{materials::Material, WHITE}; + + #[test] + fn default() { + let m = Material::default(); + assert_eq!( + m, + Material { + color: WHITE.into(), + ambient: 0.1, + diffuse: 0.9, + specular: 0.9, + shininess: 200., + reflective: 0.0, + transparency: 0.0, + refractive_index: 1.0, + } + ); + } + + mod lighting { + use crate::{ + lights::PointLight, + materials::{lighting, Material}, + patterns::Pattern, + shapes::Shape, + tuples::{point, vector, Color}, + Float, BLACK, WHITE, + }; + + #[test] + fn eye_between_light_and_surface() { + let in_shadow = false; + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + + // Lighting with the eye between the light and the surface. + let eyev = vector(0., 0., -1.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 0., -10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, Color::new(1.9, 1.9, 1.9)); + } + + #[test] + fn eye_between_light_and_surface_offset_45() { + // Lighting with the eye between the light and the surface, eye offset 45°. + let in_shadow = false; + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + let eyev = vector(0., (2. as Float).sqrt() / 2., -(2. as Float).sqrt() / 2.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 0., -10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, WHITE); + } + #[test] + fn eye_opposite_surface_light_offset_45() { + // Lighting with the eye opposite surface, light offset 45°. + let in_shadow = false; + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + let eyev = vector(0., 0., -1.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 10., -10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, Color::new(0.7364, 0.7364, 0.7364)); + } + #[test] + fn eye_in_path_of_reflection_vector() { + // Lighting with the eye in the path of the reflection vector. + let in_shadow = false; + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + let eyev = vector(0., -(2.0 as Float).sqrt() / 2., -(2.0 as Float).sqrt() / 2.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 10., -10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, Color::new(1.63639, 1.63639, 1.63639)); + } + #[test] + fn light_behind_surface() { + // Lighting with the light behind the surface. + let in_shadow = false; + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + let eyev = vector(0., 0., -1.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 0., 10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, Color::new(0.1, 0.1, 0.1)); + } + #[test] + fn surface_in_shadow() { + // Lighting with the surface in shadow. + let m = Material::default(); + let position = point(0., 0., 0.); + let object = Shape::sphere(); + let in_shadow = true; + let eyev = vector(0., 0., -1.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 0., -10.), WHITE); + let result = lighting(&m, &object, &light, position, eyev, normalv, in_shadow); + assert_eq!(result, Color::new(0.1, 0.1, 0.1)); + } + #[test] + fn pattern_applied() { + // Lighting with a pattern applied. + let object = Shape::sphere(); + let m = Material { + color: Pattern::stripe(WHITE, BLACK), + ambient: 1., + diffuse: 0., + specular: 0., + ..Material::default() + }; + let eyev = vector(0., 0., -1.); + let normalv = vector(0., 0., -1.); + let light = PointLight::new(point(0., 0., -10.), WHITE); + let c1 = lighting( + &m, + &object, + &light, + point(0.9, 0., 0.), + eyev, + normalv, + false, + ); + let c2 = lighting( + &m, + &object, + &light, + point(1.1, 0., 0.), + eyev, + normalv, + false, + ); + assert_eq!(c1, WHITE); + assert_eq!(c2, BLACK); + } + } +}