/// Performs a base-2 Owen scramble on an integer. pub fn owen2(n: u32, seed: u32) -> u32 { // Multiply by a large random prime and xor by a random number. // This is to ensure that the seed doesn't behave poorly with // e.g. incrementing parameters, and also that zero doesn't // map to zero in the hash function. let seed = seed.wrapping_mul(0xe8559dcb) ^ 0x372fcdb9; let mut result = n; for i in 0..32 { let mask = (!0 << 1) << i; // Two shifts to avoid undefined overflow. result ^= hash((n & mask) ^ seed) & (1 << i); } result } /// Performs a base-4 Owen scramble on an integer. /// /// This is motivated by z-scrambling from the paper "Screen-Space /// Blue-Noise Diffusion of Monte Carlo Sampling Error via Hierarchical /// Ordering of Pixels" by Ahmed et al. Their scrambling function is /// actually just Owen scrambling in base 4, but their attempt at /// implementing that function isn't great, both in terms of memory /// usage and scramble quality. (The paper itself is otherwise /// fantastic, though.) /// /// The implementation below is a full proper base-4 Owen scramble, /// requiring only a 24-byte lookup table. pub fn owen4(n: u32, seed: u32) -> u32 { // Bit-packed permutation table. const PERMUTATION_TABLE: [u8; 24] = [ 0 | (1 << 2) | (2 << 4) | (3 << 6), // [0, 1, 2, 3], 0 | (1 << 2) | (3 << 4) | (2 << 6), // [0, 1, 3, 2], 0 | (2 << 2) | (1 << 4) | (3 << 6), // [0, 2, 1, 3], 0 | (2 << 2) | (3 << 4) | (1 << 6), // [0, 2, 3, 1], 0 | (3 << 2) | (1 << 4) | (2 << 6), // [0, 3, 1, 2], 0 | (3 << 2) | (2 << 4) | (1 << 6), // [0, 3, 2, 1], 1 | (0 << 2) | (2 << 4) | (3 << 6), // [1, 0, 2, 3], 1 | (0 << 2) | (3 << 4) | (2 << 6), // [1, 0, 3, 2], 1 | (2 << 2) | (0 << 4) | (3 << 6), // [1, 2, 0, 3], 1 | (2 << 2) | (3 << 4) | (0 << 6), // [1, 2, 3, 0], 1 | (3 << 2) | (0 << 4) | (2 << 6), // [1, 3, 0, 2], 1 | (3 << 2) | (2 << 4) | (0 << 6), // [1, 3, 2, 0], 2 | (0 << 2) | (1 << 4) | (3 << 6), // [2, 0, 1, 3], 2 | (0 << 2) | (3 << 4) | (1 << 6), // [2, 0, 3, 1], 2 | (1 << 2) | (0 << 4) | (3 << 6), // [2, 1, 0, 3], 2 | (1 << 2) | (3 << 4) | (0 << 6), // [2, 1, 3, 0], 2 | (3 << 2) | (0 << 4) | (1 << 6), // [2, 3, 0, 1], 2 | (3 << 2) | (1 << 4) | (0 << 6), // [2, 3, 1, 0], 3 | (0 << 2) | (1 << 4) | (2 << 6), // [3, 0, 1, 2], 3 | (0 << 2) | (2 << 4) | (1 << 6), // [3, 0, 2, 1], 3 | (1 << 2) | (0 << 4) | (2 << 6), // [3, 1, 0, 2], 3 | (1 << 2) | (2 << 4) | (0 << 6), // [3, 1, 2, 0], 3 | (2 << 2) | (0 << 4) | (1 << 6), // [3, 2, 0, 1], 3 | (2 << 2) | (1 << 4) | (0 << 6), // [3, 2, 1, 0], ]; // Multiply by a large random prime and xor by a random number. // This is to ensure that the seed doesn't behave poorly with // e.g. incrementing parameters, and also that zero doesn't // map to zero in the hash function. let seed = seed.wrapping_mul(0xe8559dcb) ^ 0x372fcdb9; let mut result = 0; for i in 0..16 { let mask = (!0 << 2) << (i * 2); // Two shifts to avoid undefined overflow. let perm_entry = PERMUTATION_TABLE[ // The xor with `i` is to ensure runs of zeros in `n` still // result in different shuffles on each iteration. `i` is // shifted to avoid interacting poorly with an incrementing // `n`. (hash((n & mask) ^ seed ^ (i << 16)) % 24) as usize ]; let perm_cell_idx = ((n >> (i * 2)) & 0b11) as usize; result |= (((perm_entry >> (perm_cell_idx * 2)) & 0b11) as u32) << (i * 2); } result } //------------------------------------------------------------- /// Fast bit-mixing hash for use in the functions above. #[inline(always)] pub fn hash(mut n: u32) -> u32 { // From https://github.com/skeeto/hash-prospector n ^= n >> 16; n = n.wrapping_mul(0x21f0aaad); n ^= n >> 15; n = n.wrapping_mul(0xd35a2d97); n ^= n >> 15; n }