world & intersections: handle shadows.
This commit is contained in:
parent
09047eb713
commit
7e450d664e
@ -4,6 +4,7 @@ use crate::{
|
|||||||
rays::Ray,
|
rays::Ray,
|
||||||
spheres::Sphere,
|
spheres::Sphere,
|
||||||
tuples::{dot, Tuple},
|
tuples::{dot, Tuple},
|
||||||
|
EPSILON,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -138,6 +139,7 @@ pub struct PrecomputedData<'i> {
|
|||||||
pub t: f32,
|
pub t: f32,
|
||||||
pub object: &'i Sphere,
|
pub object: &'i Sphere,
|
||||||
pub point: Tuple,
|
pub point: Tuple,
|
||||||
|
pub over_point: Tuple,
|
||||||
pub eyev: Tuple,
|
pub eyev: Tuple,
|
||||||
pub normalv: Tuple,
|
pub normalv: Tuple,
|
||||||
pub inside: bool,
|
pub inside: bool,
|
||||||
@ -150,8 +152,10 @@ pub struct PrecomputedData<'i> {
|
|||||||
/// use rtchallenge::{
|
/// use rtchallenge::{
|
||||||
/// intersections::{prepare_computations, Intersection, Intersections},
|
/// intersections::{prepare_computations, Intersection, Intersections},
|
||||||
/// rays::Ray,
|
/// rays::Ray,
|
||||||
|
/// matrices::Matrix4x4,
|
||||||
/// spheres::{intersect, Sphere},
|
/// spheres::{intersect, Sphere},
|
||||||
/// tuples::Tuple,
|
/// tuples::Tuple,
|
||||||
|
/// EPSILON
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// // Precomputing the state of an intersection.
|
/// // Precomputing the state of an intersection.
|
||||||
@ -182,6 +186,15 @@ pub struct PrecomputedData<'i> {
|
|||||||
/// assert_eq!(comps.inside, true);
|
/// assert_eq!(comps.inside, true);
|
||||||
//// // Normal would have been (0, 0, 1), but is inverted when inside.
|
//// // Normal would have been (0, 0, 1), but is inverted when inside.
|
||||||
/// assert_eq!(comps.normalv, Tuple::vector(0., 0., -1.));
|
/// assert_eq!(comps.normalv, Tuple::vector(0., 0., -1.));
|
||||||
|
///
|
||||||
|
/// // The hit should offset the point.
|
||||||
|
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||||
|
/// let mut shape = Sphere::default();
|
||||||
|
/// shape .set_transform(Matrix4x4::translation(0.,0.,1.));
|
||||||
|
/// let i = Intersection::new(5., &shape);
|
||||||
|
/// let comps = prepare_computations(&i, &r);
|
||||||
|
/// assert!(comps.over_point.z< -EPSILON/2.);
|
||||||
|
/// assert!(comps.point.z>comps.over_point.z);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn prepare_computations<'i>(i: &'i Intersection, r: &Ray) -> PrecomputedData<'i> {
|
pub fn prepare_computations<'i>(i: &'i Intersection, r: &Ray) -> PrecomputedData<'i> {
|
||||||
let point = r.position(i.t);
|
let point = r.position(i.t);
|
||||||
@ -192,10 +205,12 @@ pub fn prepare_computations<'i>(i: &'i Intersection, r: &Ray) -> PrecomputedData
|
|||||||
} else {
|
} else {
|
||||||
(false, normalv)
|
(false, normalv)
|
||||||
};
|
};
|
||||||
|
let over_point = point + normalv * EPSILON;
|
||||||
PrecomputedData {
|
PrecomputedData {
|
||||||
t: i.t,
|
t: i.t,
|
||||||
object: i.object,
|
object: i.object,
|
||||||
point,
|
point,
|
||||||
|
over_point,
|
||||||
normalv,
|
normalv,
|
||||||
inside,
|
inside,
|
||||||
eyev,
|
eyev,
|
||||||
|
|||||||
@ -91,7 +91,9 @@ impl World {
|
|||||||
/// use rtchallenge::{
|
/// use rtchallenge::{
|
||||||
/// intersections::{prepare_computations, Intersection},
|
/// intersections::{prepare_computations, Intersection},
|
||||||
/// lights::PointLight,
|
/// lights::PointLight,
|
||||||
|
/// matrices::Matrix4x4,
|
||||||
/// rays::Ray,
|
/// rays::Ray,
|
||||||
|
/// spheres::Sphere,
|
||||||
/// tuples::{Color, Tuple},
|
/// tuples::{Color, Tuple},
|
||||||
/// world::World,
|
/// world::World,
|
||||||
/// WHITE,
|
/// WHITE,
|
||||||
@ -115,18 +117,31 @@ impl World {
|
|||||||
/// let comps = prepare_computations(&i, &r);
|
/// let comps = prepare_computations(&i, &r);
|
||||||
/// let c = w.shade_hit(&comps);
|
/// let c = w.shade_hit(&comps);
|
||||||
/// assert_eq!(c, Color::new(0.90498, 0.90498, 0.90498));
|
/// assert_eq!(c, Color::new(0.90498, 0.90498, 0.90498));
|
||||||
|
///
|
||||||
|
/// // Shading with an intersection in shadow.
|
||||||
|
/// let mut w = World::default();
|
||||||
|
/// w.light = Some(PointLight::new(Tuple::point(0., 0., -10.), WHITE));
|
||||||
|
/// let s1 = Sphere::default();
|
||||||
|
/// let mut s2 = Sphere::default();
|
||||||
|
/// s2.set_transform(Matrix4x4::translation(0., 0., 10.));
|
||||||
|
/// w.objects = vec![s1, s2.clone()];
|
||||||
|
/// let r = Ray::new(Tuple::point(0., 0., 5.), Tuple::vector(0., 0., 1.));
|
||||||
|
/// let i = Intersection::new(4., &s2);
|
||||||
|
/// let comps = prepare_computations(&i, &r);
|
||||||
|
/// let c = w.shade_hit(&comps);
|
||||||
|
/// assert_eq!(c, Color::new(0.1, 0.1, 0.1));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn shade_hit(&self, comps: &PrecomputedData) -> Color {
|
pub fn shade_hit(&self, comps: &PrecomputedData) -> Color {
|
||||||
// TODO(wathiede): support multiple light sources by iterating over all
|
// TODO(wathiede): support multiple light sources by iterating over all
|
||||||
// the light sources and summing the calls to lighting.
|
// the light sources and summing the calls to lighting.
|
||||||
let in_shadow = false;
|
let shadowed = self.is_shadowed(comps.over_point);
|
||||||
lighting(
|
lighting(
|
||||||
&comps.object.material,
|
&comps.object.material,
|
||||||
&self.light.as_ref().expect("World has no lights"),
|
&self.light.as_ref().expect("World has no lights"),
|
||||||
comps.point,
|
comps.over_point,
|
||||||
comps.eyev,
|
comps.eyev,
|
||||||
comps.normalv,
|
comps.normalv,
|
||||||
in_shadow,
|
shadowed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/// Compute color for given ray fired at the world.
|
/// Compute color for given ray fired at the world.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user