Skip to content

Commit e9ad277

Browse files
leroyvnschunkes
andcommitted
Added distant sensor plugin
Co-authored-by: Sebastian Schunke <[email protected]>
1 parent abf6938 commit e9ad277

File tree

4 files changed

+415
-0
lines changed

4 files changed

+415
-0
lines changed

src/librender/scene.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ MTS_VARIANT Scene<Float, Spectrum>::Scene(const Properties &props) {
9696
// Create emitters' shapes (environment luminaires)
9797
for (Emitter *emitter: m_emitters)
9898
emitter->set_scene(this);
99+
100+
// Create sensors' shapes (environment sensors)
101+
for (Sensor *sensor: m_sensors)
102+
sensor->set_scene(this);
99103
}
100104

101105
MTS_VARIANT Scene<Float, Spectrum>::~Scene() {

src/sensors/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_plugin(perspective perspective.cpp)
44
add_plugin(radiancemeter radiancemeter.cpp)
55
add_plugin(thinlens thinlens.cpp)
66
add_plugin(irradiancemeter irradiancemeter.cpp)
7+
add_plugin(distant distant.cpp)
78

89
# Register the test directory
910
add_tests(${CMAKE_CURRENT_SOURCE_DIR}/tests)

src/sensors/distant.cpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include <mitsuba/core/bbox.h>
2+
#include <mitsuba/core/bsphere.h>
3+
#include <mitsuba/core/math.h>
4+
#include <mitsuba/core/properties.h>
5+
#include <mitsuba/core/transform.h>
6+
#include <mitsuba/core/warp.h>
7+
#include <mitsuba/render/scene.h>
8+
#include <mitsuba/render/sensor.h>
9+
10+
NAMESPACE_BEGIN(mitsuba)
11+
12+
/**!
13+
14+
.. _sensor-distant:
15+
16+
Distant directional sensor (:monosp:`distant`)
17+
----------------------------------------------
18+
19+
.. pluginparameters::
20+
21+
* - to_world
22+
- |transform|
23+
- Sensor-to-world transformation matrix.
24+
* - direction
25+
- |vector|
26+
- Alternative (and exclusive) to `to_world`. Direction from which the
27+
sensor will be recording in world coordinates.
28+
* - target
29+
- |point|
30+
- *Optional.* Point (in world coordinates) to which sampled rays will be
31+
cast. Useful for one-dimensional scenes. If unset, rays will be cast
32+
uniformly over the entire scene.
33+
34+
This sensor plugin implements a distant directional sensor which records
35+
radiation leaving the scene in a given direction. If the ``target`` parameter
36+
is not set, rays cast by the sensor will be distributed uniformly on the cross
37+
section of the scene's bounding sphere.
38+
39+
*/
40+
41+
MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
42+
public:
43+
MTS_IMPORT_BASE(Sensor, m_world_transform, m_needs_sample_3, m_film)
44+
MTS_IMPORT_TYPES(Scene)
45+
46+
DistantSensor(const Properties &props) : Base(props) {
47+
/* Until `set_scene` is called, we have no information
48+
about the scene and default to the unit bounding sphere. */
49+
m_bsphere = ScalarBoundingSphere3f(ScalarPoint3f(0.f), 1.f);
50+
51+
if (props.has_property("direction")) {
52+
if (props.has_property("to_world"))
53+
Throw("Only one of the parameters 'direction' and 'to_world' "
54+
"can be specified at the same time!'");
55+
56+
ScalarVector3f direction(normalize(props.vector3f("direction")));
57+
auto [up, unused] = coordinate_system(direction);
58+
59+
m_world_transform =
60+
new AnimatedTransform(ScalarTransform4f::look_at(
61+
ScalarPoint3f(0.0f), ScalarPoint3f(direction), up));
62+
}
63+
64+
if (props.has_property("target")) {
65+
m_target = props.point3f("target");
66+
m_has_target = true;
67+
Log(Debug, "Targeting point %s", m_target);
68+
} else {
69+
m_has_target = false;
70+
}
71+
72+
if (m_film->size() != ScalarPoint2i(1, 1))
73+
Throw("This sensor only supports films of size 1x1 Pixels!");
74+
75+
if (m_film->reconstruction_filter()->radius() >
76+
0.5f + math::RayEpsilon<Float>)
77+
Log(Warn, "This sensor should be used with a reconstruction filter "
78+
"with a radius of 0.5 or lower (e.g. default box)");
79+
80+
m_needs_sample_3 = false;
81+
}
82+
83+
void set_scene(const Scene *scene) override {
84+
m_bsphere = scene->bbox().bounding_sphere();
85+
m_bsphere.radius =
86+
max(math::RayEpsilon<Float>,
87+
m_bsphere.radius * (1.f + math::RayEpsilon<Float>) );
88+
}
89+
90+
std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
91+
const Point2f &spatial_sample,
92+
const Point2f & /*direction_sample*/,
93+
Mask active) const override {
94+
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
95+
Ray3f ray;
96+
ray.time = time;
97+
98+
// 1. Sample spectrum
99+
auto [wavelengths, wav_weight] =
100+
sample_wavelength<Float, Spectrum>(wavelength_sample);
101+
ray.wavelengths = wavelengths;
102+
103+
// 2. Set ray direction
104+
auto trafo = m_world_transform->eval(time, active);
105+
ray.d = trafo.transform_affine(Vector3f{ 0.f, 0.f, 1.f });
106+
107+
// 3. Sample ray origin
108+
if (!m_has_target) {
109+
// If no target point is defined, sample a target point on the
110+
// bounding sphere's cross section
111+
Point2f offset =
112+
warp::square_to_uniform_disk_concentric(spatial_sample);
113+
Vector3f perp_offset =
114+
trafo.transform_affine(Vector3f{ offset.x(), offset.y(), 0.f });
115+
ray.o = m_bsphere.center + (perp_offset - ray.d) * m_bsphere.radius;
116+
} else {
117+
ray.o = m_target - 2.f * ray.d * m_bsphere.radius;
118+
}
119+
120+
ray.update();
121+
return std::make_pair(
122+
ray, m_has_target
123+
? wav_weight
124+
: wav_weight * (math::Pi<Float> * sqr(m_bsphere.radius)));
125+
}
126+
127+
std::pair<RayDifferential3f, Spectrum> sample_ray_differential(
128+
Float time, Float wavelength_sample, const Point2f &spatial_sample,
129+
const Point2f & /*direction_sample*/, Mask active) const override {
130+
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
131+
RayDifferential3f ray;
132+
ray.time = time;
133+
134+
// 1. Sample spectrum
135+
auto [wavelengths, wav_weight] =
136+
sample_wavelength<Float, Spectrum>(wavelength_sample);
137+
ray.wavelengths = wavelengths;
138+
139+
// 2. Set ray direction
140+
auto trafo = m_world_transform->eval(time, active);
141+
ray.d = trafo.transform_affine(Vector3f{ 0.f, 0.f, 1.f });
142+
143+
// 3. Sample ray origin
144+
if (!m_has_target) {
145+
// If no target point is defined, sample a target point on the
146+
// bounding sphere's cross section
147+
Point2f offset =
148+
warp::square_to_uniform_disk_concentric(spatial_sample);
149+
Vector3f perp_offset =
150+
trafo.transform_affine(Vector3f{ offset.x(), offset.y(), 0.f });
151+
ray.o = m_bsphere.center + (perp_offset - ray.d) * m_bsphere.radius;
152+
} else {
153+
ray.o = m_target - 2.f * ray.d * m_bsphere.radius;
154+
}
155+
156+
// 4. Set differentials; since the film size is always 1x1, we don't
157+
// have differentials
158+
ray.has_differentials = false;
159+
160+
ray.update();
161+
return std::make_pair(
162+
ray, m_has_target
163+
? wav_weight
164+
: wav_weight * (math::Pi<Float> * sqr(m_bsphere.radius)));
165+
}
166+
167+
/// This sensor does not occupy any particular region of space, return an
168+
/// invalid bounding box
169+
ScalarBoundingBox3f bbox() const override { return ScalarBoundingBox3f(); }
170+
171+
std::string to_string() const override {
172+
std::ostringstream oss;
173+
oss << "DistantSensor[" << std::endl
174+
<< " world_transform = " << m_world_transform << "," << std::endl
175+
<< " bsphere = " << m_bsphere << "," << std::endl
176+
<< " film = " << m_film << "," << std::endl
177+
<< "]";
178+
return oss.str();
179+
}
180+
181+
MTS_DECLARE_CLASS()
182+
183+
protected:
184+
ScalarBoundingSphere3f m_bsphere;
185+
ScalarPoint3f m_target;
186+
bool m_has_target;
187+
};
188+
189+
MTS_IMPLEMENT_CLASS_VARIANT(DistantSensor, Sensor)
190+
MTS_EXPORT_PLUGIN(DistantSensor, "DistantSensor");
191+
NAMESPACE_END(mitsuba)

0 commit comments

Comments
 (0)