materials: make lighting calculation shadow aware

This commit is contained in:
Bill Thiede 2021-07-18 12:46:49 -07:00
parent efdc963a48
commit 1065702a5d
3 changed files with 24 additions and 8 deletions

View File

@ -31,7 +31,7 @@ fn main() -> Result<()> {
let light_position = Tuple::point(-10., 10., -10.);
let light_color = WHITE;
let light = PointLight::new(light_position, light_color);
let in_shadow = false;
for y in 0..h {
let world_y = half - pixel_size * y as f32;
for x in 0..w {
@ -44,7 +44,7 @@ fn main() -> Result<()> {
let point = r.position(hit.t);
let normal = hit.object.normal_at(point);
let eye = -r.direction;
let color = lighting(&hit.object.material, &light, point, eye, normal);
let color = lighting(&hit.object.material, &light, point, eye, normal, in_shadow);
c.set(x, y, color);
}
}

View File

@ -54,6 +54,7 @@ impl Default for Material {
/// WHITE,
/// };
///
/// let in_shadow = false;
/// let m = Material::default();
/// let position = Tuple::point(0., 0., 0.);
///
@ -61,35 +62,43 @@ impl Default for Material {
/// let eyev = Tuple::vector(0., 0., -1.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv);
/// let result = lighting(&m, &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 = Tuple::vector(0., 2_f32.sqrt() / 2., -2_f32.sqrt() / 2.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
/// assert_eq!(result, WHITE);
///
/// // Lighting with the eye opposite surface, light offset 45°.
/// let eyev = Tuple::vector(0., 0., -1.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv);
/// let result = lighting(&m, &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 = Tuple::vector(0., -2_f32.sqrt() / 2., -2_f32.sqrt() / 2.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 10., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
/// assert_eq!(result, Color::new(1.6363853, 1.6363853, 1.6363853));
///
/// // Lighting with the light behind the surface.
/// let eyev = Tuple::vector(0., 0., -1.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 0., 10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv);
/// let result = lighting(&m, &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 = Tuple::vector(0., 0., -1.);
/// let normalv = Tuple::vector(0., 0., -1.);
/// let light = PointLight::new(Tuple::point(0., 0., -10.), WHITE);
/// let result = lighting(&m, &light, position, eyev, normalv, in_shadow);
/// assert_eq!(result, Color::new(0.1, 0.1, 0.1));
/// ```
pub fn lighting(
@ -98,6 +107,7 @@ pub fn lighting(
point: Tuple,
eyev: Tuple,
normalv: Tuple,
in_shadow: bool,
) -> Color {
// Combine the surface color with the light's color.
let effective_color = material.color * light.intensity;
@ -128,5 +138,9 @@ pub fn lighting(
};
(diffuse, specular)
};
ambient + diffuse + specular
if in_shadow {
ambient
} else {
ambient + diffuse + specular
}
}

View File

@ -119,12 +119,14 @@ impl World {
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.
let in_shadow = false;
lighting(
&comps.object.material,
&self.light.as_ref().expect("World has no lights"),
comps.point,
comps.eyev,
comps.normalv,
in_shadow,
)
}
/// Compute color for given ray fired at the world.