Blender V4.3
sobol_burley.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5/*
6 * A shuffled, Owen-scrambled Sobol sampler, implemented with the
7 * techniques from the paper "Practical Hash-based Owen Scrambling"
8 * by Brent Burley, 2020, Journal of Computer Graphics Techniques.
9 *
10 * Note that unlike a standard high-dimensional Sobol sequence, this
11 * Sobol sampler uses padding to achieve higher dimensions, as described
12 * in Burley's paper.
13 */
14
15#pragma once
16
17#include "kernel/sample/util.h"
18#include "util/hash.h"
19#include "util/math.h"
20#include "util/types.h"
21
23
24/*
25 * Computes a single dimension of a sample from an Owen-scrambled
26 * Sobol sequence. This is used in the main sampling functions,
27 * sobol_burley_sample_#D(), below.
28 *
29 * - rev_bit_index: the sample index, with reversed order bits.
30 * - dimension: the sample dimension.
31 * - scramble_seed: the Owen scrambling seed.
32 *
33 * Note that the seed must be well randomized before being
34 * passed to this function.
35 */
37 const uint dimension,
38 const uint scramble_seed)
39{
40 uint result = 0;
41
42 if (dimension == 0) {
43 /* Fast-path for dimension 0, which is just Van der corput.
44 * This makes a notable difference in performance since we reuse
45 * dimensions for padding, and dimension 0 is reused the most. */
46 result = reverse_integer_bits(rev_bit_index);
47 }
48 else {
49 uint i = 0;
50 while (rev_bit_index != 0) {
51 uint j = count_leading_zeros(rev_bit_index);
52 result ^= sobol_burley_table[dimension][i + j];
53 i += j + 1;
54
55 /* We can't do "<<= j + 1" because that can overflow the shift
56 * operator, which doesn't do what we need on at least x86. */
57 rev_bit_index <<= j;
58 rev_bit_index <<= 1;
59 }
60 }
61
62 /* Apply Owen scrambling. */
63 result = reverse_integer_bits(reversed_bit_owen(result, scramble_seed));
64
65 return uint_to_float_excl(result);
66}
67
68/*
69 * NOTE: the functions below intentionally produce samples that are
70 * uncorrelated between functions. For example, a 1D sample and 2D
71 * sample produced with the same index, dimension, and seed are
72 * uncorrelated with each other. This allows more care-free usage
73 * of the functions together, without having to worry about
74 * e.g. 1D and 2D samples being accidentally correlated with each
75 * other.
76 */
77
78/*
79 * Computes a 1D Owen-scrambled and shuffled Sobol sample.
80 *
81 * `index` is the index of the sample in the sequence.
82 *
83 * `dimension` is which dimensions of the sample you want to fetch. Note
84 * that different 1D dimensions are uncorrelated. For samples with > 1D
85 * stratification, use the multi-dimensional sampling methods below.
86 *
87 * `seed`: different seeds produce statistically independent,
88 * uncorrelated sequences.
89 *
90 * `shuffled_index_mask` limits the sample sequence length, improving
91 * performance. It must be a string of binary 1 bits followed by a
92 * string of binary 0 bits (e.g. 0xffff0000) for the sampler to operate
93 * correctly. In general, `reverse_integer_bits(shuffled_index_mask)`
94 * should be >= the maximum number of samples expected to be taken. A safe
95 * default (but least performant) is 0xffffffff, for maximum sequence
96 * length.
97 */
99 uint const dimension,
100 uint seed,
101 uint shuffled_index_mask)
102{
103 /* Include the dimension in the seed, so we get decorrelated
104 * sequences for different dimensions via shuffling. */
105 seed ^= hash_hp_uint(dimension);
106
107 /* Shuffle and mask. The masking is just for better
108 * performance at low sample counts. */
109 index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xbff95bfe);
110 index &= shuffled_index_mask;
111
112 return sobol_burley(index, 0, seed ^ 0x635c77bd);
113}
114
115/*
116 * Computes a 2D Owen-scrambled and shuffled Sobol sample.
117 *
118 * `dimension_set` is which two dimensions of the sample you want to
119 * fetch. For example, 0 is the first two, 1 is the second two, etc.
120 * The dimensions within a single set are stratified, but different sets
121 * are uncorrelated.
122 *
123 * See sobol_burley_sample_1D for further usage details.
124 */
126 const uint dimension_set,
127 uint seed,
128 uint shuffled_index_mask)
129{
130 /* Include the dimension set in the seed, so we get decorrelated
131 * sequences for different dimension sets via shuffling. */
132 seed ^= hash_hp_uint(dimension_set);
133
134 /* Shuffle and mask. The masking is just for better
135 * performance at low sample counts. */
136 index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xf8ade99a);
137 index &= shuffled_index_mask;
138
139 return make_float2(sobol_burley(index, 0, seed ^ 0xe0aaaf76),
140 sobol_burley(index, 1, seed ^ 0x94964d4e));
141}
142
143/*
144 * Computes a 3D Owen-scrambled and shuffled Sobol sample.
145 *
146 * `dimension_set` is which three dimensions of the sample you want to
147 * fetch. For example, 0 is the first three, 1 is the second three, etc.
148 * The dimensions within a single set are stratified, but different sets
149 * are uncorrelated.
150 *
151 * See sobol_burley_sample_1D for further usage details.
152 */
154 const uint dimension_set,
155 uint seed,
156 uint shuffled_index_mask)
157{
158 /* Include the dimension set in the seed, so we get decorrelated
159 * sequences for different dimension sets via shuffling. */
160 seed ^= hash_hp_uint(dimension_set);
161
162 /* Shuffle and mask. The masking is just for better
163 * performance at low sample counts. */
164 index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xcaa726ac);
165 index &= shuffled_index_mask;
166
167 return make_float3(sobol_burley(index, 0, seed ^ 0x9e78e391),
168 sobol_burley(index, 1, seed ^ 0x67c33241),
169 sobol_burley(index, 2, seed ^ 0x78c395c5));
170}
171
172/*
173 * Computes a 4D Owen-scrambled and shuffled Sobol sample.
174 *
175 * `dimension_set` is which four dimensions of the sample you want to
176 * fetch. For example, 0 is the first four, 1 is the second four, etc.
177 * The dimensions within a single set are stratified, but different sets
178 * are uncorrelated.
179 *
180 * See sobol_burley_sample_1D for further usage details.
181 */
183 const uint dimension_set,
184 uint seed,
185 uint shuffled_index_mask)
186{
187 /* Include the dimension set in the seed, so we get decorrelated
188 * sequences for different dimension sets via shuffling. */
189 seed ^= hash_hp_uint(dimension_set);
190
191 /* Shuffle and mask. The masking is just for better
192 * performance at low sample counts. */
193 index = reversed_bit_owen(reverse_integer_bits(index), seed ^ 0xc2c1a055);
194 index &= shuffled_index_mask;
195
196 return make_float4(sobol_burley(index, 0, seed ^ 0x39468210),
197 sobol_burley(index, 1, seed ^ 0xe9d8a845),
198 sobol_burley(index, 2, seed ^ 0x5f32b482),
199 sobol_burley(index, 3, seed ^ 0x1524cc56));
200}
201
unsigned int uint
static unsigned long seed
Definition btSoftBody.h:39
CCL_NAMESPACE_BEGIN ccl_device_inline uint reversed_bit_owen(uint n, uint seed)
#define ccl_device_forceinline
#define ccl_device
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device_forceinline float2 make_float2(const float x, const float y)
CCL_NAMESPACE_BEGIN ccl_device_forceinline float uint_to_float_excl(uint n)
Definition hash.h:14
ccl_device_inline uint hash_hp_uint(uint i)
Definition hash.h:406
ccl_inline_constant unsigned int sobol_burley_table[4][32]
CCL_NAMESPACE_BEGIN ccl_device_forceinline float sobol_burley(uint rev_bit_index, const uint dimension, const uint scramble_seed)
ccl_device float sobol_burley_sample_1D(uint index, uint const dimension, uint seed, uint shuffled_index_mask)
ccl_device float2 sobol_burley_sample_2D(uint index, const uint dimension_set, uint seed, uint shuffled_index_mask)
ccl_device float4 sobol_burley_sample_4D(uint index, const uint dimension_set, uint seed, uint shuffled_index_mask)
ccl_device float3 sobol_burley_sample_3D(uint index, const uint dimension_set, uint seed, uint shuffled_index_mask)
ccl_device_inline uint count_leading_zeros(uint x)
Definition util/math.h:874
ccl_device_inline uint32_t reverse_integer_bits(uint32_t x)
Definition util/math.h:1016