diff --git a/rtiow/Cargo.lock b/rtiow/Cargo.lock index 4533176..7badcbc 100644 --- a/rtiow/Cargo.lock +++ b/rtiow/Cargo.lock @@ -490,6 +490,7 @@ dependencies = [ "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/rtiow/Cargo.toml b/rtiow/Cargo.toml index 6767136..7dd2a73 100644 --- a/rtiow/Cargo.toml +++ b/rtiow/Cargo.toml @@ -13,6 +13,7 @@ structopt = "0.2.10" stderrlog = "0.4.1" log = "0.4.5" cpuprofiler = "0.0.3" +lazy_static = "1.1.0" # For better profiling support. [profile.release] diff --git a/rtiow/src/lib.rs b/rtiow/src/lib.rs index bf3ea5d..b3c4c07 100644 --- a/rtiow/src/lib.rs +++ b/rtiow/src/lib.rs @@ -7,6 +7,7 @@ pub mod hitable_list; pub mod kdtree; pub mod material; pub mod moving_sphere; +pub mod perlin; pub mod ray; pub mod renderer; pub mod scenes; @@ -17,6 +18,8 @@ pub mod vec3; extern crate crossbeam_channel; extern crate image; #[macro_use] +extern crate lazy_static; +#[macro_use] extern crate log; extern crate num_cpus; extern crate rand; diff --git a/rtiow/src/perlin.rs b/rtiow/src/perlin.rs new file mode 100644 index 0000000..9c9d54f --- /dev/null +++ b/rtiow/src/perlin.rs @@ -0,0 +1,98 @@ +use rand; +use rand::Rng; +//use rand::SeedableRng; +//use rand::XorShiftRng; + +use vec3::Vec3; + +lazy_static! { + pub static ref GENERATOR: Perlin = Perlin::new(); +} +//const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + +pub struct Perlin { + ranfloat: Vec, + perm_x: Vec, + perm_y: Vec, + perm_z: Vec, +} + +fn perlin_generate() -> Vec { + //let mut rng: XorShiftRng = SeedableRng::from_seed(SEED); + let mut rng = rand::thread_rng(); + (0..256).map(|_| rng.gen_range::(0., 1.)).collect() +} + +fn permute(p: &mut Vec, n: usize) { + //let mut rng: XorShiftRng = SeedableRng::from_seed(SEED); + let mut rng = rand::thread_rng(); + let mut random = || rng.gen_range::(0., 1.); + for i in (0..n).rev() { + let target = (random() * (i + 1) as f32) as usize; + let tmp = p[i]; + p[i] = p[target]; + p[target] = tmp; + } +} + +fn perlin_generate_perm() -> Vec { + let mut p: Vec = (0..256).map(|i| i).collect(); + permute(p.as_mut(), 256); + p +} + +fn trilinear_interp(c: [[[f32; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 { + let mut accum = 0.; + for i in 0..2 { + for j in 0..2 { + for k in 0..2 { + let fi = i as f32; + let fj = j as f32; + let fk = k as f32; + accum += (fi * u + (1. - fi) * (1. - u)) + * (fj * v + (1. - fj) * (1. - v)) + * (fk * w + (1. - fk) * (1. - w)) + * c[i][j][k]; + } + } + } + accum +} + +impl Perlin { + fn new() -> Perlin { + Perlin { + ranfloat: perlin_generate(), + perm_x: perlin_generate_perm(), + perm_y: perlin_generate_perm(), + perm_z: perlin_generate_perm(), + } + } + + pub fn noise(&self, p: Vec3) -> f32 { + let mut u = p.x - p.x.floor(); + let mut v = p.y - p.y.floor(); + let mut w = p.z - p.z.floor(); + + // Hermite cubic to round off interpolation and attempt to address 'mach bands'. + u = u * u * (3. - 2. * u); + v = v * v * (3. - 2. * v); + w = w * w * (3. - 2. * w); + + let i = p.x.floor() as usize; + let j = p.y.floor() as usize; + let k = p.z.floor() as usize; + + let mut c: [[[f32; 2]; 2]; 2] = Default::default(); + for di in 0..2 { + for dj in 0..2 { + for dk in 0..2 { + c[di][dj][dk] = self.ranfloat[self.perm_x[(i + di) & 255] + ^ self.perm_y[(j + dj) & 255] + ^ self.perm_z[(k + dk) & 255]] + } + } + } + trilinear_interp(c, u, v, w) + } +} diff --git a/rtiow/src/renderer.rs b/rtiow/src/renderer.rs index 9eb51c4..f9f14b3 100644 --- a/rtiow/src/renderer.rs +++ b/rtiow/src/renderer.rs @@ -76,7 +76,7 @@ pub struct Opt { #[structopt(short = "h", long = "height", default_value = "1024")] pub height: usize, /// Sub-samples per pixel - #[structopt(short = "s", long = "subsample", default_value = "1")] + #[structopt(short = "s", long = "subsample", default_value = "8")] pub subsamples: usize, /// Select scene to render, one of: "bench", "book", "tutorial" "cube", "bvh", "test" #[structopt(long = "model", default_value = "test")] diff --git a/rtiow/src/scenes/test.rs b/rtiow/src/scenes/test.rs index c3f7ae4..99b63c5 100644 --- a/rtiow/src/scenes/test.rs +++ b/rtiow/src/scenes/test.rs @@ -1,24 +1,24 @@ -use std::f32::consts::PI; - use camera::Camera; use hitable::Hit; use hitable_list::HitableList; use kdtree::KDTree; use material::Lambertian; +use material::Metal; +use moving_sphere::MovingSphere; use renderer::Opt; use renderer::Scene; use sphere::Sphere; -use texture::CheckerTexture; use texture::ConstantTexture; +use texture::NoiseTexture; use vec3::Vec3; pub fn new(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(0.001, 0.001, 20.); + let lookfrom = Vec3::new(5., 5., 5.); let lookat = Vec3::new(0., 0., 0.); let dist_to_focus = (lookfrom - lookat).length(); let aperture = 0.1; let time_min = 0.; - let time_max = 0.; + let time_max = 1.; let camera = Camera::new( lookfrom, lookat, @@ -30,48 +30,52 @@ pub fn new(opt: &Opt) -> Scene { time_min, time_max, ); - let mut objects: Vec> = vec![Box::new(Sphere::new( - Vec3::new(0., 0., 0.), - 5., - Box::new(Lambertian::new(Box::new(CheckerTexture::new( - Box::new(ConstantTexture::new(Vec3::new(0., 0., 0.))), - Box::new(ConstantTexture::new(Vec3::new(1., 1., 1.))), - )))), - ))]; - let num_spheres = 6; - let radius = 7.; - for i in 0..num_spheres { - let c1 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).sin(); - let c2 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).cos(); - let center = Vec3::new(0., c1, c2); - objects.push(Box::new(Sphere::new( - center, + let _ground_color = if opt.use_accel { + Box::new(ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))) + } else { + Box::new(ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4))) + }; + + let objects: Vec> = vec![ + Box::new(Sphere::new( + Vec3::new(0., 0., 0.), 0.5, Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 1., 0., 0., + 0.1, 0.2, 0.5, ))))), - ))); - let center = Vec3::new(c1, 0., c2); - objects.push(Box::new(Sphere::new( - center, + )), + // Big sphere + Box::new(Sphere::new( + Vec3::new(0., 0., -2.), + 1.0, + Box::new(Lambertian::new(Box::new(NoiseTexture::with_scale(10.)))), + )), + // Earth sized sphere + Box::new(Sphere::new( + Vec3::new(0., -100.5, 0.), + 100., + // Box::new(Lambertian::new(ground_color)), + Box::new(Lambertian::new(Box::new(NoiseTexture::new()))), + )), + // Shiny sphere + Box::new(Sphere::new( + Vec3::new(1., 0., 0.), 0.5, - Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0., 1., 0., - ))))), - ))); - let center = Vec3::new(c1, c2, 0.); - objects.push(Box::new(Sphere::new( - center, + Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2)), + )), + Box::new(MovingSphere::new( + Vec3::new(-1., 0., -0.25), + Vec3::new(-1., 0., 0.25), 0.5, + 0., + 1., Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new( - 0., 0., 1., + 0.2, 0.8, 0.2, ))))), - ))); - } + )), + ]; let world: Box = if opt.use_accel { - let kd = KDTree::new(objects, time_min, time_max); - //println!("{}", kd); - Box::new(kd) + Box::new(KDTree::new(objects, time_min, time_max)) } else { Box::new(HitableList::new(objects)) }; diff --git a/rtiow/src/texture.rs b/rtiow/src/texture.rs index 4429d18..385ff6d 100644 --- a/rtiow/src/texture.rs +++ b/rtiow/src/texture.rs @@ -1,3 +1,4 @@ +use perlin::GENERATOR; use vec3::Vec3; pub trait Texture: Send + Sync { @@ -41,3 +42,22 @@ impl Texture for CheckerTexture { } } } + +pub struct NoiseTexture { + scale: f32, +} + +impl NoiseTexture { + pub fn new() -> NoiseTexture { + NoiseTexture { scale: 1. } + } + pub fn with_scale(scale: f32) -> NoiseTexture { + NoiseTexture { scale } + } +} + +impl Texture for NoiseTexture { + fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 { + Vec3::new(1., 1., 1.) * GENERATOR.noise(self.scale * p) + } +}