Strategy showcases · why these samplers exist →

Implementation audit · 15 September 2026 · GPU BDPT

Make the weights real.
Keep every light splat.

The suspicion was justified: there were both correctness and performance defects. Corrected MIS helps most when the strategies have very different success rates; ordinary next-event path tracing remains the better choice for easy diffuse illumination.

Changes are confined to the working RadianceLab copy under CCC_website_AIO/offline_projs. The separate backup was not edited. Pre-change checkpoint: checkpoint/bdpt-audit-2026-09-15, revision 324513c.

What was wrong, and what changed

  1. The A balance/power choices were inert. Their routine returned flat 1/N. The menu now offers legacy flat, balance and power. Old nonflat A selections are routed to the implemented explicit-density calculation.
  2. Light splats raced each other and the eye pass. Cross-pixel imageLoad/imageStore additions were not atomic; a workgroup barrier cannot synchronize the entire image. Light contributions now enter a frame-local atomic sum. A separate resolve adds them after the eye and connection passes, followed by a separate display pass. The resolve preserves per-pixel temporal weights and tilted-camera focus overlays.
  3. The camera density used a pixel footprint where the mixture needed the whole film. Light paths are launched across the film and their splats are normalized by the total number of pixels. The old density comparison suppressed light-tracing alternatives by the pixel count.
  4. NEE and emitted photons do not use the same distribution. NEE can use weighted light selection and sphere cone/visible-hemisphere sampling; photon emission uses uniform surface-emitter selection and full-area sampling. The new calculation includes those actual distributions, plus the number of light paths per pixel. Unsupported emitter types have zero emission-sampler density.
  5. Strategy ratios could overflow and recomputed densities unnecessarily. Directional densities are evaluated once per connection, then prefix/suffix products are accumulated in log space. Delta connection splits and unavailable stored-path lengths are excluded. GGX PDF evaluation now depends on the half vector and both preimages of the existing folded sampler, rather than just the outgoing cosine.
  6. Depth budgets and roulette were inconsistent with the density model. Explicit surface BDPT now uses a common depth budget, capped at eight surface scatters, and avoids unmodelled roulette. Light walks stop at the storage limit. This is a finite-depth estimator, not an infinite-bounce claim.
  7. A failed feature combination could trigger compilation every frame. Requested and successfully compiled masks are now tracked separately. Fallback is attempted once per changed feature set, and the UI states which weighting is actually running.

What the rendered tests show

Production shaders rendered two small analytical scenes at 96 × 64. Every compared image used 256 eye samples per pixel and one light path per pixel, except the separately checked four-light-path variant. References used independent BSDF-only sampling: 8,192 spp for the diffuse scene and 16,384 spp for the mirror scene. Error is linear-RGB RMSE over visible nonemissive receivers, not the tonemapped preview.

RendererDiffuse RMSEMirror + small light RMSE
Ordinary PT with MIS0.005390.08611
Legacy flat weights, corrected accumulation0.009980.14861
Corrected balance0.005860.01897
Corrected power0.005540.01883

Easy diffuse paths

Ordinary PT is both cheaper and slightly more accurate in this test. There is little reason to enumerate many bidirectional connections when NEE already samples the important paths well.

Mirror + small light

Balance has about 7.8× lower RMSE than flat at the same spp. It is not 7.8× faster per frame: in one run the corresponding render times were approximately 245 ms versus 176 ms. The ordinary PT run was about 74 ms but substantially noisier.

These are small regression scenes, one deterministic seed schedule and noisy references—not a general performance ranking. Timings include host dispatch and readback and fluctuate with GPU load. Increasing light paths to four preserved average brightness within about 1.3% of the references, but did not improve error per unit time here. Reusing one eye path creates correlated connection estimates; more light paths are not automatically the best allocation.

Regression coverage also checks 65,536 coincident positive/negative atomic splats, independently enumerated joint-density weights, delta exclusions, direct light-camera sample counts, numerical extremes, both production kernel variants, and the eight-scatter/hemisphere-sampler case.

Missing transport is different from noisy transport

A strategy can be very unlikely to sample a path, or have zero probability of sampling it. More samples help the first case. They cannot repair the second. Coverage statements below describe the current implementation and its source/camera samplers, not universal limits of an algorithm's name.

Path or sourceWhat can sample it here?What the distinction means
Actual delta point light → glossy surface → cameraEye-side NEE, including BDPT's NEE branch.Naive BSDF rays cannot hit a zero-area source. Current LT does not emit from scene.lights[] point entries; implementing a point-source emission sampler could change this.
Small emissive sphere → surface → cameraBSDF sampling, NEE and emitted light paths.A small sphere is not a delta point light. Naive sampling has nonzero probability, but a small bright source can cause rare, high-energy samples.
Ideal specular surface next to a pinhole cameraEye paths can sample the reflection direction; a generic LT connection cannot freely choose it.The mirror imposes a delta direction constraint. Do not confuse the default glossy metal sphere with an ideal mirror. A true point source plus an ideal mirror creates an additional constrained connection problem that ordinary NEE alone does not generally solve.
Environment illuminationEye paths; now also optional environment emission in pure LT.Old LT lacked an environment source sampler. This was missing coverage, not merely poor convergence. In BDPT, sky-terminated paths still belong exclusively to the eye side.
Finite emitter → specular chain → diffuse receiver → cameraLT often samples this efficiently; naive eye paths may find it rarely.A standard example of complementary strategies. It is not a blanket promise that BDPT handles every specular configuration.

Complete coverage, exactly once: contributions from disjoint path classes can be added. When strategies overlap, their estimates need consistent measures and weights that sum to one on that path. Adding complete estimates doubles the illumination; dividing an exclusively supported path by a generic strategy count loses illumination. MIS redistributes overlap—it does not invent missing support.

How the old and enhanced guided raster methods work →

Environment LT: direction plus an entry position

Enable Emit from environment under the pure Light Tracer controls. It is off by default. The new sampler supports the existing constant/vertical-gradient sky and shares the source pool with surface emitters and the projector.

The idea of sampling only a direction works when connecting an existing surface point to the sky. To launch a light ray, we must also sample its position. This implementation chooses a uniform sphere direction and a uniform disk perpendicular to it, enclosing the finite uploaded scene. It sends parallel rays inward from that disk. The joint density is 1 / (4π²R²); the initial weight also accounts for selecting the environment from the source pool. Increasing the disk radius changes efficiency, not the expected brightness, provided it still encloses the scene.

The camera supplies only the directly visible, unscattered background. LT supplies the environment's scattered paths. The artificial disk is not a luminous surface and is never directly connected to the camera. This prevents counting the background twice.

Scope: steady-state finite analytical scenes. Unbounded geometry has no finite enclosing disk. Environment emission is suppressed while a finite flight-time gate is active, since a source at infinity has no finite emission-time origin. The toggle does not introduce environment MIS into BDPT: its eye-side environment strategy remains unchanged. Existing LT material/medium limitations still apply.

GPU regression: sky-only receiver mean was 0.12441 versus 0.12149 for the eye-path reference; sky plus a surface emitter was 0.17613 versus 0.17225. Expanding the launch radius from 8 to 12 gave 0.12455 and 0.17639 respectively. These finite-sample checks pass a 6% mean-energy tolerance; they do not certify every material. Direct background also passes a separate 1% check. Testing exposed an opaque back-face normal inconsistency in LT, now aligned with the eye tracer while preserving dielectric orientation.

Coverage is not efficiency. Uniform environment directions and disk positions can miss useful geometry or illuminate regions irrelevant to the camera. Large bounds waste launch area; dim sky directions waste directional samples. Eye-side sampling starts at a visible receiver and often handles broad environment illumination more efficiently. Light-side sampling can still help selected specular transport, so this is a limitation of the current sampler and scene, not a universal failure of LT. Larger-disk regression runs preserved brightness but had higher RMSE; this was not an equal-time performance benchmark.

This projected-disk construction follows the source-sampling approach described in PBRT’s infinite-area light model and its light-source sampling discussion.

Balance versus power: verified on the GPU

The implemented weights use qi = nipi, the complete path density multiplied by its strategy sample count. Balance normalizes q; power normalizes q². The exponent acts on the sample count as well as the density. Computation uses log densities and a common maximum subtraction for numerical stability.

Two-strategy density ratio (equal counts)Balance, first strategyPower, first strategy
1:10.500000.50000
3:10.750000.90000
9:10.900000.98780

These numbers were checked by executing the production weighting function in a GPU compute shader, alongside unequal-sample-count, delta-exclusion and extreme-density tests. Run PrismBDPTGPUTest.exe --weights-only for the focused check.

Similar images are plausible: equal densities give identical weights, an exclusively supported path gets weight one under both, and a strongly dominant strategy already gets nearly all the weight. Both target the same mean image; power changes the noise allocation, not the intended brightness. Averaging over different paths can also hide differences in individual weights. The existing mirror regression gives balance RMSE 0.01897 and power 0.01883: similar error does not mean identical weighting.

Inspect the active status. It must say Power MIS active or Balance MIS active. Medium and finite/tilted-camera configurations currently fall back to flat weights. In pyramid views, Raw deliberately ignores MIS; select Weighted or Weight only. Weight-only images are accumulated per-path diagnostics, not the weight vector for a single fixed path.

The formula matches PBRT’s multiple importance sampling definition. This verifies the heuristic and its selection path, not every experimental material’s underlying density model.

Why GPU BDPT is still expensive

For four edges, five vertices, a fixed-length path occupies one diagonal: (s,t) = (0,5), (1,4), (2,3), (3,2), (4,1). That is five candidate strategies with a pinhole camera, before excluding impossible delta connections. Across all lengths from one through four edges, this implementation has 2 + 3 + 4 + 5 = 14 candidate cells. Its directly visible emitter-to-camera cell is included; some textbook implementations omit that cell. A finite-aperture hit adds a separate t=0 family, which the corrected pinhole MIS does not claim to support.

s counts light-side vertices; t counts camera-side vertices. Colored cells are candidates, not guarantees of nonzero contribution. This diagram uses the implementation's pinhole families and stored-path limits; actual geometry, visibility, delta events and filters remove work or contributions.

Therefore the objective is lower error per second, not simply more strategies or more samples. The diffuse regression favors ordinary PT. The mirror/small-light regression benefits substantially from BDPT. Sampling a subset of connections or reallocating samples is a possible optimization, but its selection probabilities must be included in the estimator.

Why balance and power can still look similar

Both use the same strategy densities. For a strategy with density pi and sample count ni, the balance weight is nipi / ∑ njpj; power uses the squared terms. If one strategy clearly dominates, both already give it most of the weight. Equal densities also produce equal weights. Similar images are therefore not a failure by themselves.

Inspect Weighted or Weight only in the strategy pyramid. Raw deliberately removes weighting, so switching the MIS heuristic there should not change the displayed contribution.

The underlying treatment of path densities, delta events and connection strategies follows the framework explained in PBRT’s bidirectional path-tracing chapter. The implementation findings and numerical measurements above come from this local audit.

Follow-up: delta point lights

The screenshot follow-up exposed another defect outside the original surface-emitter tests. Actual scene.lights[] point sources were evaluated only by eye-side NEE, but that contribution was still multiplied by the generic flat BDPT weight. Neither the emitted surface-light paths nor BSDF-hit paths could supply the missing energy. Point-source contributions now receive weight 1, including indirect eye paths that end with point-light NEE. This does not add point-source emission to the light tracer.

The added regression isolates a delta point source with every surface emitter disabled and compares BDPT to NEE. A persistent brightness deficit in this case is a weighting error, not simply a rare-event convergence problem.

The running executable during the screenshot check was the older build/bin/Release/Prism.exe. Use Open-RadianceLab-Local.bat, which sets the working directory to the corrected build-local/bin/Release tree. The old menu's A balance [inert] entry identifies the older build.

How to compare it in the app

Use GPU BDPT, a perfect pinhole, medium disabled, LT weight 1, splat radius 0, temporal/spatial filtering off, and one light path per pixel. Select Balance or Power and check the status beneath the menu. Compare convergence at equal elapsed time as well as equal sample count. Keep the legacy flat option as a diagnostic baseline.

Remaining work is explicit

Reproduce the GPU regression

From the working RadianceLab directory:

cmake --build build-local --config Release --target PrismBDPTGPUTest --parallel 4
build-local\bin\Release\PrismBDPTGPUTest.exe

The test opens a hidden OpenGL context. Source: tests/test_bdpt_gpu.cpp and tests/bdpt_scene_check.h. Measured GPU: NVIDIA GeForce RTX 4080 Laptop GPU.