Reworked Sobol sampler implementation.

This produces identical results, but generates the direction
vectors from the original sources at build time.  This makes
the source code quite a bit leaner, and will also make it easier
to play with other direction vectors in the future if the
opportunity arises.
This commit is contained in:
Nathan Vegdahl 2020-03-15 22:01:06 +09:00
parent 42a6c1e9cd
commit 047e66d9aa
5 changed files with 1172 additions and 53318 deletions

View File

@ -704,10 +704,10 @@ fn get_sample(dimension: u32, i: u32, pixel_co: (u32, u32), seed: u32) -> f32 {
let n = i.wrapping_add(scramble).wrapping_mul(2654435769); let n = i.wrapping_add(scramble).wrapping_mul(2654435769);
n as f32 * (1.0 / (1u64 << 32) as f32) n as f32 * (1.0 / (1u64 << 32) as f32)
} }
n if (n - 1) < sobol::NUM_DIMENSIONS as u32 => { n if (n - 1) < sobol::MAX_DIMENSION as u32 => {
// Sobol sampling. // Sobol sampling.
let scramble = hash_u32(pixel_id, seed); let scramble = hash_u32(pixel_id, seed);
sobol::sample_owen_scramble(dimension - 1, i, hash_u32(dimension, scramble)) sobol::sample_owen(dimension - 1, i, hash_u32(dimension, scramble))
} }
_ => { _ => {
// Random sampling. // Random sampling.

View File

@ -4,6 +4,7 @@ version = "0.1.0"
authors = ["Nathan Vegdahl <cessen@cessen.com>"] authors = ["Nathan Vegdahl <cessen@cessen.com>"]
edition = "2018" edition = "2018"
license = "MIT" license = "MIT"
build = "build.rs"
[lib] [lib]
name = "sobol" name = "sobol"

1157
sub_crates/sobol/build.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +1,10 @@
// Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org) /// An implementation of the Sobol low discrepancy sequence.
// ///
// Permission is hereby granted, free of charge, to any person obtaining a copy /// Includes variants with random digit scrambling and Owen scrambling.
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Adapted to Rust by Nathan Vegdahl (2017). // The following `include` provides `MAX_DIMENSION` and `VECTORS`.
// Owen scrambling implementation also by Nathan Vegdahl (2020). // See the build.rs file for how this included file is generated.
include!(concat!(env!("OUT_DIR"), "/vectors.inc"));
mod matrices;
pub use crate::matrices::NUM_DIMENSIONS;
use crate::matrices::{MATRICES, SIZE};
/// Compute one component of one sample from the Sobol'-sequence, where /// Compute one component of one sample from the Sobol'-sequence, where
/// `dimension` specifies the component and `index` specifies the sample /// `dimension` specifies the component and `index` specifies the sample
@ -42,7 +22,7 @@ pub fn sample(dimension: u32, index: u32) -> f32 {
/// randomly. For example, using a 32-bit hash of the dimension parameter /// randomly. For example, using a 32-bit hash of the dimension parameter
/// works well. /// works well.
#[inline] #[inline]
pub fn sample_rd_scramble(dimension: u32, index: u32, scramble: u32) -> f32 { pub fn sample_rd(dimension: u32, index: u32, scramble: u32) -> f32 {
u32_to_0_1_f32(sobol_u32(dimension, index) ^ scramble) u32_to_0_1_f32(sobol_u32(dimension, index) ^ scramble)
} }
@ -54,7 +34,7 @@ pub fn sample_rd_scramble(dimension: u32, index: u32, scramble: u32) -> f32 {
/// randomly. For example, using a 32-bit hash of the dimension parameter /// randomly. For example, using a 32-bit hash of the dimension parameter
/// works well. /// works well.
#[inline] #[inline]
pub fn sample_owen_scramble(dimension: u32, index: u32, scramble: u32) -> f32 { pub fn sample_owen(dimension: u32, index: u32, scramble: u32) -> f32 {
// Get the sobol point. // Get the sobol point.
let mut n = sobol_u32(dimension, index); let mut n = sobol_u32(dimension, index);
@ -95,13 +75,14 @@ pub fn sample_owen_scramble(dimension: u32, index: u32, scramble: u32) -> f32 {
/// The actual core Sobol samplng code. Used by the other functions. /// The actual core Sobol samplng code. Used by the other functions.
#[inline(always)] #[inline(always)]
fn sobol_u32(dimension: u32, mut index: u32) -> u32 { fn sobol_u32(dimension: u32, mut index: u32) -> u32 {
assert!((dimension as usize) < NUM_DIMENSIONS); assert!(dimension < MAX_DIMENSION);
let vecs = &VECTORS[dimension as usize];
let mut result = 0; let mut result = 0;
let mut i = dimension * SIZE as u32; let mut i = 0;
while index != 0 { while index != 0 {
let j = index.trailing_zeros(); let j = index.trailing_zeros();
result ^= MATRICES[(i + j) as usize]; result ^= vecs[(i + j) as usize];
i += j + 1; i += j + 1;
index >>= j + 1; index >>= j + 1;
} }

File diff suppressed because it is too large Load Diff