[Bf-blender-cvs] [409074aae56] master: Cycles: add Progressive Multi-Jitter sampling pattern
Stefan Werner
noreply at git.blender.org
Mon Mar 2 17:08:48 CET 2020
Commit: 409074aae56138f49ce078ce919a6d02e44e521e
Author: Stefan Werner
Date: Mon Mar 2 15:12:44 2020 +0100
Branches: master
https://developer.blender.org/rB409074aae56138f49ce078ce919a6d02e44e521e
Cycles: add Progressive Multi-Jitter sampling pattern
This sampling pattern is particularly suited to adaptive sampling, and will
be used for that upcoming feature.
Based on "Progressive Multi-Jittered Sample Sequences" by Per Christensen,
Andrew Kensler and Charlie Kilpatrick.
Ref D4686
===================================================================
M intern/cycles/blender/addon/properties.py
M intern/cycles/kernel/kernel_jitter.h
M intern/cycles/kernel/kernel_random.h
M intern/cycles/kernel/kernel_textures.h
M intern/cycles/kernel/kernel_types.h
M intern/cycles/render/CMakeLists.txt
M intern/cycles/render/integrator.cpp
A intern/cycles/render/jitter.cpp
A intern/cycles/render/jitter.h
M intern/cycles/render/scene.cpp
M intern/cycles/render/scene.h
M intern/cycles/render/session.cpp
===================================================================
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index d66a1f70c48..77dc29e11e8 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -112,6 +112,7 @@ enum_use_layer_samples = (
enum_sampling_pattern = (
('SOBOL', "Sobol", "Use Sobol random sampling pattern"),
('CORRELATED_MUTI_JITTER', "Correlated Multi-Jitter", "Use Correlated Multi-Jitter random sampling pattern"),
+ ('PROGRESSIVE_MUTI_JITTER', "Progressive Multi-Jitter", "Use Progressive Multi-Jitter random sampling pattern"),
)
enum_integrator = (
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
index e59d8946950..b733bb9fee2 100644
--- a/intern/cycles/kernel/kernel_jitter.h
+++ b/intern/cycles/kernel/kernel_jitter.h
@@ -195,4 +195,35 @@ ccl_device void cmj_sample_2D(int s, int N, int p, float *fx, float *fy)
}
#endif
+ccl_device float pmj_sample_1D(KernelGlobals *kg, int sample, int rng_hash, int dimension)
+{
+ /* Fallback to random */
+ if (sample > NUM_PMJ_SAMPLES) {
+ int p = rng_hash + dimension;
+ return cmj_randfloat(sample, p);
+ }
+ uint tmp_rng = cmj_hash_simple(dimension, rng_hash);
+ int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2;
+ return __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index) ^ (tmp_rng & 0x007fffff)) -
+ 1.0f;
+}
+
+ccl_device void pmj_sample_2D(
+ KernelGlobals *kg, int sample, int rng_hash, int dimension, float *fx, float *fy)
+{
+ if (sample > NUM_PMJ_SAMPLES) {
+ int p = rng_hash + dimension;
+ *fx = cmj_randfloat(sample, p);
+ *fy = cmj_randfloat(sample, p + 1);
+ }
+ uint tmp_rng = cmj_hash_simple(dimension, rng_hash);
+ int index = ((dimension % NUM_PMJ_PATTERNS) * NUM_PMJ_SAMPLES + sample) * 2;
+ *fx = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index) ^ (tmp_rng & 0x007fffff)) -
+ 1.0f;
+ tmp_rng = cmj_hash_simple(dimension + 1, rng_hash);
+ *fy = __uint_as_float(kernel_tex_fetch(__sample_pattern_lut, index + 1) ^
+ (tmp_rng & 0x007fffff)) -
+ 1.0f;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 80738213d2a..dae9c8f930c 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -43,7 +43,7 @@ ccl_device uint sobol_dimension(KernelGlobals *kg, int index, int dimension)
uint i = index + SOBOL_SKIP;
for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
j += x;
- result ^= kernel_tex_fetch(__sobol_directions, 32 * dimension + j - 1);
+ result ^= kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1);
}
return result;
}
@@ -56,7 +56,9 @@ ccl_device_forceinline float path_rng_1D(
#ifdef __DEBUG_CORRELATION__
return (float)drand48();
#endif
-
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) {
+ return pmj_sample_1D(kg, sample, rng_hash, dimension);
+ }
#ifdef __CMJ__
# ifdef __SOBOL__
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ)
@@ -99,7 +101,10 @@ ccl_device_forceinline void path_rng_2D(KernelGlobals *kg,
*fy = (float)drand48();
return;
#endif
-
+ if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_PMJ) {
+ pmj_sample_2D(kg, sample, rng_hash, dimension, fx, fy);
+ return;
+ }
#ifdef __CMJ__
# ifdef __SOBOL__
if (kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ)
@@ -284,4 +289,28 @@ ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng)
return (float)*rng * (1.0f / (float)0xFFFFFFFF);
}
+ccl_device_inline bool sample_is_even(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. There must be a more elegant way of writing this? */
+#if defined(__GNUC__) && !defined(__KERNEL_GPU__)
+ return __builtin_popcount(sample & 0xaaaaaaaa) & 1;
+#elif defined(__NVCC__)
+ return __popc(sample & 0xaaaaaaaa) & 1;
+#else
+ int i = sample & 0xaaaaaaaa;
+ i = i - ((i >> 1) & 0x55555555);
+ i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
+ i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+ return i & 1;
+#endif
+ }
+ else {
+ /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */
+ return sample & 0x1;
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 9eaa6b5516e..1cae34348c9 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -77,7 +77,7 @@ KERNEL_TEX(KernelShader, __shaders)
KERNEL_TEX(float, __lookup_table)
/* sobol */
-KERNEL_TEX(uint, __sobol_directions)
+KERNEL_TEX(uint, __sample_pattern_lut)
/* image textures */
KERNEL_TEX(TextureInfo, __texture_info)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 442b84a4f41..88c2d0d3196 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -267,6 +267,7 @@ enum PathTraceDimension {
enum SamplingPattern {
SAMPLING_PATTERN_SOBOL = 0,
SAMPLING_PATTERN_CMJ = 1,
+ SAMPLING_PATTERN_PMJ = 2,
SAMPLING_NUM_PATTERNS,
};
@@ -1667,6 +1668,10 @@ typedef struct WorkTile {
ccl_global float *buffer;
} WorkTile;
+/* Precoumputed sample table sizes for PMJ02 sampler. */
+#define NUM_PMJ_SAMPLES 64 * 64
+#define NUM_PMJ_PATTERNS 48
+
CCL_NAMESPACE_END
#endif /* __KERNEL_TYPES_H__ */
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 9e876b8d95c..2a077f486fa 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -24,6 +24,7 @@ set(SRC
hair.cpp
image.cpp
integrator.cpp
+ jitter.cpp
light.cpp
merge.cpp
mesh.cpp
@@ -62,6 +63,7 @@ set(SRC_HEADERS
image.h
integrator.h
light.h
+ jitter.h
merge.h
mesh.h
nodes.h
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 530c32106b7..f289e11fe14 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -18,11 +18,14 @@
#include "render/background.h"
#include "render/integrator.h"
#include "render/film.h"
+#include "render/jitter.h"
#include "render/light.h"
#include "render/scene.h"
#include "render/shader.h"
#include "render/sobol.h"
+#include "kernel/kernel_types.h"
+
#include "util/util_foreach.h"
#include "util/util_hash.h"
@@ -78,6 +81,7 @@ NODE_DEFINE(Integrator)
static NodeEnum sampling_pattern_enum;
sampling_pattern_enum.insert("sobol", SAMPLING_PATTERN_SOBOL);
sampling_pattern_enum.insert("cmj", SAMPLING_PATTERN_CMJ);
+ sampling_pattern_enum.insert("pmj", SAMPLING_PATTERN_PMJ);
SOCKET_ENUM(sampling_pattern, "Sampling Pattern", sampling_pattern_enum, SAMPLING_PATTERN_SOBOL);
return type;
@@ -203,18 +207,34 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
int dimensions = PRNG_BASE_NUM + max_samples * PRNG_BOUNCE_NUM;
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
- uint *directions = dscene->sobol_directions.alloc(SOBOL_BITS * dimensions);
+ if (sampling_pattern == SAMPLING_PATTERN_SOBOL) {
+ uint *directions = dscene->sample_pattern_lut.alloc(SOBOL_BITS * dimensions);
- sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
+ sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
- dscene->sobol_directions.copy_to_device();
+ dscene->sample_pattern_lut.copy_to_device();
+ }
+ else {
+ constexpr int sequence_size = NUM_PMJ_SAMPLES;
+ constexpr int num_sequences = NUM_PMJ_PATTERNS;
+ float2 *directions = (float2 *)dscene->sample_pattern_lut.alloc(sequence_size * num_sequences *
+ 2);
+ TaskPool pool;
+ for (int j = 0; j < num_sequences; ++j) {
+ float2 *sequence = directions + j * sequence_size;
+ pool.push(
+ function_bind(&progressive_multi_jitter_02_generate_2D, sequence, sequence_size, j));
+ }
+ pool.wait_work();
+ dscene->sample_pattern_lut.copy_to_device();
+ }
need_update = false;
}
void Integrator::device_free(Device *, DeviceScene *dscene)
{
- dscene->sobol_directions.free();
+ dscene->sample_pattern_lut.free();
}
bool Integrator::modified(const Integrator &integrator)
diff --git a/intern/cycles/render/jitter.cpp b/intern/cycles/render/jitter.cpp
new file mode 100644
index 00000000000..fc47b0e8f0a
--- /dev/null
+++ b/intern/cycles/render/jitter.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2019 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This file is based on "Progressive Multi-Jittered Sample Sequences"
+ * by Per Christensen, Andrew Kensler and Charlie Kilpatrick.
+ * http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/paper.pdf
+ *
+ * Performance can be improved in the future by implementing the new
+ * algorithm from Matt Pharr in http://jcgt.org/published/0008/01/04/
+ * "Efficient Generation of Points that Satisfy Two-Dimensional Elementary Intervals"
+ */
+
+#include "render/jitter.h"
+
+#include <math.h>
+#include <vector>
+
+CCL_NAMESPACE_BEGIN
+
+static uint cmj_hash(uint i, uint p)
+{
+ i ^= p;
+ i ^= i >> 17;
+ i ^= i >> 10;
+ i *= 0xb36534e5;
+ i ^= i >> 12;
+ i ^= i >> 21;
+ i *= 0x93fc4795;
+ i ^=
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list