13.4 A Better Path Tracer
- The direct lighting calculation is performed by sampling both the BSDF and the sampled light source and weighting both samples using multiple importance sampling. This approach can substantially reduce variance compared to sampling the light alone.
- Any LightSampler can be used, which makes it possible to use effective light sampling algorithms like the one implemented in BVHLightSampler to choose lights.
- It initializes the VisibleSurface when it is provided, giving geometric information about the first intersection point to Film implementations like GBufferFilm.
- Russian roulette is used to terminate paths, which can significantly boost the integrator’s efficiency.
- A technique known as path regularization can be applied in order to reduce variance from difficult-to-sample paths.
While these additions make its implementation more complex, they also substantially improve efficiency; see Figure 13.7 for a comparison of the two.
The most important of these differences is how the direct lighting calculation is performed. In the SimplePathIntegrator, a light was chosen with uniform probability and then that light sampled a direction; the corresponding estimator was given by Equation (13.9). More generally, the path contribution estimator can be expressed in terms of an arbitrary directional probability distribution , which gives
It may seem that using only a sampling PDF that matches the factor to sample these directions, as done by the SimplePathIntegrator, would be a good strategy; after all, the radiance can then be expected to be nonzero for the sampled direction. If we instead drew samples using the BSDF’s sampling distribution, we might choose directions that did not intersect a light source at all, finding no emitted radiance after incurring the expense of tracing a ray in the hope of intersecting a light.
However, there are cases where sampling the BSDF can be the more effective strategy. For a very smooth surface, the BSDF is nonzero for a small set of directions. Sampling the light source will be unlikely to find directions that have a significant effect on scattering from the surface, especially if the light source is large and close by. Even worse, when such a light sample happens to lie in the BSDF lobe, an estimate with large magnitude will be the result due to the combination of a high contribution from the numerator and a small value for the PDF in the denominator. The estimator has high variance.
Figure 13.8 shows a variety of cases where each of these sampling methods is much better than the other. In this scene, four rectangular surfaces ranging from very smooth (top) to very rough (bottom) are illuminated by spherical light sources of decreasing size. Figures 13.8(a) and (b) show the BSDF and light sampling strategies on their own. As the example illustrates, sampling the BSDF is much more effective when it takes on large values on a narrow set of directions that is much smaller than the set of directions that would be obtained by sampling the light sources. This case is most visible in the top left reflection of a large light source in a low-roughness surface. On the other hand, sampling the light sources can be considerably more effective in the opposite case—when the light source is small and the BSDF lobe is less concentrated (this case is most visible in the bottom right reflection).
Taking a single sample with each sampling technique and averaging the estimators would be of limited benefit. The resulting estimator would still have high variance in cases where one of the sampling strategies was ineffective and that strategy happened to sample a direction with nonzero contribution.
This situation is therefore a natural for the application of multiple importance sampling—we have multiple sampling techniques, each of which is sometimes effective and sometimes not. That approach is used in the PathIntegrator with one light sample and one BSDF sample , giving the estimator
where the surface intersection points corresponding to the two sampled directions are respectively denoted and and each term includes a corresponding multiple importance sampling (MIS) weight or that can be computed, for example, using the balance heuristic from Equation (2.14) or the power heuristic from Equation (2.15). Figure 13.8(c) shows the effectiveness of combining these two sampling techniques with multiple importance sampling.
With that context established, we can start the implementation of the PathIntegrator. It is another RayIntegrator.
Three member variables affect the PathIntegrator’s operation: a maximum path depth; the lightSampler used to sample a light source; and regularize, which controls whether path regularization is used.
The form of the Li() method is similar to SimplePathIntegrator::Li().
The L, beta, and depth variables play the same role as the corresponding variables did in the SimplePathIntegrator.
Also similarly, each iteration of the while loop traces a ray to find its closest intersection and its BSDF. Note that a number of code fragments from the SimplePathIntegrator are reused here and in what follows to define the body of the while loop. The loop continues until either the maximum path length is reached or the path is terminated via Russian roulette.
We will defer discussing the implementation of the first fragment used below, <<Add emitted light at intersection point or from the environment>>, until later in this section after more details of the implementation of the MIS direct lighting calculation have been introduced.
If the Film being used takes a VisibleSurface, then a non-nullptr VisibleSurface * is passed to the Li() method. It is initialized at the first intersection.
The only quantity that is not immediately available from the SurfaceInteraction is the albedo of the surface, which is computed here as the hemispherical-directional reflectance, Equation (4.12). Recall that the BSDF::rho() method estimates this value using Monte Carlo integration. Here, a set of 16 precomputed Owen-scrambled Halton points in arrays ucRho and uRho, not included in the text, are used for the estimate.
The use of Monte Carlo with this many samples is somewhat unsatisfying. The computed albedo is most commonly used for image-space denoising algorithms after rendering; most of these start by dividing the final color at each pixel by the first visible surface’s albedo in order to approximate the incident illumination alone. It is therefore important that the albedo value itself not have very much error. However, the albedo can be computed analytically for some BSDFs (e.g., the ideal Lambertian BRDF). In those cases, executing both the BSDF sampling and evaluation algorithms repeatedly is wasteful. An exercise at the end of the chapter discusses this matter further.
The next task is to sample a light source to find a direction to use to estimate the first term of Equation (13.10). However, if the BSDF is purely specular, there is no reason to do this work, since the value of the BSDF for a sampled point on a light will certainly be zero.
Although SampleLd() is only called once and thus could be expanded inline in the Li() method, there are multiple points along the way where it may return early. We therefore prefer a function here, as it avoids deeply nested if statements that would be needed otherwise.
If the surface is purely reflective or purely transmissive, then the reference point used for sampling pi is shifted slightly so that it lies on the side of the surface from which the outgoing ray will leave the intersection point toward the light. Doing so helps avoid a subtle error that is the result of the combination of floating-point round-off error in the computed intersection point and a ray that intersects an emitter that does not have a completely absorbing BSDF. The problem is illustrated in Figure 13.9.
Next, the LightSampler selects a light. One thing to note in the implementation here is that two more dimensions are consumed from the Sampler even if the LightSampler does not return a valid light. This is done in order to keep the allocation of Sampler dimensions consistent across all the pixel samples. (Recall the discussion of this issue in Section 8.3.)
Sampling a direction with the light proceeds using Light::SampleLi(), though here a true value is passed for its allowIncompletePDF parameter. Because we will use a second sampling technique, BSDF sampling, for the estimator in Equation (13.10), and that technique has nonzero probability of sampling all directions where the integrand is nonzero, the light sampling distribution may not include directions where the light’s emission is relatively low. (The motivation for this was discussed in Section 2.2.3 in the context of MIS compensation.)
Given a light sample, it is worth checking for various cases that require no further processing here. As an example, consider a spotlight where the intersection point is outside of its emission cone; the LightLiSample will have a zero radiance value in that case. It is worthwhile to find that there is no incident radiance before incurring the cost of evaluating the BSDF.
A shadow ray is only traced if the BSDF for the sampled direction is nonzero. It is not unusual for the BSDF to be zero here: for example, given a surface that is reflective but not transmissive, any sampled direction that is on the other side of the surface than the incident ray will have zero contribution.
The light sample’s contribution can now be computed; recall that the returned value corresponds to the first term of Equation (13.10), save for the factor. The case of a light that is described by a delta distribution receives special treatment here; recall from Section 12.1 that in that case there is an implied delta distribution in the emitted radiance value returned from SampleLi() as well as the PDF and that they cancel out when the estimator is evaluated. Further, BSDF sampling is unable to generate a light sample and therefore we must not try to apply multiple importance sampling but should evaluate the standard estimator, Equation (13.9), instead. If we do not have a delta distribution light source, then the value of the BSDF’s PDF for sampling the direction is found by calling BSDF::PDF() and the MIS weight is computed using the power heuristic. (See Figure 13.10 for a comparison between the balance heuristic and power heuristic for this computation.)
Returning now to the Li() method implementation, the next step is to sample the BSDF at the intersection to get an outgoing direction for the next ray to trace. That ray will be used to sample indirect illumination as well as for the BSDF sample for the direct lighting estimator.
In addition to the path throughput weight beta, a number of additional values related to the path are maintained, as follows:
- p_b is the PDF for sampling the direction bs->wi; this value is needed for the MIS-based direct lighting estimate. One nit comes from BSDFs like the LayeredBxDF that return a BSDFSample where the f and pdf are only proportional to their true values. In that case, an explicit call to BSDF::PDF() is required to get an estimate of the true PDF.
- As in the SimplePathIntegrator, specularBounce tracks whether the last scattering event was from a perfect specular surface.
- anyNonSpecularBounces tracks whether any scattering event along the ray’s path has been non-perfect specular. This value is used for path regularization if it is enabled.
- etaScale is the accumulated product of scaling factors that have been applied to beta due to rays being transmitted between media of different indices of refraction—a detail that is discussed in Section 9.5.2. This value will be used in the Russian roulette computation.
- Finally, prevIntrCtx stores geometric information about the intersection point from which the sampled ray is leaving. This value is also used in the MIS computation for direct lighting.
The new ray will account for indirect illumination at the intersection point in the following execution of the while loop.
Returning now to the <<Add emitted light at intersection point or from the environment>> fragment at the start of the loop, we can see how the ray from the previous iteration of the while loop can take care of the BSDF sample in Equation (13.10). The ray’s direction was chosen by sampling the BSDF, and so if it happens to hit a light source, then we have everything we need to evaluate the second term of the estimate other than the MIS weight . If the ray does not hit a light source, then that term is zero for the BSDF sample and there is no further work to do.
There are two cases to handle: infinite lights for rays that do not intersect any geometry, and surface emission for rays that do. In the first case, the ray path can terminate once lights have been considered.
For the initial ray from the camera or after a perfect specular scattering event, emitted radiance should be included in the path without any MIS weighting, since light sampling was not performed at the previous vertex of the path. At this point in execution, beta already includes the BSDF, cosine factor, and PDF value from the previous scattering event, so multiplying beta by the emitted radiance gives the correct contribution.
Otherwise, it is necessary to compute the MIS weight . p_b gives us the BSDF’s PDF from the previous scattering event, so all we need is the PDF for the ray’s direction from sampling the light. This value is given by the product of the probability of sampling the light under consideration times the probability the light returns for sampling the direction.
Note that the PDF_Li() method is passed a true value for allowIncompletePDF here, again reflecting the fact that because BSDF sampling is capable of sampling all valid directions, it is not required that light sampling do so as well.
The code for the case of a ray hitting an emissive surface is in the fragment <<Incorporate emission from surface hit by ray>>. It is almost the same as the infinite light case, so we will not include it here.
The final issue is Russian roulette–based path termination. As outlined in Section 13.2.1, the task is easy: we compute a termination probability however we like, make a random choice as to whether to terminate the path, and update beta if the path is not terminated so that all subsequent terms will be scaled appropriately.
However, the details of how is set can make a big difference. In general, it is a good idea for the termination probability to be based on the path throughput weight; in this way, if the BSDF’s value is small, it is more likely that the path will be terminated. Further, if the path is not terminated, then the scaling factor will generally cause beta to have a value around 1. Thus, all rays that are traced tend to make the same contribution to the image, which improves efficiency.
Another issue is that it is best if the beta value used to compute does not include radiance scaling due to refraction. Consider a ray that passes through a glass object with a relative index of refraction of 1.5: when it enters the object, beta will pick up a factor of , but when it exits, that factor will cancel and beta will be back to 1. For ray paths that would exit, to have terminated them after the first refraction would be the wrong decision. Therefore, etaScale tracks those factors in beta so that they can be removed. The image in Figure 13.11 shows the increase in noise if this effect is not corrected for.
Finally, note that the termination probability is set according to the maximum component value of rrBeta rather than, for example, its average. Doing so gives better results when surface reflectances are highly saturated and some of the wavelength samples have much lower beta values than others, since it prevents any of the beta components from going above 1 due to Russian roulette.
Recall that Russian roulette only increases variance. Because it terminates some paths, this must be so, as the final image includes less information when it is applied. However, it can improve efficiency by allowing the renderer to focus its efforts on tracing rays that make the greatest contribution to the final image. Table 13.1 presents measurements of efficiency improvements from Russian roulette for a number of scenes.
|Kroken (Figure 13.4)|
|Watercolor (Figure 13.6)|
|San Miguel (Figure 13.7)|
|BMW M6 (Figure 13.12)|
13.4.1 Path Regularization
Scenes with concentrated indirect lighting can pose a challenge to the path-tracing algorithm: the problem is that if the incident indirect radiance at a point has substantial variation but BSDF sampling is being used to generate the direction of indirect rays, then the sampling distribution may be a poor match for the integrand. Variance spikes then occur when the ratio in the Monte Carlo estimator is large.
Figure 13.12 shows an example of this issue. The car is illuminated by a sky environment map where a bright sun occupies a small number of pixels. Consider sampling indirect lighting at a point on the ground near one of the wheels: the ground material is fairly diffuse, so any direction will be sampled with equal (cosine-weighted) probability. Rarely, a direction will be sampled that both hits the highly specular wheel and then also reflects to a direction where the sun is visible. This is the cause of the bright pixels on the ground. (The lighting in the car interior is similarly difficult to sample, since the glass prevents light source sampling; the variance spikes there follow.)
Informally, the idea behind path regularization is to blur the function being integrated in the case that it cannot be sampled effectively (or cannot be sampled in the first place). See Figure 13.13, which shows the same scene, but with all the BSDFs made more rough: perfect specular surfaces are glossy specular, and glossy specular surfaces are more diffuse. Although the overall characteristics of the image are quite different, the high variance on the ground has been eliminated: when an indirect lighting ray hits one of the wheels, it is now possible to use a lower variance MIS-based direct lighting calculation in place of following whichever direction is dictated by the law of specular reflection.
Blurring all the BSDFs in this way is an undesirable solution, but there is no need to do so for the camera rays or for rays that have only undergone perfect specular scattering: in those cases, we would like to leave the scene as it was specified. We can consider non-specular scattering itself to be a sort of blurring of the incident light, such that blurring the scene that is encountered after it occurs is less likely to be objectionable—thus the motivation to track this case via the anyNonSpecularBounces variable.
The BSDF class provides a Regularize() method that forwards the request on to its BxDF.
The BxDF interface in turn requires the implementation of a Regularize() method. For BxDFs that are already fairly broad (e.g., the DiffuseBxDF), the corresponding method implementation is empty.
However, both the DielectricBxDF and ConductorBxDF can be nearly specular or perfect specular, depending on how smooth their microfacet distribution is. Therefore, their Regularize() method implementations do adjust their scattering properties, through a call to yet one more method named Regularize(), this one implemented by the TrowbridgeReitzDistribution.
Unless the surface is already fairly rough, the TrowbridgeReitzDistribution’s Regularize() method doubles the parameters and then clamps them—to ensure both that perfect specular surfaces with a roughness of zero become non-perfect specular and that surfaces are not excessively roughened.