Part IV · Path tracing · Chapter 15
Two ways to the light
Chapter 14 found light by aiming at it: pick a point on a lamp and send a shadow ray. Chapter 13 found it by chance: bounce the way the surface scatters, and see whether the bounce meets a lamp. Each is good where the other is bad. Multiple importance sampling uses both at once and weighs every answer by how good its way was at finding it, so the picture gets the best of each.
1Each way fails somewhere
Four plates, from nearly a mirror (top row, σ 0.02) to quite rough (bottom row, σ 0.6), and four lamps over them, from tiny to long, each giving off the same total light (a short lamp is brighter for its size; the ticks under each lamp show the side it glows from). A glossy plate reflects light mostly near its mirror direction; σ is how far its reflection spreads around it, as an angle in radians (0.02 is about 1°, 0.6 about 34°). The camera sees each lamp reflected somewhere along each plate: the tiny lamp near the left end, the long one near the right. The plate is a line seen from the side, so each strip below is one plate, left to right, and each column of a strip is one point of it.
Every point's light is estimated three ways, from the same random numbers. The lamp strategy (left column) picks a point on a lamp and looks whether the plate reflects its light to the camera: this is chapter 14's next-event estimation, NEE. The plate strategy (middle) picks a direction the way the plate itself reflects, and looks whether it meets a lamp: chapter 13's bounce, called BSDF sampling after the BSDF, the formula for how a surface reflects. The right column uses both, weighed. All three are estimates of the same picture and settle on it in the end; they differ in how fast. After 8 samples the three differ a lot. Point at a strip to read that point's estimate, its error bar and the exact answer.
After 256 samples, look at where each is still streaked. The lamp strategy is noisy on the sharp plates, worst under the long lamp: a point picked anywhere on it is almost never in the narrow range of directions the plate reflects. The plate strategy is noisy on the rough plates, worst under the tiny lamp: a direction drawn from a wide spread almost never meets it. Each is smooth where the other is streaked. Both, weighed is smooth everywhere: the readout's error bars are 13% and 12% of the light for the two alone, 6% with MIS.
The mathsTwo estimates of one sum
The light a plate point sends to the camera adds up the light arriving from every direction, each weighed by how much of it the plate sends on to the camera. Pick one direction ω at random, and either strategy gives an estimate of that whole sum:
f(ω) cos θ Le(ω)plamp(ω) or f(ω) cos θ Le(ω)pplate(ω)
- f(ω)
- how much of the light from ω the plate reflects towards the camera (its BSDF)
- cos θ
- the slant the light arrives at, as in chapter 1
- Le(ω)
- the brightness of the lamp seen along ω (0 where no lamp is)
- plamp
- how likely the lamp strategy is to give direction ω, per radian
- pplate
- how likely the plate strategy is to give it
Dividing by p is chapter 12's rule: a direction picked often must count for little each time, one picked rarely for a lot, so that on average every direction counts once (a probability density). An estimate is noisy where its p is small but the light is not: a rare direction carrying a lot, divided by a tiny p, a bright streak in the picture.
Why weights that add up to 1 count each direction once: over many samples the lamp strategy brings back the whole of a direction's light, on average, and so does the plate strategy. Counted in full, both together would count it twice. Multiply the lamp strategy's samples by wlamp(ω) and the plate strategy's by wplate(ω), and on average they bring back (wlamp + wplate) times it: once, exactly, when the two add up to 1. Each sample is weighed at its own direction, with both densities there: a lamp sample at ω₁ by plamp(ω₁) and pplate(ω₁), a plate sample at ω₂ by the same two at ω₂.
Any weights that add up to 1 would be fair. The power heuristic squares the densities:
wlamp = plamp²plamp² + pplate², wplate = pplate²plamp² + pplate²
The squares lean harder towards the likelier strategy than the plain ratio would, so a direction only one strategy was likely to find counts almost entirely through it; Veach found the squares usually the least noisy of the recipes he tried (his chapter 9). With the second figure's numbers, 5.86 against 0.66: 5.86² = 34.3, 0.66² = 0.44, and 34.3 / 34.7 = 0.99, where the plain ratio would give 5.86 / 6.52 = 0.90.
That is also why the streaks go. A streak is a rare, lucky find by the weak strategy: a direction its p makes unlikely, divided by that small p. In that same direction the other strategy's p is large, so the lucky find is multiplied by a weight near 0, and its light comes in instead, steadily, through the strategy that finds it often.
2Who is good at what
At one point of one plate, the top plot shows how likely each strategy is to pick each direction, on a log scale (each mark up is ten times the one below, so a density a thousand times smaller still shows). The lamps' density is a hump for each lamp seen from here, named above it, taller where a lamp looks smaller from here (a short lamp, or a far one seen edge-on); a lamp more than 80° away is off the plot. The plate's is a bell around its mirror direction. The bottom plot shows the weights MIS gives each. On the rough plate under the tiny lamp, the plate's bell is low and wide and the lamp's hump is tall: the tiny lamp's light counts almost entirely through the lamp strategy (weight 0.99, the narrow orange spike in the bottom plot). Elsewhere the plate's weight is 1, but there is no lamp there (shaded): no light arrives from those directions, so their weights count nothing. Only the stretches under a lamp matter.
On the sharp plate under the long lamp, the plate's bell is a narrow spike far above the long lamp's low hump, and the weights turn round: in the mirror direction, the plate's way counts entirely. Move the point along the plate and change the plate, and watch the weights follow whichever density is higher. Where no lamp lies and the sharp plate's bell has fallen to almost nothing, both weights read 0: neither strategy would ever pick that direction, so there is nothing to weigh (the code's guard against dividing 0 by 0 gives 0 there). Point at the curves to read them.
3How ShadyTracer does it
The weight is one function:
The lamp side: when a shadow ray is aimed, the material is asked how much it reflects that way (lobesEval,
the maths' f) and how likely its own sampling was to pick it (lobesPdf, the maths'
pplate), and the shadow ray carries the weighted contribution:
The plate side's weight is worked out at the bounce, when the direction is chosen, but used later: whether the
ray meets a light is only known when it arrives, maybe many rounds later. So the weight is computed here and
carried on the ray. This part is for the sun and the sky; chapter 16 does the same for glowing surfaces, with the
density kept as prevPdf:
4Tricks and trade-offs
Each is stamped with how it is known; point at a stamp to see what it means.
Only against a way that could have found it. A direction the lamp strategy could never pick (below the surface, or a perfect mirror's single direction, which aiming cannot hit) keeps weight 1: weighing it against a density of zero would be right. Weighing it against the lamp strategy's density where that should be zero but is not gives it a weight below 1, and the lamp strategy never makes up the rest: light lost (the glass ball, in section 5).
Both must estimate the same thing. MIS is unbiased only if the two strategies multiply in the
same material. In the first run of the glowing-surface lights (on the user's NVIDIA Ampere card,
roadmap/PLAN.md, "Emissive surfaces as lights"), the lamp strategy evaluated its own approximation
of the material while the bounce sampled the real one. A setting decides what share of shadow rays go to
glowing surfaces, and the picture's brightness moved with it: −1.2% with no shadow rays at all, −0.9% at a share
of 0.2, 0 at 0.5 (the default, which the others are measured against), +0.5% at 0.9. The share is a factor of
the lamp strategy's density (a direction is picked only if a shadow ray goes that way at all), so a bigger share
means a bigger plamp and a bigger weight: when the two estimate different things, the mix
of them moves with the share. Which row was right, the document does not say; with no shadow rays only the
bounce counts, with the real material, so that row is the likelier one (inferred), and the default read about
1% too bright. With the lamp strategy asking the material the bounce samples, the second run's rows all agreed within
0.25%. The code now says so beside the call: "what the sampler samples".
5What went wrong before
- A glass ball with a plain shadow. Under the sun a glass ball should cast a shadow with a
bright spot in it, the sun focused through the glass (a caustic, chapter 18). The light
that makes the spot comes the long way round: a path from the camera reaches the floor in the shadow, bounces up
into the ball, and leaves it on the far side, refracted towards the sun. At that last point, on the ball's
surface, "above the surface" means the side the ray came from, and the lamp strategy only ever aims there; the
refracted ray goes through, to the other side. Yet it was weighed against the lamp strategy, whose density the
sun's cone gave as not zero. And the plate
side's own density was 0: clear glass refracts into one single direction, which a density spread over directions
cannot describe, so the code counts it as 0. Its weight came out 0² / (0² + plamp²) = 0; the lamp
strategy never produced it either; so the sun through glass was counted by neither, and a glass ball cast a plain
dark shadow (the comment above
prevPdf). - Glossy plastic lit by chance. A perfectly smooth coat used to be given a density of 10⁹, a stand-in for "a single direction". That number went into the plate side's density for the whole material, coat and matte base together, so a shadow ray to the sun from the base was weighed plamp² / (plamp² + (10⁹)²), which is 0: aiming counted nothing for the base, and a glossy plastic in sunlight was lit only by bounces that happened to find the sun (the comment on delta events).
- Two estimates of two things: the brightness that moved with the shadow rays' share, above.
6Try it
- In the second figure, find the plate and point where the two weights are equal in the mirror direction.
- Which plate would you choose to show off the lamp strategy, and which the plate strategy?
- In ShadyTracer, turn on Developer in the Render settings and switch Next-Event Estimation (the lamp strategy) off and on in a scene with a glossy floor under a large light. Where does the noise move?