From 4f2365dbca2680a53ba3f3cdf4d6a114bfcd5329 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Fri, 5 Mar 2021 16:11:41 +0530 Subject: [PATCH] Trying to figure out perlin noise --- Cargo.toml | 1 - src/demos/mod.rs | 2 + src/demos/perlin_noise_ball.rs | 61 +++++++++++++++++++++++++++++ src/main.rs | 14 +++++-- src/materials/lambertian.rs | 8 ++-- src/texture/checker.rs | 2 +- src/texture/mod.rs | 6 ++- src/texture/perlin.rs | 70 ++++++++++++++++++++++++++++++++++ src/texture/perlin_noise.rs | 21 ++++++++++ src/texture/solid.rs | 4 +- 10 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 src/demos/perlin_noise_ball.rs create mode 100644 src/texture/perlin.rs create mode 100644 src/texture/perlin_noise.rs diff --git a/Cargo.toml b/Cargo.toml index b6666d8..66a3266 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" authors = ["ishanjain28 "] edition = "2018" - [features] default = ["gui"] gui = ["sdl2"] diff --git a/src/demos/mod.rs b/src/demos/mod.rs index a0ea916..980abee 100644 --- a/src/demos/mod.rs +++ b/src/demos/mod.rs @@ -12,9 +12,11 @@ use std::{ }; mod checkered_motion_blur; +mod perlin_noise_ball; mod two_spheres; pub use checkered_motion_blur::CheckeredMotionBlur; +pub use perlin_noise_ball::PerlinNoiseBall; pub use two_spheres::TwoSpheres; #[derive(Debug)] diff --git a/src/demos/perlin_noise_ball.rs b/src/demos/perlin_noise_ball.rs new file mode 100644 index 0000000..c1e87e2 --- /dev/null +++ b/src/demos/perlin_noise_ball.rs @@ -0,0 +1,61 @@ +use std::sync::Arc; + +use rand::{prelude::SmallRng, SeedableRng}; + +use crate::{ + demos::{Demo, ParallelHit}, + materials::Lambertian, + shapes::Sphere, + texture::PerlinNoise, + types::Vec3, + BvhNode, Camera, +}; + +pub struct PerlinNoiseBall {} + +impl Demo for PerlinNoiseBall { + type DemoT = BvhNode>; + + fn name(&self) -> &'static str { + "perlin_noise" + } + + fn world(&self) -> Self::DemoT { + let mut world: Vec> = Vec::with_capacity(500); + + let mut rng = rand::thread_rng(); + let mut rng = SmallRng::from_rng(&mut rng).unwrap(); + + world.push(Arc::new(Sphere::new( + Vec3::new(0.0, -1000.0, 0.0), + 1000.0, + Lambertian::new(PerlinNoise::new(&mut rng)), + ))); + + world.push(Arc::new(Sphere::new( + Vec3::new(0.0, 2.0, 0.0), + 2.0, + Lambertian::new(PerlinNoise::new(&mut rng)), + ))); + + BvhNode::new(&mut rng, &mut world, 0.0, 1.0) + } + + fn camera(&self, aspect_ratio: f64) -> Camera { + let lookfrom = Vec3::new(13.0, 2.0, 3.0); + let lookat = Vec3::new(0.0, 0.0, 0.0); + let aperture = 0.1; + let focus_distance = 10.0; + Camera::new( + lookfrom, + lookat, + Vec3::new(0.0, 1.0, 0.0), + 20.0, + aspect_ratio, + aperture, + focus_distance, + 0.0, + 1.0, + ) + } +} diff --git a/src/main.rs b/src/main.rs index f1519d4..a8753b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ use demos::Demo; use std::time::Instant; -const NUM_SAMPLES: u8 = 25; +const NUM_SAMPLES: u8 = 255; const VERTICAL_PARTITION: usize = 12; const HORIZONTAL_PARTITION: usize = 12; const WIDTH: usize = 1920; @@ -68,7 +68,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { .map_err(|e| e.to_string())?; let mut active_demo: &dyn Demo>> = - &demos::CheckeredMotionBlur {}; + &demos::PerlinNoiseBall {}; let mut should_update = true; loop { @@ -93,6 +93,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { active_demo = &demos::TwoSpheres {}; should_update = true; } + Some(Keycode::Num3) => { + active_demo = &demos::PerlinNoiseBall {}; + should_update = true; + } None => unreachable!(), _ => (), }; @@ -130,9 +134,11 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { #[cfg(not(feature = "gui"))] fn run(width: usize, height: usize) -> Result<(), String> { - run_and_save_demo(demos::CheckeredMotionBlur {}, width, height); + // run_and_save_demo(demos::CheckeredMotionBlur {}, width, height); - run_and_save_demo(demos::TwoSpheres {}, width, height); + //run_and_save_demo(demos::TwoSpheres {}, width, height); + + run_and_save_demo(demos::PerlinNoiseBall {}, width, height); Ok(()) } diff --git a/src/materials/lambertian.rs b/src/materials/lambertian.rs index 9645e0d..f3642b9 100644 --- a/src/materials/lambertian.rs +++ b/src/materials/lambertian.rs @@ -21,9 +21,9 @@ impl Material for Lambertian { let scatter_direction = hit_rec.normal + random_point_in_unit_sphere(rng); let scattered_ray = Ray::new(hit_rec.p, scatter_direction, ray.time()); - let mut p = hit_rec.p; - self.albedo.value(hit_rec.u, hit_rec.v, &mut p); - - (p, Some(scattered_ray)) + ( + self.albedo.value(hit_rec.u, hit_rec.v, &hit_rec.p), + Some(scattered_ray), + ) } } diff --git a/src/texture/checker.rs b/src/texture/checker.rs index 2741449..3e25b94 100644 --- a/src/texture/checker.rs +++ b/src/texture/checker.rs @@ -12,7 +12,7 @@ impl Checker { } impl Texture for Checker { - fn value(&self, u: f64, v: f64, p: &mut Vec3) { + fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3 { let sine_wave = f64::sin(10.0 * p.x()) * f64::sin(10.0 * p.y()) * f64::sin(10.0 * p.z()); if sine_wave < 0.0 { diff --git a/src/texture/mod.rs b/src/texture/mod.rs index f3dba8e..01201ad 100644 --- a/src/texture/mod.rs +++ b/src/texture/mod.rs @@ -1,11 +1,15 @@ mod checker; +mod perlin; +mod perlin_noise; mod solid; pub use checker::Checker; +pub use perlin::Perlin; +pub use perlin_noise::PerlinNoise; pub use solid::Solid; use crate::types::Vec3; pub trait Texture { - fn value(&self, u: f64, v: f64, p: &mut Vec3); + fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3; } diff --git a/src/texture/perlin.rs b/src/texture/perlin.rs new file mode 100644 index 0000000..ab029fe --- /dev/null +++ b/src/texture/perlin.rs @@ -0,0 +1,70 @@ +use crate::types::Vec3; +use rand::{distributions::Uniform, Rng}; + +const POINT_COUNT: usize = 256; + +pub struct Perlin { + points: Vec, + + permute_x: Vec, + permute_y: Vec, + permute_z: Vec, +} + +impl Perlin { + pub fn new(rng: &mut R) -> Self { + let mut points = vec![0.0; POINT_COUNT]; + + for p in points.iter_mut() { + *p = rng.gen_range(0.0..=1.0) + } + + let permute_x = Self::perlin_generate_permutation(rng); + let permute_y = Self::perlin_generate_permutation(rng); + let permute_z = Self::perlin_generate_permutation(rng); + + Self { + points, + permute_x, + permute_y, + permute_z, + } + } + + fn perlin_generate_permutation(rng: &mut R) -> Vec { + let mut p = (0..POINT_COUNT).collect::>(); + permute(rng, &mut p); + p + } + + pub fn noise(&self, p: &Vec3) -> f64 { + let i = (4.0 * p.x()) as usize & 255; + let j = (4.0 * p.y()) as usize & 255; + let k = (4.0 * p.z()) as usize & 255; + + // if p.x() > 1.0 && p.y() > 1.0 && p.z() > 1.0 { + // println!( + // "p = {} i = {} j = {} k = {} pi = {} pj = {} pk = {} point = {}", + // p, + // i, + // j, + // k, + // self.permute_x[i], + // self.permute_x[j], + // self.permute_x[k], + // self.points[self.permute_x[i] ^ self.permute_y[j] ^ self.permute_z[k]] + // ); + // } + + self.points[self.permute_x[i] ^ self.permute_y[j] ^ self.permute_z[k]] + } +} + +fn permute(rng: &mut R, p: &mut [usize]) { + let l = p.len(); + + for i in (0..l).rev() { + let r = rng.gen_range(0..=i); + p.swap(i, r); + } +} diff --git a/src/texture/perlin_noise.rs b/src/texture/perlin_noise.rs new file mode 100644 index 0000000..1f7490c --- /dev/null +++ b/src/texture/perlin_noise.rs @@ -0,0 +1,21 @@ +use rand::Rng; + +use crate::{texture::Perlin, types::Vec3, Texture}; + +pub struct PerlinNoise { + noise: Perlin, +} + +impl PerlinNoise { + pub fn new(rng: &mut R) -> Self { + Self { + noise: Perlin::new(rng), + } + } +} + +impl Texture for PerlinNoise { + fn value(&self, _u: f64, _v: f64, p: &Vec3) -> Vec3 { + Vec3::new(1.0, 1.0, 1.0) * self.noise.noise(p) + } +} diff --git a/src/texture/solid.rs b/src/texture/solid.rs index 7d8f04e..e4ce99c 100644 --- a/src/texture/solid.rs +++ b/src/texture/solid.rs @@ -11,7 +11,7 @@ impl Solid { } impl Texture for Solid { - fn value(&self, _u: f64, _v: f64, p: &mut Vec3) { - *p = self.color + fn value(&self, _u: f64, _v: f64, _p: &Vec3) -> Vec3 { + self.color } }