Improve Owen scrambling by seeding with add instead of xor.

Also removed some unnecessary complexity from the implementation,
and use different constants.
This commit is contained in:
Nathan Vegdahl 2020-04-17 10:42:35 +09:00
parent 8deb305850
commit c4e1bedd43

View File

@ -111,14 +111,6 @@ fn sobol_u32(dimension: u32, index: u32) -> u32 {
/// Scrambles `n` using Owen scrambling and the given scramble parameter. /// Scrambles `n` using Owen scrambling and the given scramble parameter.
#[inline(always)] #[inline(always)]
fn owen_scramble_u32(mut n: u32, scramble: u32) -> u32 { fn owen_scramble_u32(mut n: u32, scramble: u32) -> u32 {
// The lower 16 bits aren't generated by our sobol sampler anyway,
// and shifting them out allows the seed to better affect the mixing
// of the higher bits in a more randomized way, which improves the
// scrambling.
n >>= 16;
// Do Owen scrambling.
//
// This uses the technique presented in the paper "Stratified Sampling for // This uses the technique presented in the paper "Stratified Sampling for
// Stochastic Transparency" by Laine and Karras. // Stochastic Transparency" by Laine and Karras.
// The basic idea is that we're running a special kind of hash function // The basic idea is that we're running a special kind of hash function
@ -132,23 +124,23 @@ fn owen_scramble_u32(mut n: u32, scramble: u32) -> u32 {
// But in this case that only-downward behavior is exactly what we want, // But in this case that only-downward behavior is exactly what we want,
// because it ends up being equivalent to Owen scrambling. // because it ends up being equivalent to Owen scrambling.
// //
// Note that the application of the scramble parameter here is equivalent // Note that the application of the scramble parameter here via addition
// to doing random digit scrambling. This is valid because random digit // does not invalidate the Owen scramble as long as it is done after the
// scrambling is a strict subset of Owen scrambling, and therefore does // bit the reversal.
// not invalidate the Owen scrambling itself.
// //
// The permutation constants here were selected through an optimization // The permutation constants here were selected through an optimization
// process to maximize low-bias avalanche between bits. // process to maximize low-bias avalanche between bits.
n = n.reverse_bits(); n = n.reverse_bits();
n ^= scramble; n = n.wrapping_add(scramble);
let perms = [0x1313e844, 0xa14a177e, 0x18c8e432]; let perms = [0x97b756bc, 0x4b0a8a12, 0x75c77e36];
for p in perms.iter() { for &p in perms.iter() {
n ^= n.wrapping_mul(*p); n ^= n.wrapping_mul(p);
} }
n = n.reverse_bits(); n = n.reverse_bits();
// Return the scrambled value, shifted back into place. // Return the scrambled value.
n << 16 n
} }
#[inline(always)] #[inline(always)]