From 7468ba111203788f7fcced34c15a2d3402683393 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Fri, 5 Mar 2021 20:54:25 +0530 Subject: [PATCH] completed perlin textures --- src/main.rs | 10 ++--- src/texture/perlin.rs | 86 ++++++++++++++++++++++--------------- src/texture/perlin_noise.rs | 4 +- src/types/vec3.rs | 7 +++ 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/src/main.rs b/src/main.rs index 48236a4..6325d38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,11 +23,11 @@ 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; -const HEIGHT: usize = 1080; +const WIDTH: usize = 2560; +const HEIGHT: usize = 1440; fn main() -> Result<(), String> { run(WIDTH, HEIGHT) @@ -134,9 +134,9 @@ 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); diff --git a/src/texture/perlin.rs b/src/texture/perlin.rs index 5881213..12d8336 100644 --- a/src/texture/perlin.rs +++ b/src/texture/perlin.rs @@ -1,10 +1,10 @@ use crate::types::Vec3; -use rand::{distributions::Uniform, Rng}; +use rand::Rng; const POINT_COUNT: usize = 256; pub struct Perlin { - points: Vec, + points: Vec, permute_x: Vec, permute_y: Vec, @@ -13,10 +13,9 @@ pub struct Perlin { impl Perlin { pub fn new(rng: &mut R) -> Self { - let points = rng - .sample_iter(Uniform::from(0.0..=1.0)) - .take(POINT_COUNT) - .collect::>(); + let points = (0..POINT_COUNT) + .map(|_| Vec3::random(rng).unit_vector()) + .collect::>(); let permute_x = Self::perlin_generate_permutation(rng); let permute_y = Self::perlin_generate_permutation(rng); @@ -37,41 +36,57 @@ impl Perlin { } pub fn noise(&self, p: Vec3) -> f64 { - let i = p.x().floor() as i32; - let j = p.y().floor() as i32; - let k = p.z().floor() as i32; + let mut smooth_grid = [[[Vec3::new(0.0, 0.0, 0.0); 2]; 2]; 2]; - let mut smooth_grid = [[[0.0; 2]; 2]; 2]; + { + let i = p.x().floor() as i32; + let j = p.y().floor() as i32; + let k = p.z().floor() as i32; + for (di, a) in smooth_grid.iter_mut().enumerate() { + let di = di as i32; + for (dj, b) in a.iter_mut().enumerate() { + let dj = dj as i32; + for (dk, c) in b.iter_mut().enumerate() { + let dk = dk as i32; - for (di, a) in smooth_grid.iter_mut().enumerate() { - let di = di as i32; - for (dj, b) in a.iter_mut().enumerate() { - let dj = dj as i32; - for (dk, c) in b.iter_mut().enumerate() { - let dk = dk as i32; - *c = self.points[self.permute_x[((i + di) & 255) as usize] - ^ self.permute_y[((j + dj) & 255) as usize] - ^ self.permute_z[((k + dk) & 255) as usize]] + *c = self.points[self.permute_x[((i + di) & 255) as usize] + ^ self.permute_y[((j + dj) & 255) as usize] + ^ self.permute_z[((k + dk) & 255) as usize]] + } } } } - let mut u = p.x() - p.x().floor(); - let mut v = p.y() - p.y().floor(); - let mut w = p.z() - p.z().floor(); + let u = p.x() - p.x().floor(); + let v = p.y() - p.y().floor(); + let w = p.z() - p.z().floor(); - // Hermitian smoothing so we don't see obvious grid features in the picture - // Those features show up when we interpolate colors. Those features are - // also called mach bands - u = u * u * (3.0 - 2.0 * u); - v = v * v * (3.0 - 2.0 * v); - w = w * w * (3.0 - 2.0 * w); + perlin_interpolate(smooth_grid, u, v, w) + } - return trilinear_interpolate(smooth_grid, u, v, w); + pub fn turbulence(&self, p: Vec3, depth: u32) -> f64 { + let mut acc = 0.0f64; + let mut weight = 1.0; + let mut temp_p = p; + + for _i in 0..depth { + acc += weight * self.noise(temp_p); + weight *= 0.5; + temp_p *= 2.0; + } + + acc.abs() } } -fn trilinear_interpolate(smooth_grid: [[[f64; 2]; 2]; 2], u: f64, v: f64, w: f64) -> f64 { +fn perlin_interpolate(smooth_grid: [[[Vec3; 2]; 2]; 2], u: f64, v: f64, w: f64) -> f64 { + // Hermitian smoothing so we don't see obvious grid features in the picture + // Those features show up when we interpolate colors. Those features are + // also called mach bands + let uu = u * u * (3.0 - 2.0 * u); + let vv = v * v * (3.0 - 2.0 * v); + let ww = w * w * (3.0 - 2.0 * w); + let mut acc = 0.0; for (di, a) in smooth_grid.iter().enumerate() { @@ -80,10 +95,13 @@ fn trilinear_interpolate(smooth_grid: [[[f64; 2]; 2]; 2], u: f64, v: f64, w: f64 let dj = dj as f64; for (dk, c) in b.iter().enumerate() { let dk = dk as f64; - acc += (di * u + (1.0 - di) * (1.0 - u)) - * (dj * v + (1.0 - dj) * (1.0 - v)) - * (dk * w + (1.0 - dk) * (1.0 - w)) - * c; + + let wt = Vec3::new(u - di, v - dj, w - dk); + + acc += (di * uu + (1.0 - di) * (1.0 - uu)) + * (dj * vv + (1.0 - dj) * (1.0 - vv)) + * (dk * ww + (1.0 - dk) * (1.0 - ww)) + * c.dot(&wt); } } } diff --git a/src/texture/perlin_noise.rs b/src/texture/perlin_noise.rs index e7ab463..ab94de2 100644 --- a/src/texture/perlin_noise.rs +++ b/src/texture/perlin_noise.rs @@ -26,6 +26,8 @@ impl PerlinNoise { 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 * self.scale) + Vec3::new(1.0, 1.0, 1.0) + * 0.5 + * (1.0 + (self.scale * p.z() + 10.0 * self.noise.turbulence(p, 7)).sin()) } } diff --git a/src/types/vec3.rs b/src/types/vec3.rs index 6235253..84896c1 100644 --- a/src/types/vec3.rs +++ b/src/types/vec3.rs @@ -3,6 +3,8 @@ use std::{ ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign}, }; +use rand::Rng; + #[derive(Debug, Copy, Clone)] pub struct Vec3([f64; 3]); @@ -73,6 +75,11 @@ impl Vec3 { let length = self.length(); Vec3([self[0] / length, self[1] / length, self[2] / length]) } + + #[inline] + pub fn random(rng: &mut R) -> Vec3 { + Vec3([rng.gen(), rng.gen(), rng.gen()]) + } } impl Add for Vec3 {