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