RenderMan API  23.0
RixRNGProgressive.h
Go to the documentation of this file.
1 /*
2 # ------------------------------------------------------------------------------
3 #
4 # Copyright (c) 1986-2019 Pixar. All rights reserved.
5 #
6 # The information in this file (the "Software") is provided for the exclusive
7 # use of the software licensees of Pixar ("Licensees"). Licensees have the
8 # right to incorporate the Software into other products for use by other
9 # authorized software licensees of Pixar, without fee. Except as expressly
10 # permitted herein, the Software may not be disclosed to third parties, copied
11 # or duplicated in any form, in whole or in part, without the prior written
12 # permission of Pixar.
13 #
14 # The copyright notices in the Software and this entire statement, including the
15 # above license grant, this restriction and the following disclaimer, must be
16 # included in all copies of the Software, in whole or in part, and all permitted
17 # derivative works of the Software, unless such copies or derivative works are
18 # solely in the form of machine-executable object code generated by a source
19 # language processor.
20 #
21 # PIXAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL PIXAR BE
23 # LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
25 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. IN NO CASE WILL
27 # PIXAR'S TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR IN CONNECTION WITH
28 # THE USE OR PERFORMANCE OF THIS SOFTWARE EXCEED $50.
29 #
30 # Pixar
31 # 1200 Park Ave
32 # Emeryville CA 94608
33 #
34 # ------------------------------------------------------------------------------
35 */
36 
37 
38 #ifndef RixRNGProgressive_h
39 #define RixRNGProgressive_h
40 
41 // IWYU pragma: no_include <assert.h> // for assert
42 // IWYU pragma: no_include "RiTypesHelper.h" // for RtFloat3, RtFloat2
43 // IWYU pragma: no_include "prmanapi.h" // for PRMAN_INLINE
44 
45 // This file is intended solely for inclusion by RixInterfaces.h and should
46 // not be included directly. Here we define inline implementations of private
47 // RixRNG methods. Conceptually the contents of this file are "opaque" but
48 // we provide them to deliver the highest performance. Each release may
49 // differ from the last, so in order to obtain the new benefits, clients
50 // will need to recompile.
51 //
52 // These routines collectively implement progressive multi-jittered (PMJ) sample
53 // sequences based on lookups in precomputed tables. The progressive multi-jittered
54 // sample sequences are described in detail in:
55 // "Progressive multi-jittered sample sequences" by
56 // Per Christensen, Andrew Kensler, and Charlie Kilpatrick,
57 // Proc. Eurographics Symposium on Rendering, 2018.
58 // (http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/).
59 //
60 // See also the related work on correlated multi-jittered sample sets described
61 // in Pixar Technical Memo #13-01, "Correlated Multi-Jittered Sampling"
62 // (http://graphics.pixar.com/library/MultiJitteredSampling/).
63 //
64 // Alternatively, you may use the fields in Ctx as inputs to your own
65 // sampling sequence instead if you prefer.
66 //
67 
68 //
69 // Progressive multi-jittered samples (PMJ).
70 // Lookups in pre-generated tables of progressive samples.
71 // We scramble the bits (xor) -- this preserves the PMJ properties
72 // but further increases the number of apparently different sample sequences.
73 // x and y could be flipped in order to add further apparent randomness to
74 // the samples, thus reducing aliasing from using a limited number of tables
75 // -- but this alone is not sufficient; bit scrambling gives many more
76 // different sequences.
77 // (In contrast, regular Cranley-Patterson rotation is a very bad idea
78 // for PMJ samples: it increases variance by a lot. Probably because the
79 // strata on edges get wrapped around introducing large jumps for the
80 // samples in those strata. If we really needed rotation, we could
81 // restrict the rotations to e.g. multiples of 0.25 or 0.125.)
82 //
83 
84 #define N_PMJ_DIMS 24 // number of pmj dimensions (8*3D)
85 #define N_PMJ_SEQS 48 // number of different pmj sequences
86 #define N_PMJ_SAMPS 4096 // number of samples in each pmj sequence
87 
88 class ProgressiveSampler : public Generator
89 {
90 public:
91  void* pmjTables;
92 
93  ProgressiveSampler(void* tables) : pmjTables(tables) {}
94 
95 private:
96 
97  // Compute a repeatable random float in [0,1) based on value and scramble
98  PRMAN_INLINE static float
99  HashToRandom(const unsigned value, const unsigned scramble)
100  {
101  // clang-format off
102  unsigned result = value;
103  result ^= scramble;
104  result ^= result >> 17;
105  result ^= result >> 10; result *= 0xb36534e5;
106  result ^= result >> 12;
107  result ^= result >> 21; result *= 0x93fc4795;
108  result ^= 0xdf6e307f;
109  result ^= result >> 17; result *= 1 | scramble >> 18;
110  return static_cast<float>(result) / 4298115584.0f;
111  // clang-format on
112  }
113 
114  // Compute a repeatable random unsigned int based on value and scramble.
115  // Same as HashToRandom() but returns unsigned int instead of float.
116  // Has avalanche property: if a single input bit changes, an average
117  // of half the output bits change.
118  PRMAN_INLINE static unsigned int
119  HashToRandomUInt(unsigned int const value, unsigned int const scramble)
120  {
121  // clang-format off
122  unsigned int result = value;
123  result ^= scramble;
124  result ^= result >> 17;
125  result ^= result >> 10; result *= 0xb36534e5;
126  result ^= result >> 12;
127  result ^= result >> 21; result *= 0x93fc4795;
128  result ^= 0xdf6e307f;
129  result ^= result >> 17; result *= 1 | scramble >> 18;
130  return result;
131  // clang-format on
132  }
133 
134  // Locally shuffle the sample order by carefully swapping neighbor samples
135  // (and groups of two samples and reversal of order): only samples of same
136  // class are swapped, and only within local groups of 16 samples.
137  // Class order is: AABBAABBBBAABBAA ...
138  // Local shuffling does not affect the convergence properties of each
139  // sequence, but decorrelates 2D sequences so they can be safely combined
140  // to a higher-dimensional sample (aka. "padding"). Even two patterns
141  // that happen to map to the same table and dimension will be decorrelated
142  // when shuffled differently.
143  // (In RenderMan 21 we locally shuffled the sample order by swapping neighbor
144  // samples, groups of two samples, groups of four samples, and groups of
145  // eight samples. Simpler, but breaks multiclass classification.)
146  PRMAN_INLINE static unsigned int
147  shuffle(unsigned int pattern, unsigned int sample)
148  {
149  unsigned int sample16, s;
150  s = sample;
151  sample16 = sample % 16;
152 
153  if (sample < 16) return sample;
154 
155  // Randomly swap neighbor samples (with same class)
156  if (sample16 == 0 && (pattern & 0x0100)) s++;
157  if (sample16 == 1 && (pattern & 0x0100)) s--;
158  if (sample16 == 2 && (pattern & 0x0200)) s++;
159  if (sample16 == 3 && (pattern & 0x0200)) s--;
160  if (sample16 == 4 && (pattern & 0x0400)) s++;
161  if (sample16 == 5 && (pattern & 0x0400)) s--;
162  if (sample16 == 6 && (pattern & 0x0800)) s++;
163  if (sample16 == 7 && (pattern & 0x0800)) s--;
164  if (sample16 == 8 && (pattern & 0x1000)) s++;
165  if (sample16 == 9 && (pattern & 0x1000)) s--;
166  if (sample16 == 10 && (pattern & 0x2000)) s++;
167  if (sample16 == 11 && (pattern & 0x2000)) s--;
168  if (sample16 == 12 && (pattern & 0x4000)) s++;
169  if (sample16 == 13 && (pattern & 0x4000)) s--;
170  if (sample16 == 14 && (pattern & 0x8000)) s++;
171  if (sample16 == 15 && (pattern & 0x8000)) s--;
172 
173  // Randomly swap sample pairs offset by 4 (such pairs have same class)
174  if ((sample16 == 0 || sample16 == 1) && (pattern & 0x10000)) s += 4;
175  if ((sample16 == 4 || sample16 == 5) && (pattern & 0x10000)) s -= 4;
176  if ((sample16 == 2 || sample16 == 3) && (pattern & 0x20000)) s += 4;
177  if ((sample16 == 6 || sample16 == 7) && (pattern & 0x20000)) s -= 4;
178  if ((sample16 == 8 || sample16 == 9) && (pattern & 0x40000)) s += 4;
179  if ((sample16 == 12 || sample16 == 13) && (pattern & 0x40000)) s -= 4;
180  if ((sample16 == 10 || sample16 == 11) && (pattern & 0x80000)) s += 4;
181  if ((sample16 == 14 || sample16 == 15) && (pattern & 0x80000)) s -= 4;
182 
183  // Randomly reverse sample order within groups of 16 samples
184  if (pattern & 0x100000) s = s + 15 - 2*(s%16);
185 
186  // Swap adjacent groups of 16 samples (probably not necessary?)
187  /*
188  if (pattern & 0x200000 && sample >= 32) {
189  if ((sample/16) % 2 == 0)
190  sample += 16;
191  else
192  sample -= 16;
193  }
194  */
195 
196  assert(sample/16 == s/16); // original and shuffled sample should be in same group of 16
197 
198  return s;
199  }
200 
201  // Scramble bits of sample f with bits of 'scramble' and convert back to
202  // float. Both the input f and the result are floats between 0.0 and 1.0.
203  PRMAN_INLINE static float
204  fpScramble(float f, unsigned int scramble)
205  {
206  union
207  {
208  float f;
209  unsigned int i;
210  } f2i;
211  f2i.f = f + 1.0f; // map f to [1,2) so we know the exponent is 0
212  f2i.i ^= (scramble & 0x007fffff); // scramble the fp mantissa bits
213  return f2i.f - 1.0f; // map result to [0,1)
214  }
215 
216  // Compute a progressive 1D PMJ (actually PJ) sample
217  PRMAN_INLINE float progressive1DSample(
218  const unsigned int pattern,
219  const unsigned int sample) const
220  {
221  float result;
222  float* sampleTable;
223  unsigned int d, t, s;
224  const unsigned int nDims = N_PMJ_DIMS; // 24
225  const unsigned int nSeqs = N_PMJ_SEQS; // 48
226  const unsigned int nSamps = N_PMJ_SAMPS; // 4096
227  //const unsigned int totalTableSize = nDims * nSeqs * nSamps;
228 
229  if (sample > nSeqs * nSamps)
230  {
231  // Resort to (repeatable) random when running out of table entries
232  // after 48*4096 = 196,608 samples with same pattern id.
233  // (Could be 24 times more if wrapping to next dim.)
234  result = HashToRandom(sample, pattern * 0x51633e2d);
235  return result;
236  }
237 
238  // Select sequence (table).
239  // (Note that we cannot use a 'table' specified by pixel number encoded
240  // e.g. in first 6 bits of pattern -- Woodcock tracking needs less
241  // correlation in volume tracing within in each pixel.)
242  t = pattern % nSeqs;
243  assert(t < nSeqs);
244 
245  // Select dimension
246  d = (pattern >> 7) % nDims;
247  if (d < 3) d += 9; // avoid dimension 0--2: correlated with pixel pos
248  assert(d < nDims);
249 
250  // Locally shuffle the sample order by carefully swapping neighbor samples
251  // (and groups of four samples) -- only samples of same class are swapped.
252  s = shuffle(pattern, sample);
253 
254  // When we have "used up" all 4096 samples in a table we start over
255  // in the next table.
256  t += s / nSamps;
257  t = t % nSeqs;
258  s = s % nSamps;
259 
260  // Select table entry -- note that these are ordered with sample number
261  // having the largest stride in the table, this is for improved memory
262  // access coherency during incremental (progressive) rendering.
263  s = s * nSeqs * nDims + t * nDims + d;
264  assert(s < nDims * nSeqs * nSamps);
265 
266  // Lookup sample in table
267  float** const tables = (float**)pmjTables;
268  sampleTable = tables[0]; // a single 24D table
269  result = sampleTable[s]; // progressive jittered 1D
270  assert(0.0f <= result && result <= 1.0f); // 1.0 is okay here
271 
272  // Random (but consistent) flips
273  // if (pattern & 0x1) result = 1.0f-result;
274 
275  // Scramble bits of sample with bits of pattern, convert back to float
276  unsigned int pattern1 = HashToRandomUInt(pattern, 0x51633e2d);
277  result = fpScramble(result, pattern1);
278 
279  // Ensure (bit-scrambled) values are strictly less than 1.0
280  if (result > 0.999990f) result = 0.999990f;
281  assert(0.0f <= result && result < 1.0f);
282 
283  return result;
284  }
285 
286  // Compute a progressive 2D PMJ sample.
287  // Uses bit-scrambling to generate many sequences from only 48 tables.
288  PRMAN_INLINE RtFloat2 progressive2DSample(
289  const unsigned int pattern,
290  const unsigned int sample) const
291  {
292  RtFloat2 result;
293  float* sampleTable;
294  unsigned int d, t, s;
295  const unsigned int nDims = N_PMJ_DIMS; // 24
296  const unsigned int nSeqs = N_PMJ_SEQS; // 48
297  const unsigned int nSamps = N_PMJ_SAMPS; // 4096
298  //const unsigned int totalTableSize = nDims * nSeqs * nSamps;
299 
300  if (sample > nSeqs * nSamps)
301  {
302  // Resort to (repeatable) random when running out of table entries
303  // after 48*4096 = 196,608 samples with same pattern id.
304  // (Could be 8 times more if wrapping to next dim.)
305  result.x = HashToRandom(sample, pattern * 0x51633e2d);
306  result.y = HashToRandom(sample, pattern * 0x68bc21eb);
307  return result;
308  }
309 
310  // Select sequence (table).
311  // (Note that we cannot use a 'table' specified by pixel number encoded
312  // e.g. in first 6 bits of pattern -- subsurface scattering domains etc
313  // need less correlation within in each pixel.)
314  t = pattern % nSeqs;
315  assert(t < nSeqs);
316 
317  // Select dimension based on 3 bits of pattern --
318  // each pair of dimensions 0+1, 3+4, 6+7, etc. are a pmj (0,2) sequence
319  d = 3 * ((pattern >> 23) & 0x7);
320  if (d == 0) d = 12; // avoid dimensions 0+1: correlated with pixel pos
321  assert(d < nDims);
322 
323  // Locally shuffle the sample order by carefully swapping neighbor samples
324  // (and groups of four samples) -- only samples of same class are swapped.
325  // Local shuffling does not affect the convergence properties of each
326  // sequence, but decorrelates 2D sequences so they can be safely combined
327  // to a higher-dimensional sample (aka. "padding"). Even two patterns
328  // that happen to map to the same table and dimension will be decorrelated
329  // when shuffled differently.
330  s = shuffle(pattern, sample);
331 
332  // When we have "used up" all 4096 samples in a table we start over
333  // in the next table.
334  t += s / nSamps;
335  t = t % nSeqs;
336  s = s % nSamps;
337 
338  // Select table entry -- note that these are ordered with sample number
339  // having the largest stride in the table, this is for improved memory
340  // access coherency during incremental (progressive) rendering.
341  s = s * nSeqs * nDims + t * nDims + d;
342  assert(s < nDims * nSeqs * nSamps);
343 
344  // Lookup sample in table
345  float** const tables = (float**)pmjTables;
346  sampleTable = tables[0]; // a single 24D table
347  result.x = sampleTable[s]; // 2D progressive multijittered (0,2) samples
348  result.y = sampleTable[s+1];
349  assert(0.0f <= result.x && result.x <= 1.0f); // 1.0 is okay here
350  assert(0.0f <= result.y && result.y <= 1.0f);
351 
352  // Random (but consistent) flips
353  // if (pattern & 0x1) result.x = 1.0f-result.x;
354  // if (pattern & 0x2) result.y = 1.0f-result.y;
355  // if (pattern & 0x4) std::swap(result.x, result.y);
356 
357  // Scramble bits of sample with bits of pattern, convert back to float
358  unsigned int pattern1 = HashToRandomUInt(pattern, 0x51633e2d);
359  unsigned int pattern2 = HashToRandomUInt(pattern, 0x68bc21eb);
360  result.x = fpScramble(result.x, pattern1);
361  result.y = fpScramble(result.y, pattern2);
362 
363  // Ensure (bit-scrambled) values are strictly less than 1.0
364  if (result.x > 0.999990f) result.x = 0.999990f;
365  if (result.y > 0.999990f) result.y = 0.999990f;
366  assert(0.0f <= result.x && result.x < 1.0f);
367  assert(0.0f <= result.y && result.y < 1.0f);
368 
369  return result;
370  }
371 
372  // Compute a progressive 3D PMJ sample
373  PRMAN_INLINE RtFloat3 progressive3DSample(
374  const unsigned int pattern,
375  const unsigned int sample) const
376  {
377  RtFloat3 result;
378  float* sampleTable;
379  unsigned int d, t, s;
380  const unsigned int nDims = N_PMJ_DIMS; // 24
381  const unsigned int nSeqs = N_PMJ_SEQS; // 48
382  const unsigned int nSamps = N_PMJ_SAMPS; // 4096
383  //const unsigned int totalTableSize = nDims * nSeqs * nSamps;
384 
385  if (sample > nSeqs * nSamps)
386  {
387  // Resort to (repeatable) random when running out of table entries
388  // after 48*4096 = 196,608 samples with same pattern id.
389  // (Could be 8 times more if wrapping to next dim.)
390  result.x = HashToRandom(sample, pattern * 0x51633e2d);
391  result.y = HashToRandom(sample, pattern * 0x68bc21eb);
392  result.z = HashToRandom(sample, pattern * 0x02e5be93);
393  return result;
394  }
395 
396  // Select sequence (table).
397  // (Note that we cannot use a 'table' specified by pixel number encoded
398  // e.g. in first 6 bits of pattern -- subsurface scattering domains etc
399  // need less correlation within in each pixel.)
400  t = pattern % nSeqs;
401  assert(t < nSeqs);
402 
403  // Select dimension based on 3 bits of pattern --
404  // each triple of dimensions 0--2, 3--5, 6--8, etc. are stratified in 3D
405  d = 3 * ((pattern >> 23) & 0x7);
406  if (d == 0) d = 12; // avoid dimensions 0+1: correlated with pixel pos
407  assert(d < nDims);
408 
409  // Locally shuffle the sample order by carefully swapping neighbor samples
410  // (and groups of two samples) -- only samples of same class are swapped.
411  s = shuffle(pattern, sample);
412 
413  // When we have "used up" all 4096 samples in a table we start over
414  // in the next table.
415  t += s / nSamps;
416  t = t % nSeqs;
417  s = s % nSamps;
418 
419  // Select table entry -- note that these are ordered with sample number
420  // having the largest stride in the table, this is for improved memory
421  // access coherency during incremental (progressive) rendering.
422  s = s * nSeqs * nDims + t * nDims + d;
423  assert(s < nDims * nSeqs * nSamps);
424 
425  // Lookup sample in table
426  float** const tables = (float**)pmjTables;
427  sampleTable = tables[0]; // a single 24D table
428  result.x = sampleTable[s]; // stratified in 3D
429  result.y = sampleTable[s+1];
430  result.z = sampleTable[s+2];
431  assert(0.0f <= result.x && result.x <= 1.0f); // 1.0 is okay here
432  assert(0.0f <= result.y && result.y <= 1.0f);
433  assert(0.0f <= result.z && result.z <= 1.0f);
434 
435  // Random (but consistent) flips (could also swap xy xz yz)
436  // if (pattern & 0x1) result.x = 1.0f-result.x;
437  // if (pattern & 0x2) result.y = 1.0f-result.y;
438  // if (pattern & 0x4) result.z = 1.0f-result.z;
439 
440  // Scramble bits of sample with bits of patterns, convert back to float
441  unsigned int pattern1 = HashToRandomUInt(pattern, 0x51633e2d);
442  unsigned int pattern2 = HashToRandomUInt(pattern, 0x68bc21eb);
443  unsigned int pattern3 = HashToRandomUInt(pattern, 0x02e5be93);
444  result.x = fpScramble(result.x, pattern1);
445  result.y = fpScramble(result.y, pattern2);
446  result.z = fpScramble(result.z, pattern3);
447 
448  // Ensure (bit-scrambled) values are strictly less than 1.0
449  if (result.x > 0.999990f) result.x = 0.999990f;
450  if (result.y > 0.999990f) result.y = 0.999990f;
451  if (result.z > 0.999990f) result.z = 0.999990f;
452  assert(0.0f <= result.x && result.x < 1.0f);
453  assert(0.0f <= result.y && result.y < 1.0f);
454  assert(0.0f <= result.z && result.z < 1.0f);
455 
456  return result;
457  }
458 
459 public:
460 
461  // Functions to draw a single PMJ sample from a sequence.
462  // The 'i' parameter (shading context index) is part of the Generator class
463  // interface, but ignored for PMJ samples.
464  virtual float Sample1D(const SampleCtx& rctx, unsigned i) const
465  {
466  PIXAR_ARGUSED(i);
467  return progressive1DSample(rctx.patternid, rctx.sampleid);
468  }
469 
470  virtual RtFloat2 Sample2D(const SampleCtx& rctx, unsigned i) const
471  {
472  PIXAR_ARGUSED(i);
473  return progressive2DSample(rctx.patternid, rctx.sampleid);
474  }
475 
476  virtual RtFloat3 Sample3D(const SampleCtx& rctx, unsigned i) const
477  {
478  PIXAR_ARGUSED(i);
479  return progressive3DSample(rctx.patternid, rctx.sampleid);
480  }
481 
482  // Generator functions to draw multiple samples, each from a different sequence.
483  // (Candidates for for future simd implementation)
484  virtual void MultiSample1D(
485  unsigned int n,
486  const SampleCtx* rctx,
487  float* xis) const
488  {
489  for (unsigned int i = 0; i < n; ++i)
490  {
491  xis[i] = progressive1DSample(rctx[i].patternid, rctx[i].sampleid);
492  }
493  }
494  virtual void MultiSample2D(
495  unsigned int n,
496  const SampleCtx* rctx,
497  RtFloat2* xis) const
498  {
499  for (unsigned int i = 0; i < n; ++i)
500  {
501  xis[i] = progressive2DSample(rctx[i].patternid, rctx[i].sampleid);
502  }
503  }
504  virtual void MultiSample3D(
505  unsigned int n,
506  const SampleCtx* rctx,
507  RtFloat3* xis) const
508  {
509  for (unsigned int i = 0; i < n; ++i)
510  {
511  xis[i] = progressive3DSample(rctx[i].patternid, rctx[i].sampleid);
512  }
513  }
514 };
515 
516 #endif
virtual float Sample1D(const SampleCtx &rctx, unsigned i) const
virtual void MultiSample3D(unsigned int n, const SampleCtx *rctx, RtFloat3 *xis) const
ProgressiveSampler(void *tables)
#define N_PMJ_DIMS
virtual RtFloat2 Sample2D(const SampleCtx &rctx, unsigned i) const
#define N_PMJ_SEQS
#define N_PMJ_SAMPS
virtual void MultiSample2D(unsigned int n, const SampleCtx *rctx, RtFloat2 *xis) const
#define PRMAN_INLINE
Definition: prmanapi.h:86
pxrcore::Float3 RtFloat3
Definition: RiTypesHelper.h:68
virtual RtFloat3 Sample3D(const SampleCtx &rctx, unsigned i) const
virtual void MultiSample1D(unsigned int n, const SampleCtx *rctx, float *xis) const
#define PIXAR_ARGUSED(x)
Definition: prmanapi.h:171