diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e89a613..c0c3cf9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] channel = "1.77.0" -components = [ "rustfmt", "clippy" ] +components = [ "rustfmt", "clippy", "rust-analyzer", "rust-src" ] diff --git a/src/camera.rs b/src/camera.rs index c60309f..63a9f78 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -74,7 +74,6 @@ mod tests { use super::*; use crate::color::Color; - use crate::matrix; use crate::vector; use approx::relative_eq; use core::f64::consts::PI; @@ -97,10 +96,10 @@ mod tests { #[test] fn test_camera_pixel_size_calculation() { let camera = Camera::new(200, 125, FRAC_PI_2); - relative_eq!(camera.pixel_size(), 0.01, epsilon = matrix::EPSILON); + relative_eq!(camera.pixel_size(), 0.01, epsilon = crate::EPSILON); let camera = Camera::new(125, 200, FRAC_PI_2); - relative_eq!(camera.pixel_size(), 0.01, epsilon = matrix::EPSILON); + relative_eq!(camera.pixel_size(), 0.01, epsilon = crate::EPSILON); } #[test] diff --git a/src/color.rs b/src/color.rs index f7459be..033974e 100644 --- a/src/color.rs +++ b/src/color.rs @@ -13,7 +13,6 @@ impl Color { } } -pub const EPSILON: f64 = 0.001; pub const WHITE: Color = Color { red: 1.0, green: 1.0, @@ -22,9 +21,9 @@ pub const WHITE: Color = Color { impl PartialEq for Color { fn eq(&self, other: &Self) -> bool { - let red_diff = (self.red - other.red).abs() <= EPSILON; - let green_diff = (self.green - other.green).abs() <= EPSILON; - let blue_diff = (self.blue - other.blue).abs() <= EPSILON; + let red_diff = (self.red - other.red).abs() <= crate::EPSILON; + let green_diff = (self.green - other.green).abs() <= crate::EPSILON; + let blue_diff = (self.blue - other.blue).abs() <= crate::EPSILON; red_diff && green_diff && blue_diff } diff --git a/src/lib.rs b/src/lib.rs index 995d511..f223a96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ #[macro_use] extern crate impl_ops; +pub const EPSILON: f64 = 0.001; + pub mod camera; pub mod canvas; pub mod color; diff --git a/src/main.rs b/src/main.rs index a645ec0..d7e0f45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,7 @@ fn main() { world.objects.push(right); world.objects.push(left); - let mut camera = camera::Camera::new(500, 250, FRAC_PI_3); + let mut camera = camera::Camera::new(400, 400, FRAC_PI_3); camera.transform = matrix::view_transform(point!(0, 1.5, -5), point!(0, 1, 0), vector!(0, 1, 0)); diff --git a/src/matrix.rs b/src/matrix.rs index 09be60e..1e7ab57 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -180,8 +180,6 @@ pub fn view_transform(from: Tuple, to: Tuple, up: Tuple) -> Matrix { orientation * Matrix::identity(4).translation(-from.x, -from.y, -from.z) } -pub const EPSILON: f64 = 0.001; - impl PartialEq for Matrix { fn eq(&self, other: &Self) -> bool { if self.matrix.is_empty() && other.matrix.is_empty() { @@ -196,7 +194,7 @@ impl PartialEq for Matrix { for x in 0..lines { for y in 0..columns { - if (self.at(x, y) - other.at(x, y)).abs() > EPSILON { + if (self.at(x, y) - other.at(x, y)).abs() > crate::EPSILON { return false; } } diff --git a/src/ray.rs b/src/ray.rs index 0f7b10f..7243bab 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -107,6 +107,7 @@ impl Intersection<'_> { t: self.t, object: self.object, point, + over_point: point + normalv * crate::EPSILON, eyev, normalv, inside, @@ -127,6 +128,7 @@ pub struct Computation<'a> { pub t: f64, pub object: &'a Sphere, pub point: Tuple, + pub over_point: Tuple, pub eyev: Tuple, pub normalv: Tuple, pub inside: bool, @@ -287,6 +289,26 @@ mod tests { assert_eq!(intersect.object, &sphere); } + #[test] + fn test_hit_offset_point() { + let charles = Ray { + origin: point!(0.0, 0.0, -5.0), + direction: vector!(0.0, 0.0, 1.0), + }; + + let mut sphere = Sphere::init(); + sphere.transform = Matrix::identity(4).translation(0.0, 0.0, 1.0); + + let i = Intersection { + t: 5.0, + object: &sphere, + }; + let comps = i.prepare_computations(&charles); + + assert!(comps.over_point.z < -crate::EPSILON / 2.0); + assert!(comps.point.z > comps.over_point.z); + } + #[test] fn test_hit() { let i1 = Intersection { diff --git a/src/tuple.rs b/src/tuple.rs index 5de96e5..6d8f81c 100644 --- a/src/tuple.rs +++ b/src/tuple.rs @@ -1,5 +1,5 @@ -use crate::matrix; use crate::matrix::*; +use crate::{matrix, EPSILON}; use std::ops; #[derive(Debug, Clone, Copy)] @@ -120,8 +120,6 @@ impl Tuple { } } -pub const EPSILON: f64 = 0.001; - impl PartialEq for Tuple { fn eq(&self, other: &Self) -> bool { let x_diff = (self.x - other.x).abs() <= EPSILON; diff --git a/src/world.rs b/src/world.rs index 0b82ec9..1a7df3a 100644 --- a/src/world.rs +++ b/src/world.rs @@ -75,7 +75,7 @@ impl World { comps.point, comps.eyev, comps.normalv, - false, + self.is_shadowed(&comps.over_point), ); current_color = current_color + color; } diff --git a/tests/scenarios.rs b/tests/scenarios.rs new file mode 100644 index 0000000..e007275 --- /dev/null +++ b/tests/scenarios.rs @@ -0,0 +1,32 @@ +use raytracer::{ + color::Color, + light::Light, + matrix::Matrix, + point, + ray::{Intersection, Ray, Sphere}, + tuple::Tuple, + vector, + world::World, +}; + +#[test] +// test shadowed scene +fn shade_git_given_an_intersection_in_shadow() { + let mut w = World::new(); + w.lights.push(Light { + position: point!(0, 0, -10), + intensity: Color::new(1.0, 1.0, 1.0), + }); + w.objects.push(Sphere::init()); + let mut s2 = Sphere::init(); + s2.transform = Matrix::identity(4).translation(0.0, 0.0, 10.0); + w.objects.push(s2); + let r = Ray::new(point!(0, 0, 5), vector!(0, 0, 1)); + let i = Intersection { + t: 4.0, + object: &w.objects[1], + }; + let comps = i.prepare_computations(&r); + let c = w.shade_hit(&comps); + assert_eq!(c, Color::new(0.1, 0.1, 0.1)); +}