134 lines
4.3 KiB
C
134 lines
4.3 KiB
C
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
/*
|
|
* A shuffled, Owen-scrambled Sobol sampler, implemented with the
|
|
* techniques from the paper "Practical Hash-based Owen Scrambling"
|
|
* by Brent Burley, 2020, Journal of Computer Graphics Techniques.
|
|
*
|
|
* Note that unlike a standard high-dimensional Sobol sequence, this
|
|
* Sobol sampler uses padding to achieve higher dimensions, as described
|
|
* in Burley's paper.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/sample/util.h"
|
|
#include "util/hash.h"
|
|
#include "util/math.h"
|
|
#include "util/types.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/*
|
|
* Computes a single dimension of a sample from an Owen-scrambled
|
|
* Sobol sequence. This is used in the main sampling functions,
|
|
* sobol_burley_sample_#D(), below.
|
|
*
|
|
* - rev_bit_index: the sample index, with reversed order bits.
|
|
* - dimension: the sample dimension.
|
|
* - scramble_seed: the Owen scrambling seed.
|
|
*
|
|
* Note that the seed must be well randomized before being
|
|
* passed to this function.
|
|
*/
|
|
ccl_device_forceinline float sobol_burley(uint rev_bit_index,
|
|
const uint dimension,
|
|
const uint scramble_seed)
|
|
{
|
|
uint result = 0;
|
|
|
|
if (dimension == 0) {
|
|
/* Fast-path for dimension 0, which is just Van der corput.
|
|
* This makes a notable difference in performance since we reuse
|
|
* dimensions for padding, and dimension 0 is reused the most. */
|
|
result = reverse_integer_bits(rev_bit_index);
|
|
}
|
|
else {
|
|
uint i = 0;
|
|
while (rev_bit_index != 0) {
|
|
uint j = count_leading_zeros(rev_bit_index);
|
|
result ^= sobol_burley_table[dimension][i + j];
|
|
i += j + 1;
|
|
|
|
/* We can't do "<<= j + 1" because that can overflow the shift
|
|
* operator, which doesn't do what we need on at least x86. */
|
|
rev_bit_index <<= j;
|
|
rev_bit_index <<= 1;
|
|
}
|
|
}
|
|
|
|
/* Apply Owen scrambling. */
|
|
result = reverse_integer_bits(reversed_bit_owen(result, scramble_seed));
|
|
|
|
return uint_to_float_excl(result);
|
|
}
|
|
|
|
/*
|
|
* Computes a 1D Owen-scrambled and shuffled Sobol sample.
|
|
*/
|
|
ccl_device float sobol_burley_sample_1D(uint index, uint const dimension, uint seed)
|
|
{
|
|
/* Include the dimension in the seed, so we get decorrelated
|
|
* sequences for different dimensions via shuffling. */
|
|
seed ^= hash_hp_uint(dimension);
|
|
|
|
/* Shuffle. */
|
|
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xbff95bfe);
|
|
|
|
return sobol_burley(index, 0, seed ^ 0x635c77bd);
|
|
}
|
|
|
|
/*
|
|
* Computes a 2D Owen-scrambled and shuffled Sobol sample.
|
|
*/
|
|
ccl_device float2 sobol_burley_sample_2D(uint index, const uint dimension_set, uint seed)
|
|
{
|
|
/* Include the dimension set in the seed, so we get decorrelated
|
|
* sequences for different dimension sets via shuffling. */
|
|
seed ^= hash_hp_uint(dimension_set);
|
|
|
|
/* Shuffle. */
|
|
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xf8ade99a);
|
|
|
|
return make_float2(sobol_burley(index, 0, seed ^ 0xe0aaaf76),
|
|
sobol_burley(index, 1, seed ^ 0x94964d4e));
|
|
}
|
|
|
|
/*
|
|
* Computes a 3D Owen-scrambled and shuffled Sobol sample.
|
|
*/
|
|
ccl_device float3 sobol_burley_sample_3D(uint index, const uint dimension_set, uint seed)
|
|
{
|
|
/* Include the dimension set in the seed, so we get decorrelated
|
|
* sequences for different dimension sets via shuffling. */
|
|
seed ^= hash_hp_uint(dimension_set);
|
|
|
|
/* Shuffle. */
|
|
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xcaa726ac);
|
|
|
|
return make_float3(sobol_burley(index, 0, seed ^ 0x9e78e391),
|
|
sobol_burley(index, 1, seed ^ 0x67c33241),
|
|
sobol_burley(index, 2, seed ^ 0x78c395c5));
|
|
}
|
|
|
|
/*
|
|
* Computes a 4D Owen-scrambled and shuffled Sobol sample.
|
|
*/
|
|
ccl_device float4 sobol_burley_sample_4D(uint index, const uint dimension_set, uint seed)
|
|
{
|
|
/* Include the dimension set in the seed, so we get decorrelated
|
|
* sequences for different dimension sets via shuffling. */
|
|
seed ^= hash_hp_uint(dimension_set);
|
|
|
|
/* Shuffle. */
|
|
index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xc2c1a055);
|
|
|
|
return make_float4(sobol_burley(index, 0, seed ^ 0x39468210),
|
|
sobol_burley(index, 1, seed ^ 0xe9d8a845),
|
|
sobol_burley(index, 2, seed ^ 0x5f32b482),
|
|
sobol_burley(index, 3, seed ^ 0x1524cc56));
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|