materials: move tests from doctest to unit.

This commit is contained in:
Bill Thiede 2021-07-30 21:21:51 -07:00
parent f476822bcd
commit 1d5e5a164b

View File

@ -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);
}
}
}