Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Vegdahl <cessen>2022-08-23 21:48:48 +0300
committerBrecht Van Lommel <brecht@blender.org>2022-09-01 15:57:39 +0300
commit50df9caef01a4225db216d9c4c0515134f7a37bf (patch)
treee6632fc669d7d5a9d084b2ad33764810b286e156 /intern/cycles/util/hash.h
parentba1bf87bd8f13fa2c67c435eb4a31a0c898d65ac (diff)
Cycles: improve Progressive Multi-Jittered sampling
Fix two issues in the previous implementation: * Only power-of-two prefixes were progressively stratified, not suffixes. This resulted in unnecessarily increased noise when using non-power-of-two sample counts. * In order to try to get away with just a single sample pattern, the code used a combination of sample index shuffling and Cranley-Patterson rotation. Index shuffling is normally fine, but due to the sample patterns themselves not being quite right (as described above) this actually resulted in additional increased noise. Cranley-Patterson, on the other hand, always increases noise with randomized (t,s) nets like PMJ02, and should be avoided with these kinds of sequences. Addressed with the following changes: * Replace the sample pattern generation code with a much simpler algorithm recently published in the paper "Stochastic Generation of (t, s) Sample Sequences". This new implementation is easier to verify, produces fully progressively stratified PMJ02, and is *far* faster than the previous code, being O(N) in the number of samples generated. * It keeps the sample index shuffling, which works correctly now due to the improved sample patterns. But it now uses a newer high-quality hash instead of the original Laine-Karras hash. * The scrambling distance feature cannot (to my knowledge) be implemented with any decorrelation strategy other than Cranley-Patterson, so Cranley-Patterson is still used when that feature is enabled. But it is now disabled otherwise, since it increases noise. * In place of Cranley-Patterson, multiple independent patterns are generated and randomly chosen for different pixels and dimensions as described in the original PMJ paper. In this patch, the pattern selection is done via hash-based shuffling to ensure there are no repeats within a single pixel until all patterns have been used. The combination of these fixes brings the quality of Cycles' PMJ sampler in line with the previously submitted Sobol-Burley sampler in D15679. They are essentially indistinguishable in terms of quality/noise, which is expected since they are both randomized (0,2) sequences. Differential Revision: https://developer.blender.org/D15746
Diffstat (limited to 'intern/cycles/util/hash.h')
-rw-r--r--intern/cycles/util/hash.h91
1 files changed, 57 insertions, 34 deletions
diff --git a/intern/cycles/util/hash.h b/intern/cycles/util/hash.h
index 351b8796be7..4f83f331229 100644
--- a/intern/cycles/util/hash.h
+++ b/intern/cycles/util/hash.h
@@ -4,6 +4,7 @@
#ifndef __UTIL_HASH_H__
#define __UTIL_HASH_H__
+#include "util/math.h"
#include "util/types.h"
CCL_NAMESPACE_BEGIN
@@ -407,42 +408,16 @@ ccl_device_inline uint hash_hp_seeded_uint(uint i, uint seed)
return hash_hp_uint(i ^ seed);
}
-/* Outputs [0.0, 1.0]. */
-ccl_device_inline float hash_hp_seeded_float(uint i, uint seed)
+/* Outputs [0.0, 1.0). */
+ccl_device_inline float hash_hp_float(uint i)
{
- return uint_to_float_incl(hash_hp_seeded_uint(i, seed));
+ return uint_to_float_excl(hash_hp_uint(i));
}
-/* ***** CMJ Hash Functions *****
- *
- * These are based on one of the hash functions in the paper
- * "Correlated Multi-Jittered Sampling" by Andrew Kensler, 2013.
- *
- * These are here for backwards-compatibility, and can be replaced
- * by the Hash Prospector hashes above at some point.
- * See https://developer.blender.org/D15679#426304
- */
-
-ccl_device_inline uint hash_cmj_seeded_uint(uint i, uint seed)
-{
- i ^= seed;
- i ^= i >> 17;
- i ^= i >> 10;
- i *= 0xb36534e5;
- i ^= i >> 12;
- i ^= i >> 21;
- i *= 0x93fc4795;
- i ^= 0xdf6e307f;
- i ^= i >> 17;
- i *= 1 | seed >> 18;
-
- return i;
-}
-
-/* Outputs [0.0, 1.0]. */
-ccl_device_inline float hash_cmj_seeded_float(uint i, uint seed)
+/* Outputs [0.0, 1.0). */
+ccl_device_inline float hash_hp_seeded_float(uint i, uint seed)
{
- return uint_to_float_excl(hash_cmj_seeded_uint(i, seed));
+ return uint_to_float_excl(hash_hp_seeded_uint(i, seed));
}
/* ***** Modified Wang Hash Functions *****
@@ -463,10 +438,58 @@ ccl_device_inline uint hash_wang_seeded_uint(uint i, uint seed)
return i;
}
-/* Outputs [0.0, 1.0]. */
+/* Outputs [0.0, 1.0). */
ccl_device_inline float hash_wang_seeded_float(uint i, uint seed)
{
- return uint_to_float_incl(hash_wang_seeded_uint(i, seed));
+ return uint_to_float_excl(hash_wang_seeded_uint(i, seed));
+}
+
+/* ***** Index Shuffling Hash Function *****
+ *
+ * This function takes an index, the length of the thing the index points
+ * into, and returns a shuffled index. For example, if you pass indices
+ * 0 through 19 to this function with a length parameter of 20, it will
+ * return the indices in a shuffled order with no repeats. Indices
+ * larger than the length parameter will simply repeat the same shuffled
+ * pattern over and over.
+ *
+ * This is useful for iterating over an array in random shuffled order
+ * without having to shuffle the array itself.
+ *
+ * Passing different seeds results in different random shuffles.
+ *
+ * This function runs in average O(1) time.
+ *
+ * See https://andrew-helmer.github.io/permute/ for details on how this
+ * works.
+ */
+ccl_device_inline uint hash_shuffle_uint(uint i, uint length, uint seed)
+{
+ i = i % length;
+ uint mask = (1 << (32 - count_leading_zeros(length - 1))) - 1;
+
+ do {
+ i ^= seed;
+ i *= 0xe170893d;
+ i ^= seed >> 16;
+ i ^= (i & mask) >> 4;
+ i ^= seed >> 8;
+ i *= 0x0929eb3f;
+ i ^= seed >> 23;
+ i ^= (i & mask) >> 1;
+ i *= 1 | seed >> 27;
+ i *= 0x6935fa69;
+ i ^= (i & mask) >> 11;
+ i *= 0x74dcb303;
+ i ^= (i & mask) >> 2;
+ i *= 0x9e501cc3;
+ i ^= (i & mask) >> 2;
+ i *= 0xc860a3df;
+ i &= mask;
+ i ^= i >> 5;
+ } while (i >= length);
+
+ return i;
}
/* ********** */