PLTFalcor icon indicating copy to clipboard operation
PLTFalcor copied to clipboard

Question Regarding Path Weight Update Order in `scatterTriangleMeshClosestHit` Shader

Open LorenzoMauro opened this issue 11 months ago • 1 comments
trafficstars

Hello!

I've been studying your work on Physical Light Transport and, more recently, this implementation. Thank you for sharing it with the community.

I'm encountering a potential issue with the order in which path.weight is updated relative to appending bounces in the scatterTriangleMeshClosestHit shader. This affects the weighting of bounce contributions during Next Event Estimation (NEE) and emissive evaluations.

Current Implementation:

In the scatterTriangleMeshClosestHit function, the path weight is updated after BSDF sampling and before appending the bounce:

// BSDF sampling and generate a new ray direction.
BSDFSample bsdfSample;
if (!shouldEndPath) {
    // BSDF sampling logic...
}

// Update path weight, thp, and pdf
path.weight *= bsdfSample.weight;
path.thp_modifier *= rcp_thp;
path.pdf *= bsdfSample.pdf;

// Append bounce
appendBounce(path, hitInfo, wi, bsdfSample.lobe);
++path.length;

https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_sample.rt.slang#L130

Understanding of the Implementation:

  • appendBounce registers the path contribution as the bounce contribution.
  • This bounce contribution is used in the solve step to weigh the sample's contribution.
  • In the solve functions, during path traversal, the current bounce p is passed to NEE() and evalEmissive():
    • https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_solve.rt.slang#L421
    • https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_solve.rt.slang#L441
    • https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_solve.rt.slang#L446
  • The bounce contribution used is that of bounce p:
    • For NEE: https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_solve.rt.slang#L242
    • For evalEmissive: https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_solve.rt.slang#L197

Issue Description:

Because path.weight is updated before appending the bounce, the bounce's contribution already includes the bsdfSample.pdf of the next direction. This inclusion seems incorrect because the bsdfSample.pdf relates to the sampling of the next direction, not the current one. As a result, during NEE and emissive evaluations at the current bounce, the contributions are weighted by an unrelated probability, potentially leading to inaccurate results.

Expected Behavior:

The bounce contribution used during NEE and emissive evaluations should not include the new direction's bsdfSample.pdf, as it pertains to the next path segment, not the current one.

Observed Behavior:

  • In a simple scene with a sun analytic light and spheres with different materials (roughness set to 1.0):
    • Setting maxBounces to 0 triggers shouldEndPath, skipping the multiplication by bsdfSample.pdf: https://github.com/ssteinberg/PLTFalcor/blob/6c58971d1f8f031eb61ce8fd93e4ffddbe963e85/Source/RenderPasses/PLTPT/pltpt_sample.rt.slang#L114
    • The resulting output is extremely dim.
    • Increasing maxBounces to 1 includes the multiplication, and the result is noticeably brighter.
    • Image Illustrating the Issue: Rendering Issue

Theoretical Concern:

Multiplying the contribution by bsdfSample.pdf results in an estimator that divides by an unrelated probability( $p_b(x_{3,i} | x_1)$ ), which should be incorrect. The estimator for Direct Light Sampling under NEE would effectively become:

$$ L' = \frac{1}{N} \sum_{i=1}^{N} \frac{L_e(x_{2,i} \rightarrow x_1) \cdot f(x_1, \omega_1, \omega_{2,i}) \cdot G(x_1 \leftrightarrow x_{2,i}) \cdot V(x_1, x_{2,i})}{p_l(x_{2,i} | x_1) \cdot p_b(x_{3,i} | x_1)} \frac{p_l(x_{2,i} | x_1)}{p_l(x_{2,i} | x_1) + p_b(x_{2,i} | x_1)} $$

with

  • $p_l(x | x_1)$ the probability of sampling $x$ given $x_1$ under direct light sampling
  • $p_b(x | x_1)$ the probability of sampling $x$ given $x_1$ under bsdf sampling

This suggests that the bsdfSample.pdf of a different direction influences the current bounce's contribution.

Question:

  • Is there a specific reason for updating path.weight before appending the bounce, resulting in the inclusion of bsdfSample.pdf in the current bounce's contribution?
  • Could updating path.weight after appending the bounce be more appropriate to ensure that only relevant probabilities influence the current bounce's contribution during NEE and emissive evaluations?
  • If updating path.weight after appending the bounce is more appropriate to exclude the unrelated bsdfSample.pdf, why does this change result in the image appearing so dim? Is there an aspect of the implementation or theory I'm missing that could explain this behavior?

Thank you very much for your assistance. I appreciate any insights you can give me.

LorenzoMauro avatar Dec 03 '24 14:12 LorenzoMauro

That's likely wrong. Not sure why it was done so. Thanks for noticing. This project is not maintained, but I will leave this open in case anyone else stumbles upon this.

ssteinberg avatar Feb 17 '25 02:02 ssteinberg