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.
#[inline(always)]
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
// Stochastic Transparency" by Laine and Karras.
// 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,
// because it ends up being equivalent to Owen scrambling.
//
// Note that the application of the scramble parameter here is equivalent
// to doing random digit scrambling. This is valid because random digit
// scrambling is a strict subset of Owen scrambling, and therefore does
// not invalidate the Owen scrambling itself.
// Note that the application of the scramble parameter here via addition
// does not invalidate the Owen scramble as long as it is done after the
// bit the reversal.
//
// The permutation constants here were selected through an optimization
// process to maximize low-bias avalanche between bits.
n = n.reverse_bits();
n ^= scramble;
let perms = [0x1313e844, 0xa14a177e, 0x18c8e432];
for p in perms.iter() {
n ^= n.wrapping_mul(*p);
n = n.wrapping_add(scramble);
let perms = [0x97b756bc, 0x4b0a8a12, 0x75c77e36];
for &p in perms.iter() {
n ^= n.wrapping_mul(p);
}
n = n.reverse_bits();
// Return the scrambled value, shifted back into place.
n << 16
// Return the scrambled value.
n
}
#[inline(always)]