You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DiskLight / RectLight with spread < 1: intersect() reports a different pdf than sample() #330
Two related problems in lib/rendering/pbr/light/DiskLight.cc and RectLight.cc (same in the ISPC versions), version 2026.29.1.
1. DiskLight: bounding box instead of the disk
Reproduce. Glossy floor (roughness 0.3) under a disk light, max_depth 1:
spread
light samples only
BSDF samples only
both
1.0
0.04509
0.04510
0.04509
0.95
0.04114
0.04116
0.04139
0.8
0.02979
0.02980
0.02997
Cause.DiskLight::sample() uses mInvArea (1 / (pi R^2)) when the whole disk lies inside the spread region (lightIsInsideSpread), and the overlap rectangle otherwise. DiskLight::intersect() always calls getOverlapBounds, which in the first case returns the 2R x 2R bounding box, so the hit pdf is 1 / (4 R^2). The MIS weights of light and BSDF samples then do not sum to one.
Fix (untested). Use the same case distinction in intersect() as in sample().
2. Reverse and two-sided lights: signed distance
Reproduce. The same floor under a light with sidedness reverse and spread 0.8:
light
light samples only
BSDF samples only
both
DiskLight
0.02980
0
0.02942
RectLight
0.03794
0
0.03725
Cause.intersect() computes float spreadLength = localP.z * mTanSpreadTheta; with the signed localP.z, which is negative on the reverse side. getOverlapBounds then finds no overlap and returns false without writing width and height; the return value is not checked and the pdf is computed from them. sample() uses the sign-corrected plane distance and is fine.
Fix (untested). Use abs(localP.z), and check the return value of getOverlapBounds.
Activity