Page tree

Versions Compared

Key

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

In order to render images with as low noise and as fast convergence as possible, it is important to use samples that do not clump and do not leave large parts of the sampling domain empty.  We call such samples well stratified.

Image Added  Image Added

Left: 256 random 2D samples.  Right: 256 well-stratified 2D samples.

There  There are several different ways of generating well-stratified samples; RenderMan uses lookups in pre-generated tables of progressive multi-jittered (PMJ) sample sequences which are suitable for progressive rendering and are stratified in 1D, 2D, and 3D.  The 1D sample values are between 0 and 1, the 2D samples are on the unit square, and the 3D samples are in the unit cube.  (Practical tips on how to map to other domains are mentioned below.)

...

This ensures that you will get consecutive samples from a single sample sequence, with 'newnsamples' samples for each iteration.  I.e. you will get the exact same samples values as if you had shot 'newnsamples' as many camera rays and only 1 sample at each camera hit.  In the NewDomainSplit() function, there is a line with the following: newd.sampleid *= newnsamples.  That means skipping ahead in the sequence by the splitting branching factor 'newnsamples', thereby ensuring that the combined samples are consecutive and non-overlapping.

TO DO: FIGURE OF TRAJECTORY SPLITTING 

Image Added  Image Added

Left: no trajectory splitting (8 camera rays with 1 reflection ray each).  Right: trajectory splitting (2 camera rays with 4 reflection rays each).  Note that the 8 reflection directions are the same in both cases.

There are also similar functions in the RixRNG class that can fill in new domains (patternids) for an There are also similar functions in the RixRNG class that can fill in new domains (patternids) for an entire array of sample contexts (RixRNG sampleCtxArray).

...

Code Block
  RtFloat2 sample = rng->DrawSample2D(i);
  float r = radius * sqrt(sample.x);
  float angle = 2 * M_PI * sample.y;
  point.x = r * cos(angle);
  point.y = r * sin(angle);;
  point.y = r * sin(angle);

Other common mappings map samples to the surface of a sphere, hemisphere, or cylinder, map samples to directions proportional to a glossy bxdf lobe, and so on.

Shirley remapping

We often need samples that to combine a selection between sub-domains and generation of positions (or directions) on one of those sub-domains.  For example: select a light source and a generate a sample position on that light source, or select a Bxdf bxdf lobe and generate a sample direction proportional to that lobe.  

One way to do that is to get a 3D sample and use the z coordinate to choose the sub-domain, and the xy coordinates to select the position (or direction) in that sub-domain.  When  This can be a fine way to do this when the samples are well stratified in 3D and their xy coordinates are well stratified in 2D this can be a fine way to do this.

A common – equally good – alternative is called "Shirley remapping".  It does not rely on 3D stratification.  Instead, get a 2D sample and first use one of the coordinates of the sample to select the sub-domain, and then map the sample within that selected domain (based on the probability) back to the unit square domain.  A figure provides a more intuitive explanation:

...

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

When TO DO?:  When to use splitting and when not.

...

For more (very nerdy!) details about the properties of PMJ samples please refer to the following paper:

  "Progressive multi-jittered sample sequences",

  Per Christensen, Andrew Kensler, and Charlie Kilpatrick,

  Computer Graphics Forum (Proceedings of the Eurographics Symposium on Rendering), 37(4):21-33, 2018.

Paper and presentation slides are available here:  graphics graphics.pixar.com/library/ProgressiveMultijitteredSampling