diff --git a/src/python/python/ad/integrators/common.py b/src/python/python/ad/integrators/common.py index 195e6b807..65067b7a1 100644 --- a/src/python/python/ad/integrators/common.py +++ b/src/python/python/ad/integrators/common.py @@ -1138,9 +1138,12 @@ def render_primarily_visible_silhouette(self, block = film.create_block(normalize=True) block.set_coalesce(block.coalesce() and spp >= 4) block.put( - pos=sensor_ds.uv, + pos=sensor_ds.uv + mi.ScalarPoint2f(block.offset()), wavelengths=wavelengths, - value=derivative * dr.rcp(mi.ScalarFloat(spp)), + # Boundary samples are not tied to pixels: normalize by their + # count and the pixel area, not by `spp` + value=derivative * (dr.prod(film.crop_size()) / + mi.ScalarFloat(sampler.wavefront_size())), weight=0, alpha=1, active=active @@ -1246,14 +1249,16 @@ def render_indirect_silhouette(self, scene, sensor, sample, sampler, preprocess=False) active = dr.any(value != 0) - # Account for the guiding sampling density and spp - value *= rcp_pdf_guiding * dr.rcp(spp) + # Account for the guiding density, the sample count and the + # pixel area + value *= rcp_pdf_guiding * (dr.prod(film.crop_size()) / + mi.ScalarFloat(sampler.wavefront_size())) # Splat the result to the film block = film.create_block(normalize=True) block.set_coalesce(block.coalesce() and spp >= 4) block.put( - pos=sensor_uv, + pos=sensor_uv + mi.ScalarPoint2f(block.offset()), wavelengths=wavelengths, value=value, weight=0, diff --git a/src/python/python/ad/projective.py b/src/python/python/ad/projective.py index 4c8b6fede..2e312082c 100644 --- a/src/python/python/ad/projective.py +++ b/src/python/python/ad/projective.py @@ -175,7 +175,17 @@ def eval_primary_silhouette_radiance_difference(self, it = dr.zeros(mi.Interaction3f) it.p = ss.p ds, _ = sensor.sample_direction(it, mi.Point2f(0), active) - visible &= ds.pdf != 0 + film = sensor.film() + if film.sample_border(): + # The filter reaches past the crop window, so points just + # outside of it still contribute + border = film.rfilter().border_size() + size = mi.ScalarVector2f(film.crop_size()) + in_front = (to_world.inverse() @ ss.p).z > 0 + visible &= in_front & dr.all((ds.uv >= -border) & + (ds.uv <= size + border)) + else: + visible &= ds.pdf != 0 # Sample wavelengths wavelength_sample = 0