From f347e2e47d4a5e71b9601a3989a0ecb7bc03e425 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 23 Jun 2024 23:04:15 -0400 Subject: [PATCH] Set up some diagnostics for the specular highlight --- ray-tracer/src/bin/sphere.rs | 114 ++++++++++++++++++++++--------- ray-tracer/src/types/material.rs | 3 +- ray-tracer/src/types/mod.rs | 8 +++ ray-tracer/src/types/sphere.rs | 2 +- 4 files changed, 92 insertions(+), 35 deletions(-) diff --git a/ray-tracer/src/bin/sphere.rs b/ray-tracer/src/bin/sphere.rs index 86a1361..a309d85 100644 --- a/ray-tracer/src/bin/sphere.rs +++ b/ray-tracer/src/bin/sphere.rs @@ -1,53 +1,101 @@ use ray_tracer::{types::*, PPM}; use rayon::prelude::*; -use std::{fs::File, io::Write, sync::{Arc, RwLock}}; +use std::{ + fs::File, + io::Write, + sync::{Arc, RwLock}, +}; const SIZE: usize = 100; -fn main() { +fn render( + camera: &Point, + light: &PointLight, + sphere: &Sphere, + wall_z: f64, + wall_size: f64, + filename: &str, +) { let canvas = Arc::new(RwLock::new(Canvas::new(SIZE, SIZE))); + + let pixel_size = wall_size / SIZE as f64; + let half = wall_size / 2.; + + let ray = Ray::new(camera.clone(), (Point::new(0., 0., wall_z) - camera).normalize()); + let xs = ray.intersect(sphere); + match xs.hit() { + Some(hit) => { + let point = ray.position(hit.t); + let normal = hit.object.normal_at(&point); + let eye = -ray.direction; + let color = hit.object.material().lighting(&light, &point, &eye, &normal); + println!("{:?}", color); + } + None => {} + } + + (0..SIZE).into_par_iter().for_each(|x| { + (0..SIZE).into_par_iter().for_each(|y| { + let world_x = -half + pixel_size * x as f64; + let world_y = half - pixel_size * y as f64; + let position = Point::new(world_x, world_y, wall_z); + + let ray = Ray::new(camera.clone(), (position - camera).normalize()); + let xs = ray.intersect(sphere); + match xs.hit() { + Some(hit) => { + let point = ray.position(hit.t); + let normal = hit.object.normal_at(&point); + let eye = -ray.direction; + let color = hit + .object + .material() + .lighting(&light, &point, &eye, &normal); + *canvas.write().unwrap().pixel_mut(x, y) = color; + } + None => {} + } + }); + }); + + let ppm = PPM::from(&*canvas.read().unwrap()); + let mut file = File::create(filename).unwrap(); + let _ = file.write(ppm.as_bytes()); +} + +fn main() { let mut sphere = Sphere::default(); let mut material = Material::default(); material.color = Color::new(1., 0.2, 1.); *sphere.material_mut() = material; - let light = PointLight::new(Point::new(-10., 10., -10.), Color::new(1., 1., 1.)); - let camera = Point::new(0., 0., -5.); - let world_z = 10.; + let wall_z = 10.; let wall_size = 7.; - let half = wall_size / 2.; - let pixel_size = wall_size / SIZE as f64; + { + let light = PointLight::new(Point::new(0., 0., -10.), Color::new(1., 1., 1.)); + render(&camera, &light, &sphere, wall_z, wall_size, "sphere_1.ppm"); + } - (0..SIZE).into_par_iter().for_each(|x| { - (0..SIZE).into_par_iter().for_each(|y| { - let world_x = -half + pixel_size * x as f64; - let world_y = half - pixel_size * y as f64; - let position = Point::new(world_x, world_y, world_z); + { + let light = PointLight::new(Point::new(-1., 0., -10.), Color::new(1., 1., 1.)); + render(&camera, &light, &sphere, wall_z, wall_size, "sphere_2.ppm"); + } - let ray = Ray::new( - camera.clone(), - (position - camera).normalize(), - ); - let xs = ray.intersect(&sphere); - match xs.hit() { - Some(hit) => { - let point = ray.position(hit.t); - let normal = hit.object.normal_at(&point); - let eye = -ray.direction; - let color = hit.object.material().lighting(&light, &point, &eye, &normal); - *canvas.write().unwrap().pixel_mut(x, y) = color; - } - None => {}, - } - }); - }); + { + let light = PointLight::new(Point::new(1., 0., -10.), Color::new(1., 1., 1.)); + render(&camera, &light, &sphere, wall_z, wall_size, "sphere_3.ppm"); + } - let canvas = canvas.read().unwrap(); + { + let light = PointLight::new(Point::new(0., -1., -10.), Color::new(1., 1., 1.)); + render(&camera, &light, &sphere, wall_z, wall_size, "sphere_4.ppm"); + } - let ppm = PPM::from(&*canvas); - let mut file = File::create("sphere.ppm").unwrap(); - let _ = file.write(ppm.as_bytes()); + { + let light = PointLight::new(Point::new(0., 1., -10.), Color::new(1., 1., 1.)); + render(&camera, &light, &sphere, wall_z, wall_size, "sphere_5.ppm"); + } } diff --git a/ray-tracer/src/types/material.rs b/ray-tracer/src/types/material.rs index 0ad0d57..391f3ac 100644 --- a/ray-tracer/src/types/material.rs +++ b/ray-tracer/src/types/material.rs @@ -97,7 +97,8 @@ mod tests { let m = Material::default(); let position = Point::default(); - let eyev = Vector::new(0., -2_f64.sqrt() / 2., -2_f64.sqrt() / 2.); + // let eyev = Vector::new(0., -2_f64.sqrt() / 2., -2_f64.sqrt() / 2.); + let eyev = Vector::new(0., -10., -10.).normalize(); let normalv = Vector::new(0., 0., -1.); let light = PointLight::new(Point::new(0., 10., -10.), Color::new(1., 1., 1.)); diff --git a/ray-tracer/src/types/mod.rs b/ray-tracer/src/types/mod.rs index b0edbc0..61adca5 100644 --- a/ray-tracer/src/types/mod.rs +++ b/ray-tracer/src/types/mod.rs @@ -166,6 +166,14 @@ mod tests { let v = Vector::new(1., -1., 0.); let n = Vector::new(0., 1., 0.); assert_eq!(v.reflect(&n), Vector::new(1., 1., 0.)); + + let v = Vector::new(-1., -1., 0.); + let n = Vector::new(1., 0., 0.); + assert_eq!(v.reflect(&n), Vector::new(1., -1., 0.)); + + let v = Vector::new(1., 0., -1.); + let n = Vector::new(0., 0., 1.); + assert_eq!(v.reflect(&n), Vector::new(1., 0., 1.)); } #[test] diff --git a/ray-tracer/src/types/sphere.rs b/ray-tracer/src/types/sphere.rs index eafd26d..c61e2a5 100644 --- a/ray-tracer/src/types/sphere.rs +++ b/ray-tracer/src/types/sphere.rs @@ -27,7 +27,7 @@ impl Sphere { pub fn normal_at(&self, world_point: &Point) -> Vector { let inverted_transform = self.transformation.inverse(); let object_point = &inverted_transform * world_point; - let object_normal = object_point - Point::new(0., 0., 0.); + let object_normal = (object_point - Point::new(0., 0., 0.)).normalize(); let mut world_normal = inverted_transform.transpose() * *object_normal; world_normal.3 = 0.; Vector::from(world_normal).normalize()