Update Owen scramble hash to the latest.

From https://psychopath.io/post/2021_01_30_building_a_better_lk_hash
This commit is contained in:
Nathan Vegdahl 2021-05-08 12:22:56 -07:00
parent b337e2cb20
commit 70fba19361

View File

@ -1,9 +1,10 @@
//! A seedable, Owen-scrambled Sobol sequence. //! A seedable, Owen-scrambled Sobol sequence.
//! //!
//! This is based on the paper "Practical Hash-based Owen Scrambling" //! This is based on the paper "Practical Hash-based Owen Scrambling"
//! by Brent Burley, but with a novel scramble function in place of the //! by Brent Burley, but using the scramble function from
//! Laine-Karras function used in the paper, and with a larger set of direction //! https://psychopath.io/post/2021_01_30_building_a_better_lk_hash
//! numbers due to Kuo et al. //! in place of the Laine-Karras function used in the paper, and with a
//! larger set of direction numbers due to Kuo et al.
//! //!
//! This implementation is limited to `2^16` samples, and will loop back //! This implementation is limited to `2^16` samples, and will loop back
//! to the start of the sequence after that limit. //! to the start of the sequence after that limit.
@ -36,7 +37,7 @@ pub fn sample_4d(sample_index: u32, dimension_set: u32, seed: u32) -> [f32; 4] {
// Shuffle the index using the given seed to produce a unique statistically // Shuffle the index using the given seed to produce a unique statistically
// independent Sobol sequence. // independent Sobol sequence.
let shuffled_rev_index = lk_scramble(sample_index.reverse_bits(), seed); let shuffled_rev_index = scramble(sample_index.reverse_bits(), seed);
// Compute the Sobol sample with reversed bits. // Compute the Sobol sample with reversed bits.
let mut sobol_rev = Int4::zero(); let mut sobol_rev = Int4::zero();
@ -51,7 +52,7 @@ pub fn sample_4d(sample_index: u32, dimension_set: u32, seed: u32) -> [f32; 4] {
} }
// Do Owen scrambling on the reversed-bits Sobol sample. // Do Owen scrambling on the reversed-bits Sobol sample.
let sobol_owen_rev = lk_scramble_int4(sobol_rev, dimension_set ^ seed); let sobol_owen_rev = scramble_int4(sobol_rev, dimension_set ^ seed);
// Un-reverse the bits and convert to floating point in [0, 1). // Un-reverse the bits and convert to floating point in [0, 1).
sobol_owen_rev.reverse_bits().to_norm_floats() sobol_owen_rev.reverse_bits().to_norm_floats()
@ -59,30 +60,33 @@ pub fn sample_4d(sample_index: u32, dimension_set: u32, seed: u32) -> [f32; 4] {
//---------------------------------------------------------------------- //----------------------------------------------------------------------
/// Scrambles `n` using a novel variation on the Laine-Karras hash. /// Scrambles `n` using the hash function from
/// https://psychopath.io/post/2021_01_30_building_a_better_lk_hash
/// ///
/// This is equivalent to Owen scrambling, but on reversed bits. /// This is equivalent to Owen scrambling, but on reversed bits.
#[inline(always)] #[inline(always)]
fn lk_scramble(mut n: u32, scramble: u32) -> u32 { fn scramble(mut n: u32, scramble: u32) -> u32 {
let scramble = hash(scramble); let scramble = hash(scramble);
n = n.wrapping_add(n << 2); n ^= n.wrapping_mul(0x3d20adea);
n ^= n.wrapping_mul(0xfe9b5742);
n = n.wrapping_add(scramble); n = n.wrapping_add(scramble);
n = n.wrapping_mul((scramble >> 16) | 1); n = n.wrapping_mul((scramble >> 16) | 1);
n ^= n.wrapping_mul(0x05526c56);
n ^= n.wrapping_mul(0x53a22864);
n n
} }
/// Same as `lk_scramble()`, except does it on 4 integers at a time. /// Same as `scramble()`, except does it on 4 integers at a time.
#[inline(always)] #[inline(always)]
fn lk_scramble_int4(mut n: Int4, scramble: u32) -> Int4 { fn scramble_int4(mut n: Int4, scramble: u32) -> Int4 {
let scramble = hash_int4([scramble; 4].into()); let scramble = hash_int4([scramble; 4].into());
n += n << 2; n ^= n * [0x3d20adea; 4].into();
n ^= n * [0xfe9b5742; 4].into();
n += scramble; n += scramble;
n *= (scramble >> 16) | [1; 4].into(); n *= (scramble >> 16) | [1; 4].into();
n ^= n * [0x05526c56; 4].into();
n ^= n * [0x53a22864; 4].into();
n n
} }