diff --git a/src/main.rs b/src/main.rs index 17b73fb..0cdc9a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex}; use std::time::Instant; use crate::camera::Camera; -use crate::hittable::{Hittable, Sphere, HittableList, HittableObject}; +use crate::hittable::{Sphere, HittableList, HittableObject}; use crate::output::{Output, PNG}; use crate::ray::Ray; use crate::vec3::{Color, Point3, Vec3}; @@ -12,7 +12,8 @@ use rand::distributions::{Distribution, Uniform}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use crate::material::{Dielectric, Lambertian, Material, Metal}; use crate::aabb::Aabb; -use crate::bvh::BVH; +use crate::noise::NoiseTexture; +use crate::perlin::Perlin; use crate::texture::CheckerTexture; mod vec3; @@ -24,6 +25,8 @@ mod output; mod aabb; mod bvh; mod texture; +mod perlin; +mod noise; fn two_spheres() -> HittableList { let mut world:HittableList = Vec::new(); @@ -43,6 +46,22 @@ fn two_spheres() -> HittableList { })); world } +fn two_perlin_spheres() -> HittableList { + let mut world:HittableList = Vec::new(); + let noise = NoiseTexture { noise: Perlin::new() }; + let noise_material = Arc::new(Material::Lambertian(Lambertian::textured(Arc::new(noise)))); + world.push(Arc::new(Sphere { + center: Point3::new(0.0, -1000.0, 0.0), + radius: 1000.0, + material: Arc::clone(&noise_material) + })); + world.push(Arc::new(Sphere { + center: Point3::new(1.0, 2.0, 1.0), + radius: 2.0, + material: noise_material + })); + world +} fn random_scene() -> HittableList { let mut world: HittableList = Vec::new(); @@ -134,7 +153,7 @@ fn main() { let look_from = Point3::new(13.0, 2.0, 3.0); let look_at = Point3::new(0.0, 0.0, 0.0); - let focus_dist = 10.0; + let focus_dist = 2.0; // Camera let cam = Camera::new( @@ -142,16 +161,17 @@ fn main() { look_at, Vec3::new(0.0, 1.0, 0.0), ASPECT_RATIO, - 40.0, + 20.0, 0.0, focus_dist, 0.0, 1.0); // World - let scene: u8 = 0; + let scene: u8 = 1; let world = match scene { 0 => two_spheres(), + 1 => two_perlin_spheres(), _ => random_scene() }; diff --git a/src/material.rs b/src/material.rs index 13c3af1..f0ef5e3 100644 --- a/src/material.rs +++ b/src/material.rs @@ -1,4 +1,3 @@ -use std::rc::Rc; use std::sync::Arc; use rand::Rng; use crate::hittable::HitRecord; diff --git a/src/noise.rs b/src/noise.rs new file mode 100644 index 0000000..2dc5eb2 --- /dev/null +++ b/src/noise.rs @@ -0,0 +1,13 @@ +use crate::perlin::Perlin; +use crate::{Color, Point3}; +use crate::texture::Texture; + +pub struct NoiseTexture { + pub noise: Perlin +} + +impl Texture for NoiseTexture { + fn value(&self, _u: f64, _v: f64, point: &Point3) -> Color { + Color::new(1.0, 1.0, 1.0) * self.noise.noise(point) + } +} diff --git a/src/perlin.rs b/src/perlin.rs new file mode 100644 index 0000000..d2605f0 --- /dev/null +++ b/src/perlin.rs @@ -0,0 +1,46 @@ +use rand::distributions::{Distribution, Uniform}; +use rand::Rng; +use crate::Point3; + +pub struct Perlin { + ranfloat: Vec, + perm_x: Vec, + perm_y: Vec, + perm_z: Vec, +} + +impl Perlin { + const POINT_COUNT: usize = 256; + + pub fn new() -> Self { + let range = Uniform::from(0.0..1.0); + let mut rng = rand::thread_rng(); + let mut ranfloat = Vec::with_capacity(Perlin::POINT_COUNT); + (0..Perlin::POINT_COUNT).for_each(|_i|ranfloat.push(range.sample(&mut rng))); + Perlin { + ranfloat, + perm_x: Perlin::perlin_generate_perm(), + perm_y: Perlin::perlin_generate_perm(), + perm_z: Perlin::perlin_generate_perm(), + } + } + + pub fn noise(&self, point: &Point3) -> f64 { + let i = ((4.0 * point.x()) as i32) & 255; + let j = ((4.0 * point.y()) as i32) & 255; + let k= ((4.0 * point.z()) as i32) & 255; + let idx = self.perm_x[i as usize] ^ self.perm_y[j as usize] ^ self.perm_z[k as usize]; + self.ranfloat[idx] + } + + fn perlin_generate_perm() -> Vec { + let mut p = Vec::with_capacity(Perlin::POINT_COUNT); + (0..Perlin::POINT_COUNT).for_each(|i| p.push(i)); + let mut rng = rand::thread_rng(); + (1..Perlin::POINT_COUNT).rev().for_each(|idx| { + let target = rng.gen_range(0..=idx); + p.swap(idx, target); + }); + p + } +}