diff options
Diffstat (limited to 'intern/cycles/kernel/sample/pattern.h')
-rw-r--r-- | intern/cycles/kernel/sample/pattern.h | 122 |
1 files changed, 41 insertions, 81 deletions
diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h index 89500d51872..e12f333b3a5 100644 --- a/intern/cycles/kernel/sample/pattern.h +++ b/intern/cycles/kernel/sample/pattern.h @@ -4,6 +4,7 @@ #pragma once #include "kernel/sample/jitter.h" +#include "kernel/sample/sobol_burley.h" #include "util/hash.h" CCL_NAMESPACE_BEGIN @@ -12,33 +13,6 @@ CCL_NAMESPACE_BEGIN * this single threaded on a CPU for repeatable results. */ //#define __DEBUG_CORRELATION__ -/* High Dimensional Sobol. - * - * Multidimensional sobol with generator matrices. Dimension 0 and 1 are equal - * to classic Van der Corput and Sobol sequences. */ - -#ifdef __SOBOL__ - -/* Skip initial numbers that for some dimensions have clear patterns that - * don't cover the entire sample space. Ideally we would have a better - * progressive pattern that doesn't suffer from this problem, because even - * with this offset some dimensions are quite poor. - */ -# define SOBOL_SKIP 64 - -ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension) -{ - uint result = 0; - uint i = index + SOBOL_SKIP; - for (int j = 0, x; (x = find_first_set(i)); i >>= x) { - j += x; - result ^= __float_as_uint(kernel_data_fetch(sample_pattern_lut, 32 * dimension + j - 1)); - } - return result; -} - -#endif /* __SOBOL__ */ - ccl_device_forceinline float path_rng_1D(KernelGlobals kg, uint rng_hash, int sample, @@ -48,58 +22,29 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals kg, return (float)drand48(); #endif -#ifdef __SOBOL__ - if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) -#endif - { + if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) { + return sobol_burley_sample_1D(sample, dimension, rng_hash); + } + else { return pmj_sample_1D(kg, sample, rng_hash, dimension); } - -#ifdef __SOBOL__ - /* Sobol sequence value using direction vectors. */ - uint result = sobol_dimension(kg, sample, dimension); - float r = (float)result * (1.0f / (float)0xFFFFFFFF); - - /* Cranly-Patterson rotation using rng seed */ - float shift; - - /* Hash rng with dimension to solve correlation issues. - * See T38710, T50116. - */ - uint tmp_rng = cmj_hash_simple(dimension, rng_hash); - shift = tmp_rng * (kernel_data.integrator.scrambling_distance / (float)0xFFFFFFFF); - - return r + shift - floorf(r + shift); -#endif } -ccl_device_forceinline void path_rng_2D(KernelGlobals kg, - uint rng_hash, - int sample, - int dimension, - ccl_private float *fx, - ccl_private float *fy) +ccl_device_forceinline float2 path_rng_2D(KernelGlobals kg, + uint rng_hash, + int sample, + int dimension) { #ifdef __DEBUG_CORRELATION__ - *fx = (float)drand48(); - *fy = (float)drand48(); - return; -#endif - -#ifdef __SOBOL__ - if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) + return make_float2((float)drand48(), (float)drand48()); #endif - { - pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy); - return; + if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_SOBOL_BURLEY) { + return sobol_burley_sample_2D(sample, dimension, rng_hash); + } + else { + return pmj_sample_2D(kg, sample, rng_hash, dimension); } - -#ifdef __SOBOL__ - /* Sobol. */ - *fx = path_rng_1D(kg, rng_hash, sample, dimension); - *fy = path_rng_1D(kg, rng_hash, sample, dimension + 1); -#endif } /** @@ -145,18 +90,33 @@ ccl_device_inline uint path_rng_hash_init(KernelGlobals kg, return rng_hash; } -ccl_device_inline bool sample_is_even(int pattern, int sample) +/** + * Splits samples into two different classes, A and B, which can be + * compared for variance estimation. + */ +ccl_device_inline bool sample_is_class_A(int pattern, int sample) { - if (pattern == SAMPLING_PATTERN_PMJ) { - /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al. - * We can use this to get divide sample sequence into two classes for easier variance - * estimation. */ - return popcount(uint(sample) & 0xaaaaaaaa) & 1; - } - else { - /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */ - return sample & 0x1; +#if 0 + if (!(pattern == SAMPLING_PATTERN_PMJ || pattern == SAMPLING_PATTERN_SOBOL_BURLEY)) { + /* Fallback: assign samples randomly. + * This is guaranteed to work "okay" for any sampler, but isn't good. + * (NOTE: the seed constant is just a random number to guard against + * possible interactions with other uses of the hash. There's nothing + * special about it.) + */ + return hash_hp_seeded_uint(sample, 0xa771f873) & 1; } -} +#else + (void)pattern; +#endif + /* This follows the approach from section 10.2.1 of "Progressive + * Multi-Jittered Sample Sequences" by Christensen et al., but + * implemented with efficient bit-fiddling. + * + * This approach also turns out to work equally well with Sobol-Burley + * (see https://developer.blender.org/D15746#429471). + */ + return popcount(uint(sample) & 0xaaaaaaaa) & 1; +} CCL_NAMESPACE_END |