[Bf-blender-cvs] [03b5be4e3cd] blender-v3.4-release: Cycles: use more PMJ patterns and make their size adaptive.

Nathan Vegdahl noreply at git.blender.org
Mon Nov 21 19:19:11 CET 2022


Commit: 03b5be4e3cdf6a4967cb438dacd595c23075db79
Author: Nathan Vegdahl
Date:   Mon Nov 21 18:16:27 2022 +0100
Branches: blender-v3.4-release
https://developer.blender.org/rB03b5be4e3cdf6a4967cb438dacd595c23075db79

Cycles: use more PMJ patterns and make their size adaptive.

This resolves some issues with correlation artifacts at higher sample counts.

Fix T101356, correlation issues in new PMJ pattern.

Differential Revision: https://developer.blender.org/D16561

===================================================================

M	intern/cycles/kernel/data_template.h
M	intern/cycles/kernel/sample/jitter.h
M	intern/cycles/kernel/types.h
M	intern/cycles/scene/integrator.cpp

===================================================================

diff --git a/intern/cycles/kernel/data_template.h b/intern/cycles/kernel/data_template.h
index 6b89de13797..c7b50b20c70 100644
--- a/intern/cycles/kernel/data_template.h
+++ b/intern/cycles/kernel/data_template.h
@@ -183,6 +183,7 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_lamp_mis)
 KERNEL_STRUCT_MEMBER(integrator, int, use_caustics)
 /* Sampling pattern. */
 KERNEL_STRUCT_MEMBER(integrator, int, sampling_pattern)
+KERNEL_STRUCT_MEMBER(integrator, int, pmj_sequence_size)
 KERNEL_STRUCT_MEMBER(integrator, float, scrambling_distance)
 /* Volume render. */
 KERNEL_STRUCT_MEMBER(integrator, int, use_volumes)
@@ -205,6 +206,11 @@ KERNEL_STRUCT_MEMBER(integrator, int, use_surface_guiding)
 KERNEL_STRUCT_MEMBER(integrator, int, use_volume_guiding)
 KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_direct_light)
 KERNEL_STRUCT_MEMBER(integrator, int, use_guiding_mis_weights)
+
+/* Padding. */
+KERNEL_STRUCT_MEMBER(integrator, int, pad1)
+KERNEL_STRUCT_MEMBER(integrator, int, pad2)
+KERNEL_STRUCT_MEMBER(integrator, int, pad3)
 KERNEL_STRUCT_END(KernelIntegrator)
 
 /* SVM. For shader specialization. */
diff --git a/intern/cycles/kernel/sample/jitter.h b/intern/cycles/kernel/sample/jitter.h
index e748f95fc7d..1cde9f9d3de 100644
--- a/intern/cycles/kernel/sample/jitter.h
+++ b/intern/cycles/kernel/sample/jitter.h
@@ -7,6 +7,25 @@
 #pragma once
 CCL_NAMESPACE_BEGIN
 
+ccl_device uint pmj_shuffled_sample_index(KernelGlobals kg, uint sample, uint dimension, uint seed)
+{
+  const uint sample_count = kernel_data.integrator.pmj_sequence_size;
+
+  /* Shuffle the pattern order and sample index to better decorrelate
+   * dimensions and make the most of the finite patterns we have.
+   * The funky sample mask stuff is to ensure that we only shuffle
+   * *within* the current sample pattern, which is necessary to avoid
+   * early repeat pattern use. */
+  const uint pattern_i = hash_shuffle_uint(dimension, NUM_PMJ_PATTERNS, seed);
+  /* sample_count should always be a power of two, so this results in a mask. */
+  const uint sample_mask = sample_count - 1;
+  const uint sample_shuffled = nested_uniform_scramble(sample,
+                                                       hash_wang_seeded_uint(dimension, seed));
+  sample = (sample & ~sample_mask) | (sample_shuffled & sample_mask);
+
+  return ((pattern_i * sample_count) + sample) % (sample_count * NUM_PMJ_PATTERNS);
+}
+
 ccl_device float pmj_sample_1D(KernelGlobals kg,
                                uint sample,
                                const uint rng_hash,
@@ -20,22 +39,9 @@ ccl_device float pmj_sample_1D(KernelGlobals kg,
     seed = kernel_data.integrator.seed;
   }
 
-  /* Shuffle the pattern order and sample index to better decorrelate
-   * dimensions and make the most of the finite patterns we have.
-   * The funky sample mask stuff is to ensure that we only shuffle
-   * *within* the current sample pattern, which is necessary to avoid
-   * early repeat pattern use. */
-  const uint pattern_i = hash_shuffle_uint(dimension, NUM_PMJ_PATTERNS, seed);
-  /* NUM_PMJ_SAMPLES should be a power of two, so this results in a mask. */
-  const uint sample_mask = NUM_PMJ_SAMPLES - 1;
-  const uint sample_shuffled = nested_uniform_scramble(sample,
-                                                       hash_wang_seeded_uint(dimension, seed));
-  sample = (sample & ~sample_mask) | (sample_shuffled & sample_mask);
-
   /* Fetch the sample. */
-  const uint index = ((pattern_i * NUM_PMJ_SAMPLES) + sample) %
-                     (NUM_PMJ_SAMPLES * NUM_PMJ_PATTERNS);
-  float x = kernel_data_fetch(sample_pattern_lut, index * 2);
+  const uint index = pmj_shuffled_sample_index(kg, sample, dimension, seed);
+  float x = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS);
 
   /* Do limited Cranley-Patterson rotation when using scrambling distance. */
   if (kernel_data.integrator.scrambling_distance < 1.0f) {
@@ -61,23 +67,10 @@ ccl_device float2 pmj_sample_2D(KernelGlobals kg,
     seed = kernel_data.integrator.seed;
   }
 
-  /* Shuffle the pattern order and sample index to better decorrelate
-   * dimensions and make the most of the finite patterns we have.
-   * The funky sample mask stuff is to ensure that we only shuffle
-   * *within* the current sample pattern, which is necessary to avoid
-   * early repeat pattern use. */
-  const uint pattern_i = hash_shuffle_uint(dimension, NUM_PMJ_PATTERNS, seed);
-  /* NUM_PMJ_SAMPLES should be a power of two, so this results in a mask. */
-  const uint sample_mask = NUM_PMJ_SAMPLES - 1;
-  const uint sample_shuffled = nested_uniform_scramble(sample,
-                                                       hash_wang_seeded_uint(dimension, seed));
-  sample = (sample & ~sample_mask) | (sample_shuffled & sample_mask);
-
   /* Fetch the sample. */
-  const uint index = ((pattern_i * NUM_PMJ_SAMPLES) + sample) %
-                     (NUM_PMJ_SAMPLES * NUM_PMJ_PATTERNS);
-  float x = kernel_data_fetch(sample_pattern_lut, index * 2);
-  float y = kernel_data_fetch(sample_pattern_lut, index * 2 + 1);
+  const uint index = pmj_shuffled_sample_index(kg, sample, dimension, seed);
+  float x = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS);
+  float y = kernel_data_fetch(sample_pattern_lut, index * NUM_PMJ_DIMENSIONS + 1);
 
   /* Do limited Cranley-Patterson rotation when using scrambling distance. */
   if (kernel_data.integrator.scrambling_distance < 1.0f) {
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 24c5a6a4540..6d80fd3425c 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -1382,12 +1382,13 @@ static_assert_align(KernelShaderEvalInput, 16);
 
 /* Pre-computed sample table sizes for PMJ02 sampler.
  *
- * NOTE: divisions *must* be a power of two, and patterns
+ * NOTE: min and max samples *must* be a power of two, and patterns
  * ideally should be as well.
  */
-#define NUM_PMJ_DIVISIONS 32
-#define NUM_PMJ_SAMPLES ((NUM_PMJ_DIVISIONS) * (NUM_PMJ_DIVISIONS))
-#define NUM_PMJ_PATTERNS 64
+#define MIN_PMJ_SAMPLES 256
+#define MAX_PMJ_SAMPLES 8192
+#define NUM_PMJ_DIMENSIONS 2
+#define NUM_PMJ_PATTERNS 256
 
 /* Device kernels.
  *
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index ade4716242b..23f9e8b7aa8 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -257,12 +257,18 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
     kintegrator->light_inv_rr_threshold = 0.0f;
   }
 
+  constexpr int num_sequences = NUM_PMJ_PATTERNS;
+  int sequence_size = clamp(next_power_of_two(aa_samples - 1), MIN_PMJ_SAMPLES, MAX_PMJ_SAMPLES);
   if (kintegrator->sampling_pattern == SAMPLING_PATTERN_PMJ &&
-      dscene->sample_pattern_lut.size() == 0) {
-    constexpr int sequence_size = NUM_PMJ_SAMPLES;
-    constexpr int num_sequences = NUM_PMJ_PATTERNS;
+      dscene->sample_pattern_lut.size() !=
+          (sequence_size * NUM_PMJ_DIMENSIONS * NUM_PMJ_PATTERNS)) {
+    kintegrator->pmj_sequence_size = sequence_size;
+
+    if (dscene->sample_pattern_lut.size() != 0) {
+      dscene->sample_pattern_lut.free();
+    }
     float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
-                                                                    2);
+                                                                    NUM_PMJ_DIMENSIONS);
     TaskPool pool;
     for (int j = 0; j < num_sequences; ++j) {
       float2 *sequence = directions + j * sequence_size;



More information about the Bf-blender-cvs mailing list