From 49ca810bf302fdf48e37527d1f8d160fcbd958d2 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Fri, 2 Sep 2022 17:32:34 +0200 Subject: Cycles: enable adaptive sampling for Sobol-Burley This uses the same sample classification approach as used for PMJ, because it turns out to also work equally well with Sobol-Burley. This also implements a fallback (random classification) that should work "okay" for other samplers, though there are no other samplers at the moment. Differential Revision: https://developer.blender.org/D15845 --- intern/cycles/blender/addon/ui.py | 1 - intern/cycles/kernel/film/light_passes.h | 10 ++++----- intern/cycles/kernel/sample/pattern.h | 35 ++++++++++++++++++++++---------- intern/cycles/scene/integrator.cpp | 4 +--- 4 files changed, 30 insertions(+), 20 deletions(-) (limited to 'intern') diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 37fecec771b..ee284dd899a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -296,7 +296,6 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): row.prop(cscene, "use_animated_seed", text="", icon='TIME') col = layout.column(align=True) - col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling) col.prop(cscene, "sampling_pattern", text="Pattern") col = layout.column(align=True) diff --git a/intern/cycles/kernel/film/light_passes.h b/intern/cycles/kernel/film/light_passes.h index 5c306e8f088..b45b5305119 100644 --- a/intern/cycles/kernel/film/light_passes.h +++ b/intern/cycles/kernel/film/light_passes.h @@ -147,16 +147,16 @@ ccl_device void film_write_adaptive_buffer(KernelGlobals kg, const Spectrum contribution, ccl_global float *ccl_restrict buffer) { - /* Adaptive Sampling. Fill the additional buffer with the odd samples and calculate our stopping - * criteria. This is the heuristic from "A hierarchical automatic stopping condition for Monte - * Carlo global illumination" except that here it is applied per pixel and not in hierarchical - * tiles. */ + /* Adaptive Sampling. Fill the additional buffer with only one half of the samples and + * calculate our stopping criteria. This is the heuristic from "A hierarchical automatic + * stopping condition for Monte Carlo global illumination" except that here it is applied + * per pixel and not in hierarchical tiles. */ if (kernel_data.film.pass_adaptive_aux_buffer == PASS_UNUSED) { return; } - if (sample_is_even(kernel_data.integrator.sampling_pattern, sample)) { + if (sample_is_class_A(kernel_data.integrator.sampling_pattern, sample)) { const float3 contribution_rgb = spectrum_to_rgb(contribution); film_write_pass_float4(buffer + kernel_data.film.pass_adaptive_aux_buffer, diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h index 6477e29fa40..fa48cc216af 100644 --- a/intern/cycles/kernel/sample/pattern.h +++ b/intern/cycles/kernel/sample/pattern.h @@ -90,18 +90,31 @@ 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 Sobol-Burley 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; } -} +#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 diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp index 86a2c9571c6..e9cd753854f 100644 --- a/intern/cycles/scene/integrator.cpp +++ b/intern/cycles/scene/integrator.cpp @@ -217,9 +217,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene FLT_MAX : sample_clamp_indirect * 3.0f; - /* Adaptive sampling requires PMJ, see sample_is_even. */ - kintegrator->sampling_pattern = (use_adaptive_sampling) ? SAMPLING_PATTERN_PMJ : - sampling_pattern; + kintegrator->sampling_pattern = sampling_pattern; kintegrator->scrambling_distance = scrambling_distance; if (light_sampling_threshold > 0.0f) { -- cgit v1.2.3