Removed blue noise dithered sampling.
This commit is contained in:
parent
d71fd3b5c8
commit
567b658b6c
45
Cargo.lock
generated
45
Cargo.lock
generated
|
@ -22,13 +22,6 @@ name = "bitflags"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "c_vec"
|
name = "c_vec"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
@ -62,11 +55,6 @@ name = "crossbeam"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "float4"
|
name = "float4"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -165,7 +153,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
name = "psychopath"
|
name = "psychopath"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blue_noise_mask 0.1.0",
|
|
||||||
"clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"float4 0.1.0",
|
"float4 0.1.0",
|
||||||
|
@ -184,34 +171,6 @@ dependencies = [
|
||||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.17"
|
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 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 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 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 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 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"
|
"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 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 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 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 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 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"
|
"checksum rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "684ce48436d6465300c9ea783b6b14c4361d6b8dcbb1375b486a69cc19e2dfb0"
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"sub_crates/blue_noise_mask",
|
|
||||||
"sub_crates/float4",
|
"sub_crates/float4",
|
||||||
"sub_crates/halton",
|
"sub_crates/halton",
|
||||||
"sub_crates/math3d",
|
"sub_crates/math3d",
|
||||||
|
@ -37,9 +36,6 @@ lazy_static = "0.2"
|
||||||
openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" }
|
openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" }
|
||||||
|
|
||||||
# Local crate dependencies
|
# Local crate dependencies
|
||||||
[dependencies.blue_noise_mask]
|
|
||||||
path = "sub_crates/blue_noise_mask"
|
|
||||||
|
|
||||||
[dependencies.float4]
|
[dependencies.float4]
|
||||||
path = "sub_crates/float4"
|
path = "sub_crates/float4"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
extern crate blue_noise_mask;
|
|
||||||
extern crate float4;
|
extern crate float4;
|
||||||
extern crate halton;
|
extern crate halton;
|
||||||
extern crate math3d;
|
extern crate math3d;
|
||||||
|
|
|
@ -8,8 +8,6 @@ use std::sync::{RwLock, Mutex};
|
||||||
use crossbeam::sync::MsQueue;
|
use crossbeam::sync::MsQueue;
|
||||||
use scoped_threadpool::Pool;
|
use scoped_threadpool::Pool;
|
||||||
|
|
||||||
use blue_noise_mask;
|
|
||||||
use blue_noise_mask::{MASKS, NUM_MASKS_WRAP_BITMASK};
|
|
||||||
use halton;
|
use halton;
|
||||||
|
|
||||||
use algorithm::partition_pair;
|
use algorithm::partition_pair;
|
||||||
|
@ -137,19 +135,16 @@ impl<'a> Renderer<'a> {
|
||||||
// Generate light paths and initial rays
|
// Generate light paths and initial rays
|
||||||
for y in bucket.y..(bucket.y + bucket.h) {
|
for y in bucket.y..(bucket.y + bucket.h) {
|
||||||
for x in bucket.x..(bucket.x + bucket.w) {
|
for x in bucket.x..(bucket.x + bucket.w) {
|
||||||
let x = x as u32;
|
let offset = hash_u32(((x as u32) << 16) ^ (y as u32), self.seed);
|
||||||
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);
|
|
||||||
|
|
||||||
for si in 0..self.spp {
|
for si in 0..self.spp {
|
||||||
let si = si as u32;
|
|
||||||
// Calculate image plane x and y coordinates
|
// Calculate image plane x and y coordinates
|
||||||
let (img_x, img_y) = {
|
let (img_x, img_y) = {
|
||||||
let filter_x =
|
let filter_x =
|
||||||
fast_logit(rot_f32(halton::sample(0, si), MASKS[(mask_i + 4) & (MASKS.len() - 1)]), 1.5) + 0.5;
|
fast_logit(halton::sample(4, offset + si as u32), 1.5) +
|
||||||
|
0.5;
|
||||||
let filter_y =
|
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_x = (filter_x + x as f32) * cmpx;
|
||||||
let samp_y = (filter_y + y as f32) * cmpy;
|
let samp_y = (filter_y + y as f32) * cmpy;
|
||||||
((samp_x - 0.5) * x_extent, (0.5 - samp_y) * y_extent)
|
((samp_x - 0.5) * x_extent, (0.5 - samp_y) * y_extent)
|
||||||
|
@ -160,12 +155,14 @@ impl<'a> Renderer<'a> {
|
||||||
LightPath::new(&self.scene,
|
LightPath::new(&self.scene,
|
||||||
(x, y),
|
(x, y),
|
||||||
(img_x, img_y),
|
(img_x, img_y),
|
||||||
(rot_f32(halton::sample(2, si), MASKS[(mask_i + 0) & (MASKS.len() - 1)]),
|
(halton::sample(0, offset + si as u32),
|
||||||
rot_f32(halton::sample(3, si), MASKS[(mask_i + 1) & (MASKS.len() - 1)])),
|
halton::sample(1, offset + si as u32)),
|
||||||
rot_f32(halton::sample(4, si), MASKS[(mask_i + 2) & (MASKS.len() - 1)]),
|
halton::sample(2, offset + si as u32),
|
||||||
map_0_1_to_wavelength(rot_f32(halton::sample(5, si), MASKS[(mask_i + 3) & (MASKS.len() - 1)])),
|
map_0_1_to_wavelength(halton::sample(3,
|
||||||
si,
|
offset +
|
||||||
mask_i as u32);
|
si as
|
||||||
|
u32)),
|
||||||
|
offset + si as u32);
|
||||||
paths.push(path);
|
paths.push(path);
|
||||||
rays.push(ray);
|
rays.push(ray);
|
||||||
}
|
}
|
||||||
|
@ -312,7 +309,6 @@ pub struct LightPath {
|
||||||
pixel_co: (u32, u32),
|
pixel_co: (u32, u32),
|
||||||
lds_offset: u32,
|
lds_offset: u32,
|
||||||
dim_offset: Cell<u32>,
|
dim_offset: Cell<u32>,
|
||||||
mask_offset: Cell<u32>,
|
|
||||||
time: f32,
|
time: f32,
|
||||||
wavelength: f32,
|
wavelength: f32,
|
||||||
|
|
||||||
|
@ -331,8 +327,7 @@ impl LightPath {
|
||||||
lens_uv: (f32, f32),
|
lens_uv: (f32, f32),
|
||||||
time: f32,
|
time: f32,
|
||||||
wavelength: f32,
|
wavelength: f32,
|
||||||
lds_offset: u32,
|
lds_offset: u32)
|
||||||
mask_offset: u32)
|
|
||||||
-> (LightPath, Ray) {
|
-> (LightPath, Ray) {
|
||||||
(LightPath {
|
(LightPath {
|
||||||
event: LightPathEvent::CameraRay,
|
event: LightPathEvent::CameraRay,
|
||||||
|
@ -341,7 +336,6 @@ impl LightPath {
|
||||||
pixel_co: pixel_co,
|
pixel_co: pixel_co,
|
||||||
lds_offset: lds_offset,
|
lds_offset: lds_offset,
|
||||||
dim_offset: Cell::new(6),
|
dim_offset: Cell::new(6),
|
||||||
mask_offset: Cell::new(mask_offset + 6),
|
|
||||||
time: time,
|
time: time,
|
||||||
wavelength: wavelength,
|
wavelength: wavelength,
|
||||||
|
|
||||||
|
@ -361,13 +355,10 @@ impl LightPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_lds_samp(&self) -> f32 {
|
fn next_lds_samp(&self) -> f32 {
|
||||||
let dim = self.dim_offset.get();
|
let s = halton::sample(self.dim_offset.get(), self.lds_offset);
|
||||||
let mask_i = self.mask_offset.get();
|
let inc = self.dim_offset.get() + 1;
|
||||||
self.dim_offset.set(dim + 1);
|
self.dim_offset.set(inc);
|
||||||
self.mask_offset.set((mask_i + 1) & (MASKS.len() - 1) as u32);
|
s
|
||||||
|
|
||||||
let samp = halton::sample(dim, self.lds_offset);
|
|
||||||
rot_f32(samp, unsafe { *MASKS.get_unchecked(mask_i as usize) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self,
|
fn next(&mut self,
|
||||||
|
@ -514,15 +505,3 @@ struct BucketJob {
|
||||||
w: u32,
|
w: u32,
|
||||||
h: 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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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"
|
|
|
@ -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]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"));
|
|
Loading…
Reference in New Issue
Block a user