Implement Sobol sampler that does both Owen and Cranley-Patterson.

This seems to work well in practice, and only takes one more addition
operation.
This commit is contained in:
Nathan Vegdahl 2020-03-17 20:00:09 +09:00
parent e3152e6f9c
commit de5a643a2a
2 changed files with 51 additions and 27 deletions

View File

@ -709,7 +709,10 @@ fn get_sample(dimension: u32, i: u32, pixel_co: (u32, u32), seed: u32) -> f32 {
n if (n - 1) < sobol::MAX_DIMENSION as u32 => { n if (n - 1) < sobol::MAX_DIMENSION as u32 => {
let dim = n - 1; let dim = n - 1;
// Sobol sampling. // Sobol sampling.
sobol::sample_owen(dim, i, hash_u32(dim, scramble)) // We skip the first 32 samples because doing so reduces noise
// in some areas when rendering at 64 spp. Not sure why, but it
// works.
sobol::sample_owen_cranley(dim, i + 32, hash_u32(dim, scramble))
} }
_ => { _ => {
// Random sampling. // Random sampling.

View File

@ -48,9 +48,52 @@ pub fn sample_cranley(dimension: u32, index: u32, scramble: u32) -> f32 {
/// works well. /// works well.
#[inline] #[inline]
pub fn sample_owen(dimension: u32, index: u32, scramble: u32) -> f32 { pub fn sample_owen(dimension: u32, index: u32, scramble: u32) -> f32 {
// Get the sobol point. u32_to_0_1_f32(owen_scramble_u32(sobol_u32(dimension, index), scramble))
let mut n = sobol_u32(dimension, index); }
/// Same as `sample()` except applies both Owen scrambling and
/// Cranley-Patterson rotation using the given scramble parameter.
///
/// For the technically curious: this first does Owen scrambling, and then
/// Cranley-Patterson. If it were done the other way around it would
/// invalidate the Owen scrambling.
///
/// To get proper scrambling and rotation, you need to use a different scramble
/// value for each dimension, and those values should be generated more-or-less
/// randomly. For example, using a 32-bit hash of the dimension parameter
/// works well.
#[inline]
pub fn sample_owen_cranley(dimension: u32, index: u32, scramble: u32) -> f32 {
// Reusing the same scramble parameter for both the Owen scrambling and
// the Cranely-Patterson rotation actually works fine, because the Owen
// scrambling is implemented as a sort of hash, so they don't end up being
// correlated.
u32_to_0_1_f32(owen_scramble_u32(sobol_u32(dimension, index), scramble).wrapping_add(scramble))
}
//----------------------------------------------------------------------
/// The actual core Sobol samplng code. Used by the other functions.
#[inline(always)]
fn sobol_u32(dimension: u32, mut index: u32) -> u32 {
assert!(dimension < MAX_DIMENSION);
let vecs = &VECTORS[dimension as usize];
let mut result = 0;
let mut i = 0;
while index != 0 {
let j = index.trailing_zeros();
result ^= vecs[(i + j) as usize];
i += j + 1;
index >>= j + 1;
}
result
}
/// Scrambles `n` using Owen scrambling and the given scramble parameter.
#[inline(always)]
fn owen_scramble_u32(mut n: u32, scramble: u32) -> u32 {
// We don't need the lowest 8 bits because we're converting to an f32 at // We don't need the lowest 8 bits because we're converting to an f32 at
// the end which only has 24 bits of precision anyway. And doing this // the end which only has 24 bits of precision anyway. And doing this
// allows the seed to affect the mixing of the higher bits to make them // allows the seed to affect the mixing of the higher bits to make them
@ -88,30 +131,8 @@ pub fn sample_owen(dimension: u32, index: u32, scramble: u32) -> f32 {
} }
n = n.reverse_bits(); n = n.reverse_bits();
// Shift back into place. // Return the scrambled value, shifted back into place.
n <<= 8; n << 8
u32_to_0_1_f32(n)
}
//----------------------------------------------------------------------
/// The actual core Sobol samplng code. Used by the other functions.
#[inline(always)]
fn sobol_u32(dimension: u32, mut index: u32) -> u32 {
assert!(dimension < MAX_DIMENSION);
let vecs = &VECTORS[dimension as usize];
let mut result = 0;
let mut i = 0;
while index != 0 {
let j = index.trailing_zeros();
result ^= vecs[(i + j) as usize];
i += j + 1;
index >>= j + 1;
}
result
} }
#[inline(always)] #[inline(always)]