This article covers the estimator change in the second part of commit 7cbd9f9. Candidate scoring may omit shadow rays, but the retained candidate must be evaluated with visibility before its contribution is returned.

The material below is specific to delaying visibility inside the HdRestir RIS and reservoir estimators; the linked references supply only the sampling and light-interface prerequisites.

Estimator and target

For a direct-light sample \(z\), write the contribution as

\[f(z)=V(z)\,g(z),\]

where \(g\) is the unoccluded emission–BSDF–geometry contribution and \(V\in\{0,1\}\) is visibility. RIS may use the cheaper scalar target \(\hat p(z)\approx\lVert g(z)\rVert\), select \(Y\), and evaluate visibility once:

\[\widehat I = V(Y)g(Y)\frac{S}{M\hat p(Y)}.\]
Proof Deferring visibility until after RIS selection preserves the expectation

Assumptions: The proposal covers visible contribution, the unoccluded target is finite and positive wherever visible contribution is non-zero, the candidate weight sum is positive, and visibility is evaluated for the retained sample in the receiving context.

Conditioned on candidates \(X_{1:M}\), selection probability is \(w_i/S\), where \(w_i=\hat p(X_i)/q(X_i)\). Therefore

\[\begin{aligned} \mathbb E[\widehat I\mid X_{1:M}] &=\sum_i \frac{w_i}{S} V(X_i)g(X_i)\frac{S}{M\hat p(X_i)}\\ &=\frac1M\sum_i\frac{V(X_i)g(X_i)}{q(X_i)}. \end{aligned}\]

Taking the outer expectation gives \(\int V(z)g(z)\,dz\). Visibility need not be part of the selection target, but it must remain in the final contribution.

If visibility is omitted from both scoring and final evaluation, the estimator integrates unoccluded lighting instead. If stored visibility is reused in a different shading context without validation, the same substitution can occur across frames.

Cost and variance

Let \(M\) be the candidate count and \(C_s\) the cost of one shadow ray. Testing every candidate costs approximately \(M C_s\). Testing only the winner costs approximately \(C_s\), plus winner re-evaluation. The visibility work saved is close to

\[(M-1)C_s,\]

provided that candidate generation does not perform equivalent intersection work elsewhere.

This cost expression does not predict variance. In an open scene, \(\lVert g\rVert\) can be a useful predictor of \(\lVert Vg\rVert\). In a heavily occluded scene, RIS can repeatedly select a high-target candidate that becomes zero after the final shadow ray. The estimator remains unbiased under the stated assumptions, but its variance can increase.

Commit contents Files discussed in this chapter ris_direct_light_integrator.cpp · restir_render_settings.cpp · RenderSetup.usda
Complete commit diff ↗

Candidate scoring without a shadow ray

The exact skip branch in _evaluateLightSample is:

if (skipVisibility)
    return MISContrib{.Emission         = RGBToSpectrum(ls.Color, surface.lambda),
                      .ThroughputMul    = RGBToSpectrum(bsdfValue * nDotL, surface.lambda),
                      .PNee             = pNee,
                      .PBsdf            = pBsdf,
                      .UseMis           = useMis,
                      .VisibilityTested = false};

Emission, BSDF, cosine, and both proposal densities remain present. VisibilityTested = false records the missing operation as data rather than leaving it implicit in control flow. The target later uses the luminance of this unoccluded spectral contribution.

The non-reservoir winner

After weighted selection, the ordinary RIS branch checks the flag:

SampledSpectrum winnerThroughput{chosenCandidate.Throughput};

// ...

if (!chosenCandidate.VisibilityTested && chosenCandidate.Candidate.has_value())
{
    const LightCandidate &lc{*chosenCandidate.Candidate};
    const MISContrib      nee{_evaluateLightSample(isect, *lc.Light, lc.Ls, scene, /*skipVisibility=*/false)};
    winnerThroughput = nee.Emission * nee.ThroughputMul;
}

return winnerThroughput * W;

Passing false forces the full light evaluation, including the shadow ray. The returned winnerThroughput therefore contains \(V(Y)g(Y)\), and W contains the RIS normalization derived above.

The reservoir winner

The persistent branch performs the same obligation before storing the current reservoir:

if (finalized.ChosenSample.has_value() && !finalized.ChosenSample->VisibilityTested &&
    finalized.ChosenSample->Candidate.has_value())
{
    RISLightCandidate    &winner{*finalized.ChosenSample};
    const LightCandidate &lc{*winner.Candidate};
    const MISContrib      nee{_evaluateLightSample(isect, *lc.Light, lc.Ls, scene,
                                                   /*skipVisibility=*/false)};
    winner.Throughput       = nee.Emission * nee.ThroughputMul;
    winner.VisibilityTested = true;
}

The stored sample is marked as tested for the context in which it was finalized. That flag alone does not make the visibility valid in a later receiving context. At this revision, temporal merging still accepts stored visibility more broadly than the final GPU implementation. The history limitations described in step 2 therefore remain relevant.

For a finite light, re-evaluation reconnects the retained light sample to the current surface and traces toward its endpoint. For an environment, the retained direction defines the visibility ray. The contribution, PDF, target, and visibility test must refer to compatible geometric interpretations.

Convergence curves comparing per-candidate visibility with visibility evaluated only for the retained sample
The plot compares the renderer's internal relative-noise estimate against cumulative render time. Blue (risSkipVisibility=false) pays for visibility during candidate evaluation; orange (true) defers that test until after resampling. Measurement scope: This is not reference-image error. It is one run at commit 7cbd9f9, and its interpretation depends on the scene's occlusion, candidate count, hardware, and temporal correlation. Source: deferred-visibility commit 7cbd9f9

An ordinary beauty render is deliberately omitted here: it cannot reveal whether a shadow ray was traced for every proposal or only for the retained sample. A stronger follow-up experiment would pair these curves with equal-time captures of the shadow-ray counter and hold scene, seed, candidate count, resolution, filtering, and stopping rule fixed.