diff --git a/src/sensors/distant.cpp b/src/sensors/distant.cpp index ab095da88..303643ae9 100644 --- a/src/sensors/distant.cpp +++ b/src/sensors/distant.cpp @@ -31,7 +31,7 @@ Distant radiancemeter sensor (:monosp:`distant`) * - direction - |vector| - Alternative (and exclusive) to ``to_world``. Direction orienting the - sensor's reference hemisphere. + sensor. * - target - |point| or nested :paramtype:`shape` plugin - *Optional.* Define the ray target sampling strategy. @@ -241,6 +241,48 @@ class DistantSensorImpl final : public Sensor { return { ray, ray_weight & active }; } + Spectrum eval(const SurfaceInteraction3f & /*si*/, + Mask /*active*/) const override { + return 0.f; + } + + std::pair + sample_direction(const Interaction3f &it, const Point2f & /*sample*/, + Mask active) const override { + MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleDirection, active); + + Vector3f d = m_to_world.value().transform_affine(Vector3f(0.f, 0.f, 1.f)); + Float dist = 2.f * m_bsphere.radius + math::RayEpsilon; + + DirectionSample3f ds = ek::zero(); + ds.p = it.p - d * dist; + ds.n = d; + ds.uv = Point2f(0.f); + ds.time = it.time; + ds.pdf = 1.f; + ds.delta = true; + ds.d = -d; + ds.dist = dist; + // ds.emitter = this; + // TODO: --^ must be fixed as soon as SurfaceInteraction3f is fit for + // sensor sampling + + SurfaceInteraction3f si = ek::zero(); + si.wavelengths = it.wavelengths; + + // No need to divide by the PDF here (always equal to 1.f) + // Note: Must be updated if a sensor response function is added to this plugin + UnpolarizedSpectrum spec = 1.f; + + return { ds, spec & active }; + } + + Float pdf_direction(const Interaction3f & /*it*/, + const DirectionSample3f & /*ds*/, + Mask /*active*/) const override { + return 0.f; + } + // This sensor does not occupy any particular region of space, return an // invalid bounding box ScalarBoundingBox3f bbox() const override { return ScalarBoundingBox3f(); } @@ -248,13 +290,13 @@ class DistantSensorImpl final : public Sensor { std::string to_string() const override { std::ostringstream oss; oss << "DistantSensor[" << std::endl - << " to_world = " << m_to_world << "," << std::endl - << " film = " << m_film << "," << std::endl; + << " to_world = " << string::indent(m_to_world) << "," << std::endl + << " film = " << string::indent(m_film) << "," << std::endl; if constexpr (TargetType == RayTargetType::Point) oss << " target = " << m_target_point << std::endl; else if constexpr (TargetType == RayTargetType::Shape) - oss << " target = " << m_target_shape << std::endl; + oss << " target = " << string::indent(m_target_shape) << std::endl; else // if constexpr (TargetType == RayTargetType::None) oss << " target = none" << std::endl; diff --git a/src/sensors/tests/test_distant.py b/src/sensors/tests/test_distant.py index 4411064cd..f85460081 100644 --- a/src/sensors/tests/test_distant.py +++ b/src/sensors/tests/test_distant.py @@ -80,7 +80,6 @@ def test_construct(variant_scalar_rgb): sensor = make_sensor(sensor_dict(direction=direction)) result = sensor.world_transform().matrix assert ek.allclose(result, expected) - # Couldn't get ek.allclose() to work here # Test different combinations of target and origin values # -- No target @@ -310,6 +309,31 @@ def test_sample_target(variant_scalar_rgb, sensor_setup, w_e, w_o): assert np.allclose(result, expected_value, rtol=rtol_value) +def test_sample_direction(variants_vec_rgb): + from mitsuba.render import SurfaceInteraction3f + from mitsuba.core import ScalarVector3f + + direction = ScalarVector3f([1, 1, 1]) + sensor = make_sensor(sensor_dict(direction=direction)) + + it = ek.zero(SurfaceInteraction3f, 3) + # Some positions inside the unit sphere + it.p = [[-0.5, 0.3, -0.1], [0.8, -0.3, -0.2], [-0.2, 0.6, -0.6]] + it.time = 1.0 + + # Sample sensor direction + samples = [[0.4, 0.5, 0.3], [0.1, 0.4, 0.9]] + ds, res = sensor.sample_direction(it, samples) + + assert ek.allclose(ds.pdf, 1.0) + assert ek.allclose(ds.d, -ek.normalize(direction)) + assert ek.allclose(sensor.pdf_direction(it, ds), 0.0) + assert ek.allclose(ds.time, it.time) + + # Check spectrum + assert ek.allclose(res, 1.0) + + def test_checkerboard(variants_all_rgb): """ Very basic render test with checkerboard texture and square target. @@ -317,7 +341,7 @@ def test_checkerboard(variants_all_rgb): from mitsuba.core import ScalarTransform4f from mitsuba.core.xml import load_dict - l_o = 1.0 + l_e = 1.0 # Emitted radiance rho0 = 0.5 rho1 = 1.0 @@ -339,7 +363,7 @@ def test_checkerboard(variants_all_rgb): "emitter": { "type": "directional", "direction": [0, 0, -1], - "irradiance": 1.0 + "irradiance": l_e }, "sensor0": { "type": "distant", @@ -386,5 +410,5 @@ def test_checkerboard(variants_all_rgb): scene = load_dict(scene_dict) data = np.array(scene.render()) - expected = l_o * 0.5 * (rho0 + rho1) / ek.Pi + expected = l_e * 0.5 * (rho0 + rho1) / ek.Pi assert np.allclose(data, expected, atol=1e-3)