Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Example:  Bxdf GenerateSample() functions need 2D samples to generate sample directions.  The GenerateSample() functions have a RixRNG input parameter (called often calld "rng") for this purpose.  The RixRNG's sampleCtxArray contains numPts sample contexts, where numPts is the number of shading points to generate sample directions for.  Each sample context keeps track of the patternid and sampleid for that shading point.  In order to get a 2D sample for each shading point, a single call to DrawSamples2D() is sufficient:        RtFloat2

Code Block
  RtFloat2 *xi = (RtFloat2 *) RixAlloca(sizeof(RtFloat2) * numPts);

...


  rng->DrawSamples2D(xi);

...

   // draw numPts 2D samples; fill in xi array

Generating new sample domains (new patternids)

...

The scramble patterns can be any 32-bit pattern, but it is important that the bit pattern to generate different new domains are different.  For example, if an Integrator is generating new domains for bxdf and light source sampling, those should use different scramble bit patterns.  Otherwise there will be visible correlation between bxdf and light source sampling, leading to visible artifacts and poor convergence – or even no convergence at all!  Examples of bit patterns used in the PxrPathTracer Integrator are 0x2d96c92b, 0x3917fe2e, and 0xdeb189cf; there isn't anything particular about these bit patterns, the main point is that they are "random" and different.

Integrators call RixRNG constructors to set up sample domains for bxdfs lobe selection and sampling, light selection and sampling, stochastic transmission, and several other things.  

There are several different RixRNG constructors.  The simplest ones are simply passed an already allocated sample context array and its size, and assigns these to the RixRNG sampleCtxArray and numPts member variables.  The more fancy ones data in the sampleCtxArray (patternids and sampleids) can be filled in before or after the RixRNG constructor call.  The more fancy RixRNG constructors construct a new RixRNG based on an existing one , optionally and fills in all the sampleCtxArray values – optionally with splitting or distribution.

Example:  Integrators call RixRNG constructors to set up sample domains for bxdfs lobe selection and sampling, light selection and sampling, stochastic transmission, and several other things.

RixRNG rng(parentRNG, samplectxarray, numpts);

The data in the sampleCtxArray (patternids and sampleids) can be filled in before or after the RixRNG constructor call.  For example by looping over sample points:

for (int pt = 0; pt < numPts; pt++) 

...

 These fancy constructors are convenient when the number (and order) of shading points in the new RixRNG matches the shading points in the parent RNG.  If the number (or order) is different, then the sample contexts in the new RixRNG has to be initialized individually – as in the following example.

Example:  Here is an example where a sampleCtxArray is allocated, a RixRNG is constructed, and the RixRNG's sampleCtxArray is initialized by by looping over shading points:

Code Block
  SampleCtx* samplectxarray = new SampleCtx[numPts];
  RixRNG rng(parentRNG, samplectxarray, numPts);
  for (int pt = 0; pt < numPts; pt++)
  {
    int index = shadingContext->integratorCtxIndex[pt];

...


    samplectxarray[pt] = parentRNG→NewDomainsplit(index,

...

 0x8732f9a1,

...

 4);
  }

Here the scramble bit-pattern is 0x8732f9a1 and the splitting factor is 4.

Tips for using samples in practice

This section contains a few practical tips for how to use the samples returned by the RixRNG API functions.

Mapping samples

The samples returned by the DrawSample2D() etc functions are in the unit square.  It is often necessary to map from the unit square to other domains.  

Example..  Example: uniform sampling a disk.  

Code Block
  RtPoint2 sample =

...

 rng->DrawSample2D(i);
  float radius = sqrt(sample.x);

...


  float phi = 2 * M_PI * sample.y;
  point.x = radius * cos(phi);
  point.y = radius * sin(sample.x);


When to use splitting and when not.

Shirley remapping

Example remap.  Example: Select a light source and then a position on that light source.  Figure  

get 3D sample and use z to select light and (x,y) for position.

Figure of samples before and after remapping?  

Splitting

Intuition:  intuition: 1 cam ray x 4 diff rays should give same diffuse directions as 4 cam rays x 1 diff ray.  Figure?

Uniform random samples

Non-stratified samples similar to e.g. drand48(): HashToRandom() computes a repeatable random float between 0 and 1 given two unsigned inputs.  Repeatable, and no multi-threaded contention (drand48() has notoriously bad locking, hampering multi-treaded performance).

...