Skip to content

Commit

Permalink
Added distant sensor plugin
Browse files Browse the repository at this point in the history
Co-authored-by: Sebastian Schunke <[email protected]>
  • Loading branch information
leroyvn and schunkes committed May 20, 2020
1 parent c3d2bbb commit 351c258
Show file tree
Hide file tree
Showing 4 changed files with 415 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/librender/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ MTS_VARIANT Scene<Float, Spectrum>::Scene(const Properties &props) {
// Create emitters' shapes (environment luminaires)
for (Emitter *emitter: m_emitters)
emitter->set_scene(this);

// Create sensors' shapes (environment sensors)
for (Sensor *sensor: m_sensors)
sensor->set_scene(this);
}

MTS_VARIANT Scene<Float, Spectrum>::~Scene() {
Expand Down
1 change: 1 addition & 0 deletions src/sensors/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_plugin(perspective perspective.cpp)
add_plugin(radiancemeter radiancemeter.cpp)
add_plugin(thinlens thinlens.cpp)
add_plugin(irradiancemeter irradiancemeter.cpp)
add_plugin(distant distant.cpp)

# Register the test directory
add_tests(${CMAKE_CURRENT_SOURCE_DIR}/tests)
191 changes: 191 additions & 0 deletions src/sensors/distant.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#include <mitsuba/core/bbox.h>
#include <mitsuba/core/bsphere.h>
#include <mitsuba/core/math.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/core/transform.h>
#include <mitsuba/core/warp.h>
#include <mitsuba/render/scene.h>
#include <mitsuba/render/sensor.h>

NAMESPACE_BEGIN(mitsuba)

/**!
.. _sensor-distant:
Distant directional sensor (:monosp:`distant`)
----------------------------------------------
.. pluginparameters::
* - to_world
- |transform|
- Sensor-to-world transformation matrix.
* - direction
- |vector|
- Alternative (and exclusive) to `to_world`. Direction from which the
sensor will be recording in world coordinates.
* - target
- |point|
- *Optional.* Point (in world coordinates) to which sampled rays will be
cast. Useful for one-dimensional scenes. If unset, rays will be cast
uniformly over the entire scene.
This sensor plugin implements a distant directional sensor which records
radiation leaving the scene in a given direction. If the ``target`` parameter
is not set, rays cast by the sensor will be distributed uniformly on the cross
section of the scene's bounding sphere.
*/

MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
public:
MTS_IMPORT_BASE(Sensor, m_world_transform, m_needs_sample_3, m_film)
MTS_IMPORT_TYPES(Scene)

DistantSensor(const Properties &props) : Base(props) {
/* Until `set_scene` is called, we have no information
about the scene and default to the unit bounding sphere. */
m_bsphere = ScalarBoundingSphere3f(ScalarPoint3f(0.f), 1.f);

if (props.has_property("direction")) {
if (props.has_property("to_world"))
Throw("Only one of the parameters 'direction' and 'to_world' "
"can be specified at the same time!'");

ScalarVector3f direction(normalize(props.vector3f("direction")));
auto [up, unused] = coordinate_system(direction);

m_world_transform =
new AnimatedTransform(ScalarTransform4f::look_at(
ScalarPoint3f(0.0f), ScalarPoint3f(direction), up));
}

if (props.has_property("target")) {
m_target = props.point3f("target");
m_has_target = true;
Log(Debug, "Targeting point %s", m_target);
} else {
m_has_target = false;
}

if (m_film->size() != ScalarPoint2i(1, 1))
Throw("This sensor only supports films of size 1x1 Pixels!");

if (m_film->reconstruction_filter()->radius() >
0.5f + math::RayEpsilon<Float>)
Log(Warn, "This sensor should be used with a reconstruction filter "
"with a radius of 0.5 or lower (e.g. default box)");

m_needs_sample_3 = false;
}

void set_scene(const Scene *scene) override {
m_bsphere = scene->bbox().bounding_sphere();
m_bsphere.radius =
max(math::RayEpsilon<Float>,
m_bsphere.radius * (1.f + math::RayEpsilon<Float>) );
}

std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
const Point2f &spatial_sample,
const Point2f & /*direction_sample*/,
Mask active) const override {
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
Ray3f ray;
ray.time = time;

// 1. Sample spectrum
auto [wavelengths, wav_weight] =
sample_wavelength<Float, Spectrum>(wavelength_sample);
ray.wavelengths = wavelengths;

// 2. Set ray direction
auto trafo = m_world_transform->eval(time, active);
ray.d = trafo.transform_affine(Vector3f{ 0.f, 0.f, 1.f });

// 3. Sample ray origin
if (!m_has_target) {
// If no target point is defined, sample a target point on the
// bounding sphere's cross section
Point2f offset =
warp::square_to_uniform_disk_concentric(spatial_sample);
Vector3f perp_offset =
trafo.transform_affine(Vector3f{ offset.x(), offset.y(), 0.f });
ray.o = m_bsphere.center + (perp_offset - ray.d) * m_bsphere.radius;
} else {
ray.o = m_target - 2.f * ray.d * m_bsphere.radius;
}

ray.update();
return std::make_pair(
ray, m_has_target
? wav_weight
: wav_weight * (math::Pi<Float> * sqr(m_bsphere.radius)));
}

std::pair<RayDifferential3f, Spectrum> sample_ray_differential(
Float time, Float wavelength_sample, const Point2f &spatial_sample,
const Point2f & /*direction_sample*/, Mask active) const override {
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
RayDifferential3f ray;
ray.time = time;

// 1. Sample spectrum
auto [wavelengths, wav_weight] =
sample_wavelength<Float, Spectrum>(wavelength_sample);
ray.wavelengths = wavelengths;

// 2. Set ray direction
auto trafo = m_world_transform->eval(time, active);
ray.d = trafo.transform_affine(Vector3f{ 0.f, 0.f, 1.f });

// 3. Sample ray origin
if (!m_has_target) {
// If no target point is defined, sample a target point on the
// bounding sphere's cross section
Point2f offset =
warp::square_to_uniform_disk_concentric(spatial_sample);
Vector3f perp_offset =
trafo.transform_affine(Vector3f{ offset.x(), offset.y(), 0.f });
ray.o = m_bsphere.center + (perp_offset - ray.d) * m_bsphere.radius;
} else {
ray.o = m_target - 2.f * ray.d * m_bsphere.radius;
}

// 4. Set differentials; since the film size is always 1x1, we don't
// have differentials
ray.has_differentials = false;

ray.update();
return std::make_pair(
ray, m_has_target
? wav_weight
: wav_weight * (math::Pi<Float> * sqr(m_bsphere.radius)));
}

/// This sensor does not occupy any particular region of space, return an
/// invalid bounding box
ScalarBoundingBox3f bbox() const override { return ScalarBoundingBox3f(); }

std::string to_string() const override {
std::ostringstream oss;
oss << "DistantSensor[" << std::endl
<< " world_transform = " << m_world_transform << "," << std::endl
<< " bsphere = " << m_bsphere << "," << std::endl
<< " film = " << m_film << "," << std::endl
<< "]";
return oss.str();
}

MTS_DECLARE_CLASS()

protected:
ScalarBoundingSphere3f m_bsphere;
ScalarPoint3f m_target;
bool m_has_target;
};

MTS_IMPLEMENT_CLASS_VARIANT(DistantSensor, Sensor)
MTS_EXPORT_PLUGIN(DistantSensor, "DistantSensor");
NAMESPACE_END(mitsuba)
Loading

0 comments on commit 351c258

Please sign in to comment.