RenderMan API  23.0
RixRNG.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 RixRNG_h
39 #define RixRNG_h
40 
41 #include <cassert> // for assert
42 #include "prmanapi.h" // IWYU pragma: keep // for PRMAN_INLINE
43 #include "ri.h" // for RtFloat2, RtFloat3
44 
56 
57 #include "RixRNGInline.h" // IWYU pragma: export
58 
59 class RixRNG
60 {
61 public:
62 
63  // A bit pattern used to create new RixRNG domains. An empty scoped enum
64  // is used to make this distinct from unsigned int for type-safety.
65  // Use an explicit cast to create a value of this type, e.g.:
66  // static_cast<RixRNG::Scramble>(0xfa1afe1)
67  enum class Scramble : unsigned {};
68 
76  struct SampleCtx
77  {
78  unsigned patternid; // bit pattern used to select a sample sequence
79  unsigned sampleid; // sample number
80 
86  SampleCtx NewDomain(Scramble scramble) const
87  {
88  SampleCtx newd = *this;
89  newd.patternid =
90  RixRNGUtils::shufflePattern(patternid + static_cast<unsigned>(scramble));
91  return newd;
92  }
93 
105  SampleCtx NewDomainDistrib(Scramble scramble, unsigned newsampleid) const
106  {
107  SampleCtx newd;
108  newd.patternid =
109  RixRNGUtils::shufflePattern(patternid + static_cast<unsigned>(scramble), sampleid);
110  newd.sampleid = newsampleid;
111  return newd;
112  }
113 
123  SampleCtx NewDomainSplit(Scramble scramble, unsigned newnumsamples) const
124  {
125  SampleCtx newd = *this;
126  newd.patternid =
127  RixRNGUtils::shufflePattern(patternid + static_cast<unsigned>(scramble));
128  newd.sampleid *= newnumsamples;
129  return newd;
130  }
131  }; // end of struct SampleCtx
132 
133  // Overrideable implementation
134  class Generator
135  {
136  public:
138  virtual ~Generator() {}
139 
140  // Generator functions to draw a single sample from a sequence.
141  // The parameter 'i' is for sample generators that need the shading context index
142  // to keep track of internal data. (The default PMJ Generator does not need it.)
143  virtual float Sample1D(const SampleCtx& rCtx, unsigned i) const = 0;
144  virtual RtFloat2 Sample2D(const SampleCtx& rCtx, unsigned i) const = 0;
145  virtual RtFloat3 Sample3D(const SampleCtx& rCtx, unsigned i) const = 0;
146 
147  // Generator functions to draw multiple samples, each from a different sequence
148  virtual void MultiSample1D(
149  unsigned n,
150  const SampleCtx* rCtx,
151  float* xis) const = 0;
152  virtual void MultiSample2D(
153  unsigned n,
154  const SampleCtx* rCtx,
155  RtFloat2* xis) const = 0;
156  virtual void MultiSample3D(
157  unsigned n,
158  const SampleCtx* rCtx,
159  RtFloat3* xis) const = 0;
160  };
161 
162 // Default implementation
163 #include "RixRNGProgressive.h" // IWYU pragma: export
164 
165 public:
166 
167  // RixRNG constructors
168 
169  RixRNG(Generator const *imp, unsigned scaSize = 0)
170  : numPts(scaSize), sampleCtxArray(0), impl(imp)
171  {
172  }
173 
174  // Construct a new RixRNG, with specified number of points and SampleCtx
175  // memory block.
176  RixRNG(Generator const *imp, unsigned scaSize, SampleCtx* sca)
177  : numPts(scaSize), sampleCtxArray(sca), impl(imp)
178  {
179  }
180 
181  // Construct a RixRNG based on another, but with a new number of points
182  // and SampleCtx memory block.
183  RixRNG(RixRNG const* parent, unsigned scaSize, SampleCtx* sca)
184  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
185  {
186  }
187 
188  // Construct a RixRNG based on another, but with a new SampleCtx memory block.
189  // (Same as constructor above, except parameter order.)
190  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize)
191  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
192  {
193  }
194 
195  // Construct a RixRNG based on another, but with a new SampleCtx memory
196  // block. Derivation of the new SampleCtx domain uses NewDomains(), ie.
197  // no trajectory splitting and no independent distribution.
198  // WARNING: if your parent RNG is of a different size, do not use
199  // this routine.
200  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize, Scramble scramble)
201  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
202  {
203  // Ensure that the new RixRNG isn't larger than the parent.
204  // If the new one is larger we'll read uninitialized memory in NewDomains().
205  assert(scaSize <= parent->numPts);
206 
207  parent->NewDomains(scramble, this);
208  }
209 
210  // Construct a RixRNG based on another, but with a new SampleCtx memory
211  // block. Derivation of the new SampleCtx domain uses trajectory splitting
212  // by calling NewDomainsSplit(). If nsamps=1 then there is no
213  // actual splitting; in that case, it's the same as calling the function
214  // above.
215  // WARNING: if your parent RNG is of a different size, do not use
216  // this routine.
217  RixRNG(RixRNG const* parent, SampleCtx* sca, unsigned scaSize, Scramble scramble, unsigned nsamps)
218  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
219  {
220  // Ensure that the new RixRNG isn't larger than the parent.
221  // If the new one is larger we'll read uninitialized memory in NewDomainsSplit().
222  assert(scaSize <= parent->numPts);
223 
224  parent->NewDomainsSplit(scramble, nsamps, this);
225  }
226 
227  // Construct a RixRNG based on another, but with a new SampleCtx memory
228  // block. Derivation of the new SampleCtx domain generates a new distribution
229  // if doDistrib = true, and ordinary path tracing if false.
230  // WARNING: if your parent RNG is of a different size, do not use
231  // this routine.
233  RixRNG const* parent,
234  SampleCtx* sca, // sample context array
235  unsigned scaSize, // size of sample context array
236  Scramble scramble,
237  unsigned sampleid, // only used if doDistrib is true
238  bool doDistrib)
239  : numPts(scaSize), sampleCtxArray(sca), impl(parent->impl)
240  {
241  // Ensure that the new RixRNG isn't larger than the parent.
242  // If the new one is larger we'll read uninitialized memory in NewDomains().
243  assert(scaSize <= parent->numPts);
244 
245  if (doDistrib) {
246  parent->NewDomainsDistrib(scramble, sampleid, this);
247  } else {
248  parent->NewDomains(scramble, this);
249  }
250  }
251 
252  // Construct a single-element RNG based on another, need new SampleCtx
253  // memory and an offset into parent's sample array.
254  RixRNG GetSlice(SampleCtx* sca, unsigned index) const
255  {
256  RixRNG result(this->impl);
257  result.numPts = 1;
258  result.sampleCtxArray = sca;
259  result.sampleCtxArray[0] = this->sampleCtxArray[index];
260  return result;
261  }
262 
263  virtual ~RixRNG() {}
264 
265  unsigned numPts; // number of elements in sampleCtxArray[]
266  SampleCtx* sampleCtxArray; // sample contexts: pattern ids and sample ids
267  Generator const *impl; // implementation of sample generator
268 
269  SampleCtx& GetSampleCtx(unsigned i) { return sampleCtxArray[i]; }
270 
271  // The 'Generate' family of interfaces assumes caller will generate
272  // a sequence of samples based on a SampleCtx obtained from the
273  // renderer. Generate functions increment the sampleid; Draw functions
274  // do not.
275 
276  // Generate a sample from the sequence and increment sample id
277  float GenerateSample1D(unsigned i) const
278  {
279  float f = impl->Sample1D(sampleCtxArray[i], i); // second param is ignored for PMJ
280  sampleCtxArray[i].sampleid++;
281  return f;
282  }
283 
284  RtFloat2 GenerateSample2D(unsigned i) const
285  {
286  RtFloat2 f2 = impl->Sample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
287  sampleCtxArray[i].sampleid++;
288  return f2;
289  }
290 
291  RtFloat3 GenerateSample3D(unsigned i) const
292  {
293  RtFloat3 f3 = impl->Sample3D(sampleCtxArray[i], i); // second param is ignored for PMJ
294  sampleCtxArray[i].sampleid++;
295  return f3;
296  }
297 
298  // Generate a sample from the sequence and increment sample id
299  float GenerateSample1D(SampleCtx& c, unsigned i) const
300  {
301  float f = impl->Sample1D(c, i); // second param is ignored for PMJ
302  c.sampleid++;
303  return f;
304  }
305 
306  RtFloat2 GenerateSample2D(SampleCtx& c, unsigned i) const
307  {
308  RtFloat2 f2 = impl->Sample2D(c, i); // second param is ignored for PMJ
309  c.sampleid++;
310  return f2;
311  }
312 
313  RtFloat3 GenerateSample3D(SampleCtx& c, unsigned i) const
314  {
315  RtFloat3 f3 = impl->Sample3D(c, i); // second param is ignored for PMJ
316  c.sampleid++;
317  return f3;
318  }
319 
320  // Generate numPts samples (each from a different sequence) and increment sample ids
321  void GenerateSamples1D(float* xis) const
322  {
323  impl->MultiSample1D(numPts, sampleCtxArray, xis);
325  }
326 
327  void GenerateSamples2D(RtFloat2* xis) const
328  {
329  impl->MultiSample2D(numPts, sampleCtxArray, xis);
331  }
332 
333  void GenerateSamples3D(RtFloat3* xis) const
334  {
335  impl->MultiSample3D(numPts, sampleCtxArray, xis);
337  }
338 
339  // Draw a sample from the sequence
340  float DrawSample1D(unsigned i) const
341  {
342  return impl->Sample1D(sampleCtxArray[i], i); // second param is ignored for PMJ
343  }
344 
345  RtFloat2 DrawSample2D(unsigned i) const
346  {
347  return impl->Sample2D(sampleCtxArray[i], i); // second param is ignored for PMJ
348  }
349 
350  RtFloat3 DrawSample3D(unsigned i) const
351  {
352  return impl->Sample3D(sampleCtxArray[i], i); // second param is ignored for PMJ
353  }
354 
355  // Draw a sample from the sequence
356  float DrawSample1D(const SampleCtx& c, unsigned i) const
357  {
358  return impl->Sample1D(c, i); // second param is ignored for PMJ
359  }
360 
361  RtFloat2 DrawSample2D(const SampleCtx& c, unsigned i) const
362  {
363  return impl->Sample2D(c, i); // second param is ignored for PMJ
364  }
365 
366  RtFloat3 DrawSample3D(const SampleCtx& c, unsigned i) const
367  {
368  return impl->Sample3D(c, i); // second param is ignored for PMJ
369  }
370 
371  // Draw numPts samples (each from a different sequence)
372  void DrawSamples1D(float* xis) const
373  {
374  impl->MultiSample1D(numPts, sampleCtxArray, xis);
375  }
376 
377  void DrawSamples2D(RtFloat2* xis) const
378  {
379  impl->MultiSample2D(numPts, sampleCtxArray, xis);
380  }
381 
382  void DrawSamples3D(RtFloat3* xis) const
383  {
384  impl->MultiSample3D(numPts, sampleCtxArray, xis);
385  }
386 
387  // Increment all sampleids
388  void IncrementSampleIds() const
389  {
390  for (unsigned i = 0; i < numPts; ++i)
391  sampleCtxArray[i].sampleid++;
392  }
393 
394  // Setting up new random domains
395  SampleCtx NewDomain(unsigned i, Scramble scramble) const
396  {
397  return sampleCtxArray[i].NewDomain(scramble);
398  }
399 
400  SampleCtx NewDomainDistrib(unsigned i, Scramble scramble,
401  unsigned newsampleid) const
402  {
403  return sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
404  }
405 
406  SampleCtx NewDomainSplit(unsigned i, Scramble scramble,
407  unsigned newnumsamples) const
408  {
409  return sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
410  }
411 
412  // Multi-point versions of NewDomain() functions.
413  // Setting up new random domains for all sampleCtxs.
414  // These generate new patternids in-place.
415  void NewDomains(Scramble scramble) const
416  {
417  for (unsigned i = 0; i < numPts; i++) {
418  sampleCtxArray[i] = sampleCtxArray[i].NewDomain(scramble);
419  }
420  }
421 
422  void NewDomainsDistrib(Scramble scramble, unsigned newsampleid) const
423  {
424  for (unsigned i = 0; i < numPts; i++) {
425  sampleCtxArray[i] =
426  sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
427  }
428  }
429 
430  void NewDomainsSplit(Scramble scramble, unsigned newnumsamples) const
431  {
432  for (unsigned i = 0; i < numPts; i++) {
433  sampleCtxArray[i] =
434  sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
435  }
436  }
437 
438  // More multi-point versions of NewDomain() functions.
439  // Setting up new random domains for all sampleCtxs.
440  // (To facilitate future more efficient simd implementations.)
441  // These ones require the new RixRNG to have same size as the current ("parent") one.
442  void NewDomains(Scramble scramble, RixRNG *newRng) const
443  {
444  for (unsigned i = 0; i < numPts; i++) {
445  newRng->sampleCtxArray[i] = sampleCtxArray[i].NewDomain(scramble);
446  }
447  newRng->numPts = numPts;
448  }
449 
450  void NewDomainsDistrib(Scramble scramble, unsigned newsampleid,
451  RixRNG *newRng) const
452  {
453  for (unsigned i = 0; i < numPts; i++) {
454  newRng->sampleCtxArray[i] =
455  sampleCtxArray[i].NewDomainDistrib(scramble, newsampleid);
456  }
457  newRng->numPts = numPts;
458  }
459 
460  void NewDomainsSplit(Scramble scramble, unsigned newnumsamples,
461  RixRNG *newRng) const
462  {
463  for (unsigned i = 0; i < numPts; i++) {
464  newRng->sampleCtxArray[i] =
465  sampleCtxArray[i].NewDomainSplit(scramble, newnumsamples);
466  }
467  newRng->numPts = numPts;
468  }
469 
470 };
472 #endif
void NewDomains(Scramble scramble) const
Definition: RixRNG.h:415
virtual float Sample1D(const SampleCtx &rCtx, unsigned i) const =0
void DrawSamples3D(RtFloat3 *xis) const
Definition: RixRNG.h:382
virtual void MultiSample1D(unsigned n, const SampleCtx *rCtx, float *xis) const =0
void GenerateSamples1D(float *xis) const
Definition: RixRNG.h:321
RixRNG(RixRNG const *parent, SampleCtx *sca, unsigned scaSize, Scramble scramble, unsigned sampleid, bool doDistrib)
Definition: RixRNG.h:232
void GenerateSamples2D(RtFloat2 *xis) const
Definition: RixRNG.h:327
RtFloat3 GenerateSample3D(SampleCtx &c, unsigned i) const
Definition: RixRNG.h:313
RixRNG(Generator const *imp, unsigned scaSize, SampleCtx *sca)
Definition: RixRNG.h:176
void DrawSamples1D(float *xis) const
Definition: RixRNG.h:372
virtual ~Generator()
Definition: RixRNG.h:138
SampleCtx * sampleCtxArray
Definition: RixRNG.h:266
unsigned patternid
Definition: RixRNG.h:78
RtFloat2 GenerateSample2D(SampleCtx &c, unsigned i) const
Definition: RixRNG.h:306
Generator const * impl
Definition: RixRNG.h:267
RixRNG(Generator const *imp, unsigned scaSize=0)
Definition: RixRNG.h:169
RtFloat3 DrawSample3D(const SampleCtx &c, unsigned i) const
Definition: RixRNG.h:366
RtFloat2 GenerateSample2D(unsigned i) const
Definition: RixRNG.h:284
virtual void MultiSample3D(unsigned n, const SampleCtx *rCtx, RtFloat3 *xis) const =0
void NewDomainsDistrib(Scramble scramble, unsigned newsampleid, RixRNG *newRng) const
Definition: RixRNG.h:450
virtual RtFloat2 Sample2D(const SampleCtx &rCtx, unsigned i) const =0
RtFloat3 GenerateSample3D(unsigned i) const
Definition: RixRNG.h:291
float GenerateSample1D(SampleCtx &c, unsigned i) const
Definition: RixRNG.h:299
virtual void MultiSample2D(unsigned n, const SampleCtx *rCtx, RtFloat2 *xis) const =0
void NewDomainsSplit(Scramble scramble, unsigned newnumsamples) const
Definition: RixRNG.h:430
RixRNG(RixRNG const *parent, unsigned scaSize, SampleCtx *sca)
Definition: RixRNG.h:183
SampleCtx NewDomainDistrib(unsigned i, Scramble scramble, unsigned newsampleid) const
Definition: RixRNG.h:400
float DrawSample1D(const SampleCtx &c, unsigned i) const
Definition: RixRNG.h:356
unsigned sampleid
Definition: RixRNG.h:79
virtual RtFloat3 Sample3D(const SampleCtx &rCtx, unsigned i) const =0
SampleCtx NewDomain(Scramble scramble) const
Definition: RixRNG.h:86
Scramble
Definition: RixRNG.h:67
float DrawSample1D(unsigned i) const
Definition: RixRNG.h:340
unsigned numPts
Definition: RixRNG.h:265
RixRNG(RixRNG const *parent, SampleCtx *sca, unsigned scaSize, Scramble scramble, unsigned nsamps)
Definition: RixRNG.h:217
RixRNG(RixRNG const *parent, SampleCtx *sca, unsigned scaSize, Scramble scramble)
Definition: RixRNG.h:200
RixRNG(RixRNG const *parent, SampleCtx *sca, unsigned scaSize)
Definition: RixRNG.h:190
SampleCtx NewDomain(unsigned i, Scramble scramble) const
Definition: RixRNG.h:395
RtFloat2 DrawSample2D(unsigned i) const
Definition: RixRNG.h:345
pxrcore::Float3 RtFloat3
Definition: RiTypesHelper.h:68
Definition: RixRNG.h:59
SampleCtx NewDomainDistrib(Scramble scramble, unsigned newsampleid) const
Definition: RixRNG.h:105
void NewDomains(Scramble scramble, RixRNG *newRng) const
Definition: RixRNG.h:442
float GenerateSample1D(unsigned i) const
Definition: RixRNG.h:277
virtual ~RixRNG()
Definition: RixRNG.h:263
void NewDomainsDistrib(Scramble scramble, unsigned newsampleid) const
Definition: RixRNG.h:422
void GenerateSamples3D(RtFloat3 *xis) const
Definition: RixRNG.h:333
RixRNG GetSlice(SampleCtx *sca, unsigned index) const
Definition: RixRNG.h:254
RtFloat3 DrawSample3D(unsigned i) const
Definition: RixRNG.h:350
SampleCtx & GetSampleCtx(unsigned i)
Definition: RixRNG.h:269
SampleCtx NewDomainSplit(unsigned i, Scramble scramble, unsigned newnumsamples) const
Definition: RixRNG.h:406
void DrawSamples2D(RtFloat2 *xis) const
Definition: RixRNG.h:377
void NewDomainsSplit(Scramble scramble, unsigned newnumsamples, RixRNG *newRng) const
Definition: RixRNG.h:460
PRMAN_INLINE unsigned shufflePattern(const unsigned pattern, const unsigned scramble1=0xb2182ef5, const unsigned scramble2=0x1e1897a7)
Definition: RixRNGInline.h:67
void IncrementSampleIds() const
Definition: RixRNG.h:388
RtFloat2 DrawSample2D(const SampleCtx &c, unsigned i) const
Definition: RixRNG.h:361
SampleCtx NewDomainSplit(Scramble scramble, unsigned newnumsamples) const
Definition: RixRNG.h:123