Removed blue noise dithered sampling.

This commit is contained in:
Nathan Vegdahl 2017-05-14 12:37:01 -07:00
parent d71fd3b5c8
commit 567b658b6c
7 changed files with 19 additions and 344 deletions

45
Cargo.lock generated
View File

@ -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)" = "<none>"
"checksum openexr-sys 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)" = "<none>"
"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"

View File

@ -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"

View File

@ -1,4 +1,3 @@
extern crate blue_noise_mask;
extern crate float4;
extern crate halton;
extern crate math3d;

View File

@ -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<u32>,
mask_offset: Cell<u32>,
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
}

View File

@ -1,13 +0,0 @@
[package]
name = "blue_noise_mask"
version = "0.1.0"
authors = ["Nathan Vegdahl <cessen@cessen.com>"]
license = "MIT"
build = "build.rs"
[lib]
name = "blue_noise_mask"
path = "src/lib.rs"
[build-dependencies]
rayon = "0.7"

View File

@ -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::<Vec<_>>()
.par_iter()
.map(|i| blue_noise_mask(*i))
.collect::<Vec<_>>();
// 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::<f32>();
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<f32>,
}
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]
}
}

View File

@ -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"));