Skip to content

Yocto/Sampling: Sampling routines

Yocto/Sampling provides many functions to generate points and directions useful in path tracing and procedural generation. We also include a random number generator suitable for ray tracing.

Random number generation

Yocto/Sampling includes an implementation of the PCG32 random number generator, that is a portable generator well suited for graphics applications. The state of the generator is stored in rng_state and uses only 16 bytes. The generator is default-initialized to be able to provide random numbers as is. You can use make_rng(seed,seq) to initialize a generator with a given seed and byt selecting a specific random sequence. See PCG32 for a discussion. If you do not need to select a sequence, just use the default value.

Use rand1f(rng), rand2f(rng), rand3f(rng) and rand4f(rng) to generate random 1-4 dimensional float vectors with coordinates in [0,1). Use rand1i(rng,n) to generate a random integer in the [0,n) range. Use shuffle(sequence, rng) to randomly shuffle a sequence.

auto rng = make_rng(172784);                   // seed the generator
auto r1 = rand1f(rng); auto r2 = rand2f(rng);  // 1-2 dim. random numbers
auto r3 = rand3f(rng); auto r4 = rand4f(rng);  // 3-4 dim. random numbers
auto ri = rand1i(rng,10);                      // random int in [0,10)
auto vec = std::vector<float>{...};
shuffle(vec, rng);                             // random shuffle of a vector

Generating points and directions

Yocto/Sampling defines several functions to generate random points and directions. Each of these functions is a warp that takes random numbers in the [0,1) domain and warps them to the desired distributions. The functions are particularly useful in procedural modeling and path tracing. For each function, Yocto/Sampling provides both the warp as well as its pdf, that can be used in Monte Carlo integration.

Yocto/Sampling supports generating directions uniformly over the unit hemisphere and sphere, or cosine distributed over the hemisphere, using respectively sample_hemisphere(ruv), sample_sphere(ruv), sample_hemisphere_cos(ruv) sample_hemisphere_cos(ruv) and sample_hemisphere_cos(ruv). For each of these functions, the corresponding sample_<distribution>_pdf(dir) computes the pdf that the given direction was chosen.

auto rng = make_rng(172784);               // seed the generator
auto rhu = sample_hemisphere(rand2f(rng)); // random hemispherical direction
auto phu = sample_hemisphere_pdf(rand2f(rng)); // direction pdf
auto rhc = sample_hemisphere_cos(rand2f(rng)); // cos-distributed direction
auto rsu = sample_sphere(rand2f(rng));     // random spherical direction
auto rhu2 = sample_hemisphere(normal,rand2f(rng));     // oriented hemisphere
auto rhc2 = sample_hemisphere_cos(normal,rand2f(rng)); // oriented hemisphere

Yocto/Sampling supports generating points uniformly on geometric primitives. Use sample_disk(uv) to uniformly sample a disk and sample_triangle(uv) to uniformly sample a triangle. For triangles we also support direct sampling of triangle points with sample_triangle(p0,p1,p2,ruv). by warping random numbers from the unit square to
uniformly over the unit hemisphere and sphere, or cosine distributed over the hemisphere, using respectively sample_hemisphere(ruv), sample_sphere(ruv), sample_hemisphere_cos(ruv) sample_hemisphere_cos(ruv) and sample_hemisphere_cos(ruv). For each of these functions, the corresponding sample_<distribution>_pdf(dir) computes the pdf that the given direction was chosen.

auto rng = make_rng(172784);               // seed the generator
auto sdu = sample_disk(rand2f(rng));       // uniform uv on disk
auto stu = sample_triangle(rand2f(rng));   // uniform uv on triangle
auto stp = sample_triangle(p0,p1,p2,rand2f(rng));   // uniform triangle point

Sampling distributions

Yocto/Sampling defines several functions to sample distributions. Each of these functions is a warp that takes a random number in the [0,1) domain and warps it to the desired distribution. For each function, Yocto/Sampling provides both the warp as well as its pdf, that can be used in Monte Carlo integration.

Use sample_uniform(n,r) to randomly pick an index in the [0,n) range, sample_uniform(elems,r) to randomly pick an element from a sequence, sample_discrete_cdf(cdf,r) to pick an index from a discrete distribution that has CDF cdf and sample_discrete_weights(w,r) to pick an index from a discrete distribution with probability equal to the weights array. For discrete distribution, sample_discrete_cdf() is significantly faster when computing many samples.

auto rng = make_rng(172784);                 // seed the generator
auto idx = sample_uniform(num,rand1f(rng));  // uniform index
auto& elem = sample_uniform(elems,rand1f(rng));  // uniform element
auto prob = std::vector<float>{0.3,0.3,0.4};  // probability distribution
auto pidx = sample_discrete_weights(prob,rand1f(rng)); // index with prob
auto ppidx = sample_discrete_weights_pdf(prob,pidx);   // index pdf
auto cdf = std::vector<float>{prob.size()};
for(auto i : range(prob.size())               // compute cdf
  cdf[i] = prob[i] + (i ? cdf[i-1] : 0);
auto cidx = sample_discrete_cdf(cdf,rand1f(rng)); // index with cdf
auto pcidx = sample_discrete_cdf_pdf(cdf,cidx);   // index pdf