diff --git a/Cargo.lock b/Cargo.lock index 2ea780a..5c113ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,13 +22,6 @@ name = "bitflags" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "blue_noise_mask" -version = "0.1.0" -dependencies = [ - "rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "c_vec" version = "1.0.12" @@ -62,11 +55,6 @@ name = "crossbeam" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "deque" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "float4" version = "0.1.0" @@ -165,7 +153,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "psychopath" version = "0.1.0" dependencies = [ - "blue_noise_mask 0.1.0", "clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "float4 0.1.0", @@ -184,34 +171,6 @@ dependencies = [ "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "deque 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.1.17" @@ -300,7 +259,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf1114886d7cde2d6448517161d7db8d681a9a1c09f7d210f0b0864e48195f6" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum deque 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a694dae478589798d752c7125542f8a5ae8b6e59476172baf2eed67357bdfa27" "checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" @@ -311,9 +269,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum openexr 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)" = "" "checksum openexr-sys 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)" = "" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum rayon 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c83adcb08e5b922e804fe1918142b422602ef11f2fd670b0b52218cb5984a20" -"checksum rayon-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "767d91bacddf07d442fe39257bf04fd95897d1c47c545d009f6beb03efd038f8" "checksum redox_syscall 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "29dbdfd4b9df8ab31dec47c6087b7b13cbf4a776f335e4de8efba8288dda075b" "checksum rgb 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4db5350eea2dbb4f4972c4fb4d980b70c3f0ed3983eb2f66d174a43457514a14" "checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0" diff --git a/Cargo.toml b/Cargo.toml index c8847ee..eb4233f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "sub_crates/blue_noise_mask", "sub_crates/float4", "sub_crates/halton", "sub_crates/math3d", @@ -37,9 +36,6 @@ lazy_static = "0.2" openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" } # Local crate dependencies -[dependencies.blue_noise_mask] -path = "sub_crates/blue_noise_mask" - [dependencies.float4] path = "sub_crates/float4" diff --git a/src/main.rs b/src/main.rs index baaefcd..61ebee9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -extern crate blue_noise_mask; extern crate float4; extern crate halton; extern crate math3d; diff --git a/src/renderer.rs b/src/renderer.rs index 48c0834..baa8ddb 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -8,8 +8,6 @@ use std::sync::{RwLock, Mutex}; use crossbeam::sync::MsQueue; use scoped_threadpool::Pool; -use blue_noise_mask; -use blue_noise_mask::{MASKS, NUM_MASKS_WRAP_BITMASK}; use halton; use algorithm::partition_pair; @@ -137,19 +135,16 @@ impl<'a> Renderer<'a> { // Generate light paths and initial rays for y in bucket.y..(bucket.y + bucket.h) { for x in bucket.x..(bucket.x + bucket.w) { - let x = x as u32; - let y = y as u32; - - let mask_i = blue_noise_mask::get_index_to_point(x, y) + ((self.seed as usize * 53) & NUM_MASKS_WRAP_BITMASK as usize); - + let offset = hash_u32(((x as u32) << 16) ^ (y as u32), self.seed); for si in 0..self.spp { - let si = si as u32; // Calculate image plane x and y coordinates let (img_x, img_y) = { - let filter_x = - fast_logit(rot_f32(halton::sample(0, si), MASKS[(mask_i + 4) & (MASKS.len() - 1)]), 1.5) + 0.5; + let filter_x = + fast_logit(halton::sample(4, offset + si as u32), 1.5) + + 0.5; let filter_y = - fast_logit(rot_f32(halton::sample(1, si), MASKS[(mask_i + 5) & (MASKS.len() - 1)]), 1.5) + 0.5; + fast_logit(halton::sample(5, offset + si as u32), 1.5) + + 0.5; let samp_x = (filter_x + x as f32) * cmpx; let samp_y = (filter_y + y as f32) * cmpy; ((samp_x - 0.5) * x_extent, (0.5 - samp_y) * y_extent) @@ -160,12 +155,14 @@ impl<'a> Renderer<'a> { LightPath::new(&self.scene, (x, y), (img_x, img_y), - (rot_f32(halton::sample(2, si), MASKS[(mask_i + 0) & (MASKS.len() - 1)]), - rot_f32(halton::sample(3, si), MASKS[(mask_i + 1) & (MASKS.len() - 1)])), - rot_f32(halton::sample(4, si), MASKS[(mask_i + 2) & (MASKS.len() - 1)]), - map_0_1_to_wavelength(rot_f32(halton::sample(5, si), MASKS[(mask_i + 3) & (MASKS.len() - 1)])), - si, - mask_i as u32); + (halton::sample(0, offset + si as u32), + halton::sample(1, offset + si as u32)), + halton::sample(2, offset + si as u32), + map_0_1_to_wavelength(halton::sample(3, + offset + + si as + u32)), + offset + si as u32); paths.push(path); rays.push(ray); } @@ -312,7 +309,6 @@ pub struct LightPath { pixel_co: (u32, u32), lds_offset: u32, dim_offset: Cell, - mask_offset: Cell, time: f32, wavelength: f32, @@ -331,8 +327,7 @@ impl LightPath { lens_uv: (f32, f32), time: f32, wavelength: f32, - lds_offset: u32, - mask_offset: u32) + lds_offset: u32) -> (LightPath, Ray) { (LightPath { event: LightPathEvent::CameraRay, @@ -341,7 +336,6 @@ impl LightPath { pixel_co: pixel_co, lds_offset: lds_offset, dim_offset: Cell::new(6), - mask_offset: Cell::new(mask_offset + 6), time: time, wavelength: wavelength, @@ -361,13 +355,10 @@ impl LightPath { } fn next_lds_samp(&self) -> f32 { - let dim = self.dim_offset.get(); - let mask_i = self.mask_offset.get(); - self.dim_offset.set(dim + 1); - self.mask_offset.set((mask_i + 1) & (MASKS.len() - 1) as u32); - - let samp = halton::sample(dim, self.lds_offset); - rot_f32(samp, unsafe { *MASKS.get_unchecked(mask_i as usize) }) + let s = halton::sample(self.dim_offset.get(), self.lds_offset); + let inc = self.dim_offset.get() + 1; + self.dim_offset.set(inc); + s } fn next(&mut self, @@ -514,15 +505,3 @@ struct BucketJob { w: u32, h: u32, } - -#[inline(always)] -fn rot_f32(a: f32, b: f32) -> f32 { - //assert!(a >= 0.0); - //assert!(b >= 0.0); - let mut c = a + b; - while c >= 1.0 { - c -= 1.0; - } - - c -} diff --git a/sub_crates/blue_noise_mask/Cargo.toml b/sub_crates/blue_noise_mask/Cargo.toml deleted file mode 100644 index e6b91f9..0000000 --- a/sub_crates/blue_noise_mask/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "blue_noise_mask" -version = "0.1.0" -authors = ["Nathan Vegdahl "] -license = "MIT" -build = "build.rs" - -[lib] -name = "blue_noise_mask" -path = "src/lib.rs" - -[build-dependencies] -rayon = "0.7" \ No newline at end of file diff --git a/sub_crates/blue_noise_mask/build.rs b/sub_crates/blue_noise_mask/build.rs deleted file mode 100644 index ccab5bc..0000000 --- a/sub_crates/blue_noise_mask/build.rs +++ /dev/null @@ -1,237 +0,0 @@ -// Generate Blue Noise Mask tables. - -extern crate rayon; - -use std::cmp::Ordering; -use std::env; -use std::fs::File; -use std::io::Write; -use std::ops::{Index, IndexMut}; -use std::path::Path; - -use rayon::prelude::*; - -const WINDOW_RADIUS: isize = 63; -const FILTER_WIDTH: f32 = 1.2; -const FILTER_PASSES: usize = 1; - -// These are specified in powers of two (2^N) for fast wrapping -// in the generated Rust code. -const NUM_MASKS_POW: usize = 7; // 128 -const MASK_SIZE_POW: usize = 7; // 128 - -const MASK_SIZE: usize = 1 << MASK_SIZE_POW; -const MASK_SIZE_BITMASK: usize = (1 << MASK_SIZE_POW) - 1; - -fn main() { - let out_dir = env::var("OUT_DIR").unwrap(); - let dest_path = Path::new(&out_dir).join("blue_noise_masks.rs"); - let mut f = File::create(&dest_path).unwrap(); - - // Generate masks - let masks = (0..(1 << NUM_MASKS_POW)) - .collect::>() - .par_iter() - .map(|i| blue_noise_mask(*i)) - .collect::>(); - - // Write the beginning bits of the file - f.write_all(format!(r#" -// This file is automatically generated. - -// Compute points of the Halton sequence with with Faure-permutations for different bases. - -pub const NUM_MASKS: u32 = {}; -pub const MASK_SIZE: u32 = {}; -pub const NUM_MASKS_WRAP_BITMASK: u32 = {}; -const MASK_SIZE_WRAP_BITMASK: u32 = {}; -const MASK_POINTS: u32 = {}; - -#[inline] -pub fn get_point(x: u32, y: u32) -> &'static [f32] {{ - let i = get_index_to_point(x, y); - - &MASKS[i..(i + NUM_MASKS as usize)] -}} - -#[inline] -pub fn get_index_to_point(x: u32, y: u32) -> usize {{ - let x = x & MASK_SIZE_WRAP_BITMASK; - let y = y & MASK_SIZE_WRAP_BITMASK; - - ((y * MASK_SIZE * NUM_MASKS) + (x * NUM_MASKS)) as usize -}} -"#, - 1 << NUM_MASKS_POW, - MASK_SIZE, - (1 << NUM_MASKS_POW) - 1, - MASK_SIZE_BITMASK, - MASK_SIZE * MASK_SIZE, - ).as_bytes()).unwrap(); - - // Write the mask data - f.write_all(format!(r#" -pub static MASKS: [f32; {}] = [ - "#, MASK_SIZE * MASK_SIZE * (1 << NUM_MASKS_POW)).as_bytes()).unwrap(); - - for y in 0..MASK_SIZE { - for x in 0..MASK_SIZE { - for mask in masks.iter() { - let v = mask[(x as isize, y as isize)]; - f.write_all(format!(r#" {:.8}, -"#, v).as_bytes()).unwrap(); - } - } - } - - f.write_all(format!(r#" -]; -"#).as_bytes()).unwrap(); -} - - - -/// Creates a blue noise mask -fn blue_noise_mask(seed: u32) -> Mask { - // Generate white noise mask - let mut mask = Mask::new(); - for (i, v) in mask.data.iter_mut().enumerate() { - *v = hash_u32_to_f32(i as u32, seed); - } - - // High pass and remap - for _ in 0..FILTER_PASSES { - high_pass_filter(&mut mask, WINDOW_RADIUS, FILTER_WIDTH); - remap_values(&mut mask); - } - - mask -} - -/// Performs a high pass filter on a Mask -fn high_pass_filter(mask: &mut Mask, window_radius: isize, filter_width: f32) { - // Precompute filter convolution matrix - let conv = { - let mut conv = Mask::new(); - for j in (-window_radius)..(window_radius + 1) { - for i in (-window_radius)..(window_radius + 1) { - let n = (((j * j) + (i * i)) as f32).sqrt(); - //let n = (j.abs() + i.abs()) as f32; - conv[(i + window_radius, j + window_radius)] = sinc(n, filter_width); - } - } - - let inv_total = 1.0f32 / conv.data.iter().sum::(); - for v in conv.data.iter_mut() { - *v *= inv_total; - } - - conv - }; - - // Compute the low-pass mask - let mut low_pass_mask = Mask::new(); - for y in 0..MASK_SIZE { - for x in 0..MASK_SIZE { - for j in (-window_radius as isize)..(window_radius + 1) { - for i in (-window_radius as isize)..(window_radius + 1) { - let b = y as isize + j; - let a = x as isize + i; - let alpha = conv[(i + window_radius, j + window_radius)]; - low_pass_mask[(x as isize, y as isize)] += mask.get_wrapped(a, b) * alpha; - } - } - } - } - - // Subtract low pass from original - for i in 0..mask.data.len() { - mask.data[i] -= low_pass_mask.data[i]; - } -} - -/// Remaps the values in a Mask to be linearly distributed within [0, 1] -fn remap_values(mask: &mut Mask) { - let mut vals = Vec::with_capacity(MASK_SIZE * MASK_SIZE); - for y in 0..MASK_SIZE { - for x in 0..MASK_SIZE { - vals.push((mask[(x as isize, y as isize)], x, y)); - } - } - vals.sort_by(|a, b| if a < b { - Ordering::Less - } else { - Ordering::Greater - }); - let inc = 1.0 / (vals.len() - 1) as f32; - let mut n = 0.0; - for v in vals.iter() { - mask[(v.1 as isize, v.2 as isize)] = n; - n += inc; - } -} - -/// Normal distribution -fn gauss(x: f32, sd: f32) -> f32 { - let norm = 1.0 / (2.0 * std::f32::consts::PI * sd * sd).sqrt(); - let dist = ((-x * x) / (2.0 * sd * sd)).exp(); - norm * dist -} - -// Sinc filter function -fn sinc(x: f32, w: f32) -> f32 { - if x == 0.0 { - 1.0 - } else { - let x = x * std::f32::consts::PI / w; - x.sin() / x - } -} - -/// Returns a random float in [0, 1] based on 'n' and a seed. -/// Generally use n for getting a bunch of different random -/// numbers, and use seed to vary between runs. -pub fn hash_u32_to_f32(n: u32, seed: u32) -> f32 { - let mut hash = n; - - for _ in 0..8 { - hash = hash.wrapping_mul(1936502639); - hash ^= hash.wrapping_shr(16); - hash = hash.wrapping_add(seed); - } - - const INV_MAX: f32 = 1.0 / std::u32::MAX as f32; - return hash as f32 * INV_MAX; -} - - -// Holds data for a 2d mask -struct Mask { - data: Vec, -} - -impl Mask { - fn new() -> Mask { - Mask { data: vec![0.0; MASK_SIZE * MASK_SIZE] } - } - - fn get_wrapped(&self, ix: isize, iy: isize) -> f32 { - let x = (ix + MASK_SIZE as isize) as usize & MASK_SIZE_BITMASK; - let y = (iy + MASK_SIZE as isize) as usize & MASK_SIZE_BITMASK; - - self.data[(y << MASK_SIZE_POW) + x] - } -} - -impl Index<(isize, isize)> for Mask { - type Output = f32; - fn index(&self, index: (isize, isize)) -> &f32 { - &self.data[index.1 as usize * MASK_SIZE + index.0 as usize] - } -} - -impl IndexMut<(isize, isize)> for Mask { - fn index_mut(&mut self, index: (isize, isize)) -> &mut f32 { - &mut self.data[index.1 as usize * MASK_SIZE + index.0 as usize] - } -} diff --git a/sub_crates/blue_noise_mask/src/lib.rs b/sub_crates/blue_noise_mask/src/lib.rs deleted file mode 100644 index d75a756..0000000 --- a/sub_crates/blue_noise_mask/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![allow(dead_code)] - -// Include the file generated by the build.rs script -include!(concat!(env!("OUT_DIR"), "/blue_noise_masks.rs"));