Previously, environment maps could only be intersected via random BSDF ray bouncing. In scenes where the environment is the primary light source (like a sunset or studio HDRI), this leads to extreme variance because rays rarely hit the small, bright regions (like the sun) by chance. This feature implements Importance Sampling for the environment map. By constructing a probability distribution based on the map's texture, the renderer can explicitly target bright directions, treating the infinite environment as a physically based area light.
Distribution Construction:
The core of the implementation involves creating `Distribution1D` and `Distribution2D` classes, heavily inspired by PBRT. These classes transform the environment texture into a Probability Density Function (PDF). The weight of each pixel is determined by its photometric luminance \(Y\):
\[ Y = 0.2126 R + 0.7152 G + 0.0722 B \]
I construct a 2D distribution by first computing 1D marginal distributions for the columns (vertical) and then conditional distributions for the rows (horizontal). This allows us to sample a pixel coordinate \((u,v)\) proportional to its energy contribution.
Compensated Distribution:
To further optimize sampling, I implemented an optional "compensated" strategy. This computes the average luminance of the entire map and culls pixels falling below this threshold from the sampling pool. This forces the integrator to focus exclusively on the highest-energy regions.
Integration:
I extended the EnvMap class to implement the sampleDirect interface, allowing it to be chosen by the Next Event Estimation logic. I also implemented pdfDirect, which queries the 2D distribution to return the correct solid-angle PDF for Multiple Importance Sampling.
Improved Environment Sampling with Compensated Distribution
BSDF Sampling only (Extreme noise)
The biggest challenge was implementing the distribution functions from scratch following the PBRT methodology. While the concepts were not overly difficult, the actual implementation process was time-consuming.
I also encountered a specific issue where the compensated distribution produced very dark spots, which was particularly noticeable in the sunset scene. However, this artifact was fully resolved once I implemented and integrated Multiple Importance Sampling (MIS).
To reduce variance and improve convergence speed compared to standard Monte Carlo integration, I implemented low-discrepancy (Quasi-Monte Carlo) sampling using Halton sequences. Unlike independent random numbers which can clump together, low-discrepancy sequences strictly minimize gaps in the sample space.
The core of the Halton sequence is the Radical Inverse function \(\Phi_b(n)\), which mirrors the digits of index \(n\) in base \(b\) around the decimal point:
\[ \Phi_b(n) = \sum_{j=0}^{\infty} a_j(n) b^{-j-1} \]
where \(a_j(n)\) are the digits of \(n\) in base \(b\). A \(d\)-dimensional Halton point is then constructed using the first \(d\) prime numbers as bases:
\[ x_n = (\Phi_{2}(n), \Phi_{3}(n), \dots, \Phi_{p_d}(n)) \]
To eliminate the structural correlations often visible in high-dimensional Halton sequences, I additionally implemented Owen Scrambling, which randomizes the digits \(a_j(n)\) while preserving the sequence's low-discrepancy properties.
Halton Sampler:
I implemented a new HaltonSampler class based on the PBRT implementation, adapting the mathematical helpers for the radical inverse and permutation scrambling to the framework.
Dimension Tracking & Strides:
The critical challenge is ensuring that specific dimensions of the sampler are consistently mapped to specific decisions in the path tracer. If dimensions shift (e.g., the dimension used for light sampling on bounce 2 becomes the dimension for BSDF sampling on bounce 3), bias and artifacts occur.
To solve this, I modified mispathtracer.cpp to enforce a strided dimension layout. I defined fixed dimension budgets for every bounce:
Hybrid Fallback Strategy:
To handle geometric operations that consume a variable and unpredictable number of samples (such as alpha masking loops or volume intersections), I implemented a hybrid strategy.
These specific samples are offset to extremely high dimension indices where the sampler may even fall back to uncorrelated "independent" random sampling (when the dimensions go above 1000).
This ensures that the unpredictable sample count of geometry queries never desynchronizes the stratified samples used for shading.
Halton Sampling with no randomizer
Independent Random Sampling (Standard)
The primary hurdle was simply understanding and implementing the number theory behind the radical inverse and Owen scrambling as presented in the PBRT literature.
The technical difficulty lay in integrating a rigid, strided sampler with operations that use an indeterminate number of random samples, such as alpha masking and volume traversals during intersection and transmittance steps. Because these operations can consume an arbitrary amount of numbers before returning, they would desynchronize the dimension counter for all subsequent lighting calculations along the path. Attempting to pad the strides was ineffective, as it simply increased the variance for the more important operations. The only working solution was to strictly isolate these "unpredictable" intersection samples into their own high-dimensional block.