From 0b31f66bbf25f9a0260e2f49d32df4ed9e2ab105 Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Tue, 6 Jun 2023 20:47:32 -0500 Subject: [PATCH] fix: Corrected the distributions I had been carrying the distributions around with the SmallRng object so that I can provide whatever bounds needed. It turns out that the book only takes advantage of this a couple of times. The functions accepting a Uniform struct no longer do. They instead construct their own temporary one -- hopefully the optimizer can see through the loops and construct it just once. :l The change exposed all the uses of the distributions (duh!) and now they are correct. The effect is most pronounced on the dielectric spheres. --- src/camera.rs | 9 ++++----- src/hittable.rs | 6 +++--- src/main.rs | 6 ++---- src/material.rs | 8 ++++---- src/vec3.rs | 10 ++++++---- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/camera.rs b/src/camera.rs index 3a7bd1f..8fcadba 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -15,14 +15,13 @@ use crate::ray::Ray; use crate::degrees_to_radians; use rand::rngs::SmallRng; -use rand::distributions::Uniform; pub struct Camera { origin: Vec3, lower_left_corner: Vec3, horizontal: Vec3, vertical: Vec3, - u: Vec3, v: Vec3, w: Vec3, + u: Vec3, v: Vec3, /*w: Vec3,*/ lens_radius: f32, } @@ -55,13 +54,13 @@ impl Camera { lower_left_corner, horizontal: horiz, vertical: verti, - u, v, w, + u, v, /* w,*/ lens_radius: aperture / 2.0, } } - pub fn get_ray(&self, s: f32, t: f32, srng: &mut SmallRng, distrib: Uniform) -> Ray { - let rd = Vec3::rand_in_unit_disk(srng, distrib) * self.lens_radius; + pub fn get_ray(&self, s: f32, t: f32, srng: &mut SmallRng) -> Ray { + let rd = Vec3::rand_in_unit_disk(srng) * self.lens_radius; let offset = self.u * rd.x + self.v * rd.y; let dir = self.lower_left_corner diff --git a/src/hittable.rs b/src/hittable.rs index 6bde1c0..d4f7950 100644 --- a/src/hittable.rs +++ b/src/hittable.rs @@ -35,9 +35,9 @@ impl HittableList{ pub fn add(&mut self, hittable: Box ) -> () { self.hittables.push(hittable); } - pub fn clear(&mut self) -> () { - self.hittables.clear(); - } +// pub fn clear(&mut self) -> () { +// self.hittables.clear(); +// } } impl Hittable for HittableList{ diff --git a/src/main.rs b/src/main.rs index 54c829b..4e13927 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,7 +65,7 @@ fn main() { for _ in 0..samples_per_pixel { let u = ((x as f32) + small_rng.sample(distrib_zero_one)) / ((image.0 - 1) as f32); let v = ((y as f32) + small_rng.sample(distrib_zero_one)) / ((image.1 - 1) as f32); - let ray = cam.get_ray(u, v, &mut small_rng, distrib_plusminus_one); + let ray = cam.get_ray(u, v, &mut small_rng); color+= ray_color(ray, &world, max_depth, &mut small_rng, distrib_plusminus_one); } println!("{}", color.print_ppm(samples_per_pixel)); @@ -88,7 +88,7 @@ fn ray_color(r: Ray, world: &dyn Hittable, depth: u32, srng: &mut SmallRng, dist let mut attenuation = Vec3::zero(); match rec.material { Some(mat) => { - if mat.scatter(r, rec, &mut attenuation, &mut scattered, srng, distrib) { + if mat.scatter(r, rec, &mut attenuation, &mut scattered, srng) { return attenuation * ray_color(scattered, world, depth-1, srng, distrib); }; }, @@ -108,8 +108,6 @@ fn random_scene(srng: &mut SmallRng) -> HittableList { world.add( Box::new( Sphere::new(0.0, -1000.0, 0.0, 1000.0, Some(mat_ground) ))); let distrib_zero_one = Uniform::new(0.0, 1.0); - let distrib_plusminus_one = Uniform::new(-1.0, 1.0); - for a in -11..11 { for b in -11..11 { let choose_mat = srng.sample(distrib_zero_one); diff --git a/src/material.rs b/src/material.rs index df1abb3..d94cffb 100644 --- a/src/material.rs +++ b/src/material.rs @@ -25,11 +25,10 @@ impl Material { attenuation: &mut Vec3, scattered: &mut Ray, srng: &mut SmallRng, - distrib: Uniform, ) -> bool { match self { Material::Lambertian { albedo } => { - let scatter_dir = rec.normal + Vec3::rand_unit_vector(srng, distrib); + let scatter_dir = rec.normal + Vec3::rand_unit_vector(srng); // The compiler might be smart enough to compute this ^^^ just once. In which case, // I don't need to do this weird dance. Oh well. It'll work. let scatter_dir = if scatter_dir.near_zero() { // if near zero, @@ -55,7 +54,7 @@ impl Material { ); *scattered = Ray{ orig: rec.p, - dir: reflected + Vec3::rand_in_unit_sphere(srng, distrib) * *fuzz, + dir: reflected + Vec3::rand_in_unit_sphere(srng) * *fuzz, }; *attenuation = *albedo; return Vec3::dot(scattered.dir, rec.normal) > 0.0; @@ -69,7 +68,8 @@ impl Material { let sin_theta = (1.0 - cos_theta * cos_theta).sqrt(); let cannot_refract = refraction_ratio * sin_theta > 1.0; - let direction = if cannot_refract || Material::reflectance(cos_theta, refraction_ratio) > srng.sample(distrib) { + let distrib_zero_one = Uniform::new(0.0, 1.0); + let direction = if cannot_refract || Material::reflectance(cos_theta, refraction_ratio) > srng.sample(distrib_zero_one) { Vec3::reflect(unit_direction, rec.normal) } else { Vec3::refract(unit_direction, rec.normal, refraction_ratio) diff --git a/src/vec3.rs b/src/vec3.rs index e3b99ab..3ab8a3e 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -53,7 +53,8 @@ impl Vec3{ } } - pub fn rand_in_unit_sphere(srng: &mut SmallRng, distrib: Uniform) -> Vec3 { + pub fn rand_in_unit_sphere(srng: &mut SmallRng) -> Vec3 { + let distrib = Uniform::new(-1.0, 1.0); loop { let p = Vec3::rand(srng, distrib); if p.length_squared() >= 1.0 { continue; } @@ -61,7 +62,8 @@ impl Vec3{ } } - pub fn rand_in_unit_disk(srng: &mut SmallRng, distrib: Uniform) -> Vec3 { + pub fn rand_in_unit_disk(srng: &mut SmallRng) -> Vec3 { + let distrib = Uniform::new(-1.0, 1.0); loop { let p = Vec3 { x: srng.sample(distrib), @@ -73,8 +75,8 @@ impl Vec3{ } } - pub fn rand_unit_vector(srng: &mut SmallRng, distrib: Uniform) -> Vec3 { - return Vec3::as_unit(Vec3::rand_in_unit_sphere(srng, distrib)); + pub fn rand_unit_vector(srng: &mut SmallRng) -> Vec3 { + return Vec3::as_unit(Vec3::rand_in_unit_sphere(srng)); } pub fn length(&self) -> f32 {