Skip to content

Commit bbcb3a4

Browse files
committed
Changed endpoint to take a 3d uniform random number instead of 2d for volume sampling. Modified every dependency accordingly and added a flag to signal when the third sample is used. Updated all tests to correctly account for the use of Point3f over Point2f.
1 parent 71322da commit bbcb3a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+239
-198
lines changed

include/mitsuba/python/docstr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,6 +2508,10 @@ static const char *__doc_mitsuba_Endpoint_needs_sample_2 =
25082508
R"doc(Does the method sample_ray() require a uniformly distributed 2D sample
25092509
for the ``sample2`` parameter?)doc";
25102510

2511+
static const char *__doc_mitsuba_Endpoint_needs_sample_2_3d =
2512+
R"doc(Does the method sample_ray() require a uniformly distributed 3D sample
2513+
for the ``sample2`` parameter?)doc";
2514+
25112515
static const char *__doc_mitsuba_Endpoint_needs_sample_3 =
25122516
R"doc(Does the method sample_ray() require a uniformly distributed 2D sample
25132517
for the ``sample3`` parameter?)doc";

include/mitsuba/render/endpoint.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,11 @@ class MI_EXPORT_LIB Endpoint : public Object {
135135
* dimension of the emission profile.
136136
*
137137
* \param sample2
138-
* A uniformly distributed sample on the domain <tt>[0,1]^2</tt>. For
139-
* sensor endpoints, this argument corresponds to the sample position in
140-
* fractional pixel coordinates relative to the crop window of the
141-
* underlying film.
138+
* A uniformly distributed sample on the domain <tt>[0,1]^2</tt> (or
139+
* <tt>[0,1]^3</tt> if needs_sample_2_3d() == true). For sensor
140+
* endpoints, this argument corresponds to the sample position in
141+
* fractional pixel coordinates relative to the crop window of
142+
* the underlying film.
142143
* This argument is ignored if <tt>needs_sample_2() == false</tt>.
143144
*
144145
* \param sample3
@@ -153,7 +154,7 @@ class MI_EXPORT_LIB Endpoint : public Object {
153154
* and the actual used sampling density function.
154155
*/
155156
virtual std::pair<Ray3f, Spectrum>
156-
sample_ray(Float time, Float sample1, const Point2f &sample2,
157+
sample_ray(Float time, Float sample1, const Point3f &sample2,
157158
const Point2f &sample3, Mask active = true) const;
158159

159160
//! @}
@@ -186,15 +187,16 @@ class MI_EXPORT_LIB Endpoint : public Object {
186187
* A reference position somewhere within the scene.
187188
*
188189
* \param sample
189-
* A uniformly distributed 2D point on the domain <tt>[0,1]^2</tt>.
190+
* A uniformly distributed 2D point on the domain <tt>[0,1]^2</tt> (
191+
* or <tt>[0,1]^3</tt> if <tt>needs_sample_2_3d() == true)</tt>.
190192
*
191193
* \return
192194
* A \ref DirectionSample instance describing the generated sample
193195
* along with a spectral importance weight.
194196
*/
195197
virtual std::pair<DirectionSample3f, Spectrum>
196198
sample_direction(const Interaction3f &ref,
197-
const Point2f &sample,
199+
const Point3f &sample,
198200
Mask active = true) const;
199201

200202
/**
@@ -273,7 +275,7 @@ class MI_EXPORT_LIB Endpoint : public Object {
273275
* along with an importance weight.
274276
*/
275277
virtual std::pair<PositionSample3f, Float>
276-
sample_position(Float time, const Point2f &sample,
278+
sample_position(Float time, const Point3f &sample,
277279
Mask active = true) const;
278280

279281
/**
@@ -325,6 +327,12 @@ class MI_EXPORT_LIB Endpoint : public Object {
325327
*/
326328
bool needs_sample_2() const { return m_needs_sample_2; }
327329

330+
/**
331+
* \brief Does the method \ref sample_ray() require a uniformly distributed
332+
* 2D or 3D sample for the \c sample2 parameter?
333+
*/
334+
bool needs_sample_2_3d() const { return m_needs_sample_2_3d; }
335+
328336
/**
329337
* \brief Does the method \ref sample_ray() require a uniformly distributed
330338
* 2D sample for the \c sample3 parameter?
@@ -398,6 +406,7 @@ class MI_EXPORT_LIB Endpoint : public Object {
398406
ref<Medium> m_medium;
399407
Shape *m_shape = nullptr;
400408
bool m_needs_sample_2 = true;
409+
bool m_needs_sample_2_3d = false;
401410
bool m_needs_sample_3 = true;
402411
std::string m_id;
403412
};

include/mitsuba/render/scene.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ class MI_EXPORT_LIB Scene : public Object {
333333
* </ul>
334334
*/
335335
std::tuple<Ray3f, Spectrum, const EmitterPtr>
336-
sample_emitter_ray(Float time, Float sample1, const Point2f &sample2,
336+
sample_emitter_ray(Float time, Float sample1, const Point3f &sample2,
337337
const Point2f &sample3, Mask active = true) const;
338338

339339
/**
@@ -377,7 +377,7 @@ class MI_EXPORT_LIB Scene : public Object {
377377
*/
378378
std::pair<DirectionSample3f, Spectrum>
379379
sample_emitter_direction(const Interaction3f &ref,
380-
const Point2f &sample,
380+
const Point3f &sample,
381381
bool test_visibility = true,
382382
Mask active = true) const;
383383

include/mitsuba/render/sensor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class MI_EXPORT_LIB Sensor : public Endpoint<Float, Spectrum> {
6161
*/
6262
virtual std::pair<RayDifferential3f, Spectrum>
6363
sample_ray_differential(Float time, Float sample1,
64-
const Point2f &sample2, const Point2f &sample3,
64+
const Point3f &sample2, const Point2f &sample3,
6565
Mask active = true) const;
6666

6767
/**

src/bsdfs/tests/test_polarizer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def spectrum_from_stokes(v):
209209
sampler.seed(0)
210210

211211
# Sample ray from sensor
212-
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5], [0.5, 0.5])
212+
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5, 0.0], [0.5, 0.5])
213213

214214
# Call integrator
215215
value, _, _ = integrator.sample(scene, sampler, ray)
@@ -311,7 +311,7 @@ def spectrum_from_stokes(v):
311311
sampler.seed(0)
312312

313313
# Sample ray from sensor
314-
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5], [0.5, 0.5])
314+
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5, 0.0], [0.5, 0.5])
315315

316316
# Call integrator
317317
value, _, _ = integrator.sample(scene, sampler, ray)

src/bsdfs/tests/test_retarder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def spectrum_from_stokes(v):
360360
sampler.seed(0)
361361

362362
# Sample ray from sensor
363-
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5], [0.5, 0.5])
363+
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5, 0.0], [0.5, 0.5])
364364

365365
# Call integrator
366366
value, _, _ = integrator.sample(scene, sampler, ray)
@@ -476,7 +476,7 @@ def spectrum_from_stokes(v):
476476
sampler.seed(0)
477477

478478
# Sample ray from sensor
479-
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5], [0.5, 0.5])
479+
ray, _ = sensor.sample_ray_differential(0.0, 0.5, [0.5, 0.5, 0.0], [0.5, 0.5])
480480

481481
# Call integrator
482482
value, _, _ = integrator.sample(scene, sampler, ray)

src/emitters/area.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ emitter shape and specify an :monosp:`area` instance as its child:
5858
template <typename Float, typename Spectrum>
5959
class AreaLight final : public Emitter<Float, Spectrum> {
6060
public:
61-
MI_IMPORT_BASE(Emitter, m_flags, m_shape, m_medium)
61+
MI_IMPORT_BASE(Emitter, m_flags, m_shape, m_medium, m_needs_sample_2_3d)
6262
MI_IMPORT_TYPES(Scene, Shape, Texture)
6363

6464
AreaLight(const Properties &props) : Base(props) {
@@ -68,6 +68,7 @@ class AreaLight final : public Emitter<Float, Spectrum> {
6868
"shape.");
6969

7070
m_radiance = props.texture_d65<Texture>("radiance", 1.f);
71+
m_needs_sample_2_3d = false;
7172

7273
m_flags = +EmitterFlags::Surface;
7374
if (m_radiance->is_spatially_varying())
@@ -90,7 +91,7 @@ class AreaLight final : public Emitter<Float, Spectrum> {
9091
}
9192

9293
std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
93-
const Point2f &sample2, const Point2f &sample3,
94+
const Point3f &sample2, const Point2f &sample3,
9495
Mask active) const override {
9596
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
9697

@@ -115,7 +116,7 @@ class AreaLight final : public Emitter<Float, Spectrum> {
115116
}
116117

117118
std::pair<DirectionSample3f, Spectrum>
118-
sample_direction(const Interaction3f &it, const Point2f &sample, Mask active) const override {
119+
sample_direction(const Interaction3f &it, const Point3f &sample, Mask active) const override {
119120
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleDirection, active);
120121
Assert(m_shape, "Can't sample from an area emitter without an associated Shape.");
121122
DirectionSample3f ds;
@@ -124,13 +125,13 @@ class AreaLight final : public Emitter<Float, Spectrum> {
124125
// One of two very different strategies is used depending on 'm_radiance'
125126
if (likely(!m_radiance->is_spatially_varying())) {
126127
// Texture is uniform, try to importance sample the shape wrt. solid angle at 'it'
127-
ds = m_shape->sample_direction(it, sample, active);
128+
ds = m_shape->sample_direction(it, Point2f(sample.x(), sample.y()), active);
128129
active &= dr::dot(ds.d, ds.n) < 0.f && dr::neq(ds.pdf, 0.f);
129130

130131
si = SurfaceInteraction3f(ds, it.wavelengths);
131132
} else {
132133
// Importance sample the texture, then map onto the shape
133-
auto [uv, pdf] = m_radiance->sample_position(sample, active);
134+
auto [uv, pdf] = m_radiance->sample_position(Point2f(sample.x(), sample.y()), active);
134135
active &= dr::neq(pdf, 0.f);
135136

136137
si = m_shape->eval_parameterization(uv, +RayFlags::All, active);
@@ -193,7 +194,7 @@ class AreaLight final : public Emitter<Float, Spectrum> {
193194
}
194195

195196
std::pair<PositionSample3f, Float>
196-
sample_position(Float time, const Point2f &sample,
197+
sample_position(Float time, const Point3f &sample,
197198
Mask active) const override {
198199
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSamplePosition, active);
199200
Assert(m_shape, "Cannot sample from an area emitter without an associated Shape.");
@@ -202,10 +203,10 @@ class AreaLight final : public Emitter<Float, Spectrum> {
202203
PositionSample3f ps;
203204
if (!m_radiance->is_spatially_varying()) {
204205
// Radiance not spatially varying, use area-based sampling of shape
205-
ps = m_shape->sample_position(time, sample, active);
206+
ps = m_shape->sample_position(time, Point2f(sample.x(), sample.y()), active);
206207
} else {
207208
// Importance sample texture
208-
auto [uv, pdf] = m_radiance->sample_position(sample, active);
209+
auto [uv, pdf] = m_radiance->sample_position(Point2f(sample.x(), sample.y()), active);
209210
active &= dr::neq(pdf, 0.f);
210211

211212
auto si = m_shape->eval_parameterization(uv, +RayFlags::All, active);

src/emitters/constant.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,12 @@ class ConstantBackgroundEmitter final : public Emitter<Float, Spectrum> {
9191
}
9292

9393
std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
94-
const Point2f &sample2, const Point2f &sample3,
94+
const Point3f &sample2, const Point2f &sample3,
9595
Mask active) const override {
9696
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
9797

9898
// 1. Sample spatial component
99-
Vector3f v0 = warp::square_to_uniform_sphere(sample2);
99+
Vector3f v0 = warp::square_to_uniform_sphere(Point2f(sample2.x(), sample2.y()));
100100
Point3f orig = dr::fmadd(v0, m_bsphere.radius, m_bsphere.center);
101101

102102
// 2. Sample diral component
@@ -114,11 +114,11 @@ class ConstantBackgroundEmitter final : public Emitter<Float, Spectrum> {
114114
}
115115

116116
std::pair<DirectionSample3f, Spectrum> sample_direction(const Interaction3f &it,
117-
const Point2f &sample,
117+
const Point3f &sample,
118118
Mask active) const override {
119119
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleDirection, active);
120120

121-
Vector3f d = warp::square_to_uniform_sphere(sample);
121+
Vector3f d = warp::square_to_uniform_sphere(Point2f(sample.x(), sample.y()));
122122

123123
// Automatically enlarge the bounding sphere when it does not contain the reference point
124124
Float radius = dr::maximum(m_bsphere.radius, dr::norm(it.p - m_bsphere.center)),
@@ -127,7 +127,7 @@ class ConstantBackgroundEmitter final : public Emitter<Float, Spectrum> {
127127
DirectionSample3f ds;
128128
ds.p = dr::fmadd(d, dist, it.p);
129129
ds.n = -d;
130-
ds.uv = sample;
130+
ds.uv = Point2f(sample.x(), sample.y());
131131
ds.time = it.time;
132132
ds.pdf = warp::square_to_uniform_sphere_pdf(d);
133133
ds.delta = false;
@@ -166,7 +166,7 @@ class ConstantBackgroundEmitter final : public Emitter<Float, Spectrum> {
166166
}
167167

168168
std::pair<PositionSample3f, Float>
169-
sample_position(Float /*time*/, const Point2f & /*sample*/,
169+
sample_position(Float /*time*/, const Point3f & /*sample*/,
170170
Mask /*active*/) const override {
171171
if constexpr (dr::is_jit_v<Float>) {
172172
/* When virtual function calls are recorded in symbolic mode,

src/emitters/directional.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,14 @@ MI_VARIANT class DirectionalEmitter final : public Emitter<Float, Spectrum> {
114114
}
115115

116116
std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
117-
const Point2f &spatial_sample,
117+
const Point3f &spatial_sample,
118118
const Point2f & /*direction_sample*/,
119119
Mask active) const override {
120120
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
121121

122+
auto spatial_sample_2d = Point2f(spatial_sample.x(), spatial_sample.y());
122123
// 1. Sample spatial component
123-
Point2f offset = warp::square_to_uniform_disk_concentric(spatial_sample);
124+
Point2f offset = warp::square_to_uniform_disk_concentric(spatial_sample_2d);
124125

125126
// 2. "Sample" directional component (fixed, no actual sampling required)
126127
const auto trafo = m_to_world.value();
@@ -135,7 +136,7 @@ MI_VARIANT class DirectionalEmitter final : public Emitter<Float, Spectrum> {
135136
si.t = 0.f;
136137
si.time = time;
137138
si.p = origin;
138-
si.uv = spatial_sample;
139+
si.uv = spatial_sample_2d;
139140
auto [wavelengths, wav_weight] =
140141
sample_wavelengths(si, wavelength_sample, active);
141142

@@ -147,7 +148,7 @@ MI_VARIANT class DirectionalEmitter final : public Emitter<Float, Spectrum> {
147148
}
148149

149150
std::pair<DirectionSample3f, Spectrum>
150-
sample_direction(const Interaction3f &it, const Point2f & /*sample*/,
151+
sample_direction(const Interaction3f &it, const Point3f & /*sample*/,
151152
Mask active) const override {
152153
MI_MASKED_FUNCTION(ProfilerPhase::EndpointSampleDirection, active);
153154

@@ -199,7 +200,7 @@ MI_VARIANT class DirectionalEmitter final : public Emitter<Float, Spectrum> {
199200
}
200201

201202
std::pair<PositionSample3f, Float>
202-
sample_position(Float /*time*/, const Point2f & /*sample*/,
203+
sample_position(Float /*time*/, const Point3f & /*sample*/,
203204
Mask /*active*/) const override {
204205
if constexpr (dr::is_jit_v<Float>) {
205206
// When vcalls are recorded in symbolic mode, we can't throw an exception,

src/emitters/directionalarea.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ class DirectionalArea final : public Emitter<Float, Spectrum> {
8686
}
8787

8888
std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
89-
const Point2f &sample2,
89+
const Point3f &sample2,
9090
const Point2f & /*sample3*/,
9191
Mask active) const override {
9292
// 1. Sample spatial component
93-
PositionSample3f ps = m_shape->sample_position(time, sample2);
93+
auto [ps, ps_weight] = sample_position(time, sample2, active);
9494

9595
// 2. Directional component is the normal vector at that position.
9696
const Vector3f d = ps.n;
@@ -115,7 +115,7 @@ class DirectionalArea final : public Emitter<Float, Spectrum> {
115115
* flat surface.
116116
*/
117117
std::pair<DirectionSample3f, Spectrum>
118-
sample_direction(const Interaction3f & /*it*/, const Point2f & /*sample*/,
118+
sample_direction(const Interaction3f & /*it*/, const Point3f & /*sample*/,
119119
Mask /*active*/) const override {
120120
return { dr::zeros<DirectionSample3f>(), dr::zeros<Spectrum>() };
121121
}
@@ -127,10 +127,10 @@ class DirectionalArea final : public Emitter<Float, Spectrum> {
127127
}
128128

129129
std::pair<PositionSample3f, Float>
130-
sample_position(Float time, const Point2f &sample,
130+
sample_position(Float time, const Point3f &sample,
131131
Mask active) const override {
132132
Assert(m_shape, "Can't sample from an area emitter without an associated Shape.");
133-
PositionSample3f ps = m_shape->sample_position(time, sample, active);
133+
PositionSample3f ps = m_shape->sample_position(time, Point2f(sample.x(), sample.y()), active);
134134
Float weight = dr::select(ps.pdf > 0.f, dr::rcp(ps.pdf), 0.f);
135135
return { ps, weight };
136136
}

0 commit comments

Comments
 (0)