1
0

Trying to figure out perlin noise

This commit is contained in:
Ishan Jain 2021-03-05 16:11:41 +05:30
parent b4d7ddfc4d
commit 4f2365dbca
No known key found for this signature in database
GPG Key ID: F261A0E73038D89D
10 changed files with 176 additions and 13 deletions

View File

@ -4,7 +4,6 @@ version = "0.1.0"
authors = ["ishanjain28 <ishanjain28@gmail.com>"] authors = ["ishanjain28 <ishanjain28@gmail.com>"]
edition = "2018" edition = "2018"
[features] [features]
default = ["gui"] default = ["gui"]
gui = ["sdl2"] gui = ["sdl2"]

View File

@ -12,9 +12,11 @@ use std::{
}; };
mod checkered_motion_blur; mod checkered_motion_blur;
mod perlin_noise_ball;
mod two_spheres; mod two_spheres;
pub use checkered_motion_blur::CheckeredMotionBlur; pub use checkered_motion_blur::CheckeredMotionBlur;
pub use perlin_noise_ball::PerlinNoiseBall;
pub use two_spheres::TwoSpheres; pub use two_spheres::TwoSpheres;
#[derive(Debug)] #[derive(Debug)]

View File

@ -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<Arc<dyn ParallelHit>>;
fn name(&self) -> &'static str {
"perlin_noise"
}
fn world(&self) -> Self::DemoT {
let mut world: Vec<Arc<dyn ParallelHit>> = 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,
)
}
}

View File

@ -23,7 +23,7 @@ use demos::Demo;
use std::time::Instant; use std::time::Instant;
const NUM_SAMPLES: u8 = 25; const NUM_SAMPLES: u8 = 255;
const VERTICAL_PARTITION: usize = 12; const VERTICAL_PARTITION: usize = 12;
const HORIZONTAL_PARTITION: usize = 12; const HORIZONTAL_PARTITION: usize = 12;
const WIDTH: usize = 1920; const WIDTH: usize = 1920;
@ -68,7 +68,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> = let mut active_demo: &dyn Demo<DemoT = BvhNode<Arc<dyn ParallelHit>>> =
&demos::CheckeredMotionBlur {}; &demos::PerlinNoiseBall {};
let mut should_update = true; let mut should_update = true;
loop { loop {
@ -93,6 +93,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
active_demo = &demos::TwoSpheres {}; active_demo = &demos::TwoSpheres {};
should_update = true; should_update = true;
} }
Some(Keycode::Num3) => {
active_demo = &demos::PerlinNoiseBall {};
should_update = true;
}
None => unreachable!(), None => unreachable!(),
_ => (), _ => (),
}; };
@ -130,9 +134,11 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> {
#[cfg(not(feature = "gui"))] #[cfg(not(feature = "gui"))]
fn run(width: usize, height: usize) -> Result<(), String> { 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(()) Ok(())
} }

View File

@ -21,9 +21,9 @@ impl<T: Texture + Send + Sync> Material for Lambertian<T> {
let scatter_direction = hit_rec.normal + random_point_in_unit_sphere(rng); 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 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); self.albedo.value(hit_rec.u, hit_rec.v, &hit_rec.p),
Some(scattered_ray),
(p, Some(scattered_ray)) )
} }
} }

View File

@ -12,7 +12,7 @@ impl<T: Texture> Checker<T> {
} }
impl<T: Texture> Texture for Checker<T> { impl<T: Texture> Texture for Checker<T> {
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()); 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 { if sine_wave < 0.0 {

View File

@ -1,11 +1,15 @@
mod checker; mod checker;
mod perlin;
mod perlin_noise;
mod solid; mod solid;
pub use checker::Checker; pub use checker::Checker;
pub use perlin::Perlin;
pub use perlin_noise::PerlinNoise;
pub use solid::Solid; pub use solid::Solid;
use crate::types::Vec3; use crate::types::Vec3;
pub trait Texture { pub trait Texture {
fn value(&self, u: f64, v: f64, p: &mut Vec3); fn value(&self, u: f64, v: f64, p: &Vec3) -> Vec3;
} }

70
src/texture/perlin.rs Normal file
View File

@ -0,0 +1,70 @@
use crate::types::Vec3;
use rand::{distributions::Uniform, Rng};
const POINT_COUNT: usize = 256;
pub struct Perlin {
points: Vec<f64>,
permute_x: Vec<usize>,
permute_y: Vec<usize>,
permute_z: Vec<usize>,
}
impl Perlin {
pub fn new<R: Rng + ?Sized>(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<R: Rng + ?Sized>(rng: &mut R) -> Vec<usize> {
let mut p = (0..POINT_COUNT).collect::<Vec<usize>>();
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<R: Rng + ?Sized>(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);
}
}

View File

@ -0,0 +1,21 @@
use rand::Rng;
use crate::{texture::Perlin, types::Vec3, Texture};
pub struct PerlinNoise {
noise: Perlin,
}
impl PerlinNoise {
pub fn new<R: Rng + ?Sized>(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)
}
}

View File

@ -11,7 +11,7 @@ impl Solid {
} }
impl Texture for Solid { impl Texture for Solid {
fn value(&self, _u: f64, _v: f64, p: &mut Vec3) { fn value(&self, _u: f64, _v: f64, _p: &Vec3) -> Vec3 {
*p = self.color self.color
} }
} }