Skip to content

Commit 5efe8ac

Browse files
committed
Added flexible spectral range and default value to uniform spectrum plugin
1 parent a169505 commit 5efe8ac

File tree

2 files changed

+117
-18
lines changed

2 files changed

+117
-18
lines changed

src/spectra/tests/test_uniform.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import pytest
2+
3+
import enoki as ek
4+
import mitsuba
5+
6+
7+
def make_spectrum(value=None, lambda_min=None, lambda_max=None):
8+
from mitsuba.core.xml import load_string
9+
10+
xml_value = f"""<float name="value" value="{value}"/>""" \
11+
if value is not None else ""
12+
xml_lambda_min = f"""<float name="lambda_min" value="{lambda_min}"/>""" \
13+
if lambda_min is not None else ""
14+
xml_lambda_max = f"""<float name="lambda_max" value="{lambda_max}"/>""" \
15+
if lambda_max is not None else ""
16+
17+
xml_spectrum = f"""
18+
<spectrum version="2.0.0" type="uniform">
19+
{xml_value}
20+
{xml_lambda_min}
21+
{xml_lambda_max}
22+
</spectrum>
23+
"""
24+
return load_string(xml_spectrum)
25+
26+
27+
def test_construct(variant_scalar_spectral):
28+
assert make_spectrum() is not None
29+
assert make_spectrum(value=2.) is not None
30+
assert make_spectrum(value=2., lambda_min=400., lambda_max=500.) is not None
31+
32+
with pytest.raises(RuntimeError):
33+
make_spectrum(lambda_min=500., lambda_max=400.)
34+
35+
36+
def test_eval(variant_scalar_spectral):
37+
from mitsuba.render import SurfaceInteraction3f
38+
si = SurfaceInteraction3f()
39+
40+
value = 2.
41+
lambda_min = 400.
42+
lambda_max = 500.
43+
dlambda = lambda_max - lambda_min
44+
45+
s = make_spectrum(value, lambda_min, lambda_max)
46+
wavelengths = [390., 400., 450., 510.]
47+
values = [0, value, value, 0]
48+
49+
si.wavelengths = wavelengths
50+
assert ek.allclose(s.eval(si), values)
51+
assert ek.allclose(
52+
s.pdf(si), [1. / dlambda if value else 0. for value in values])
53+
54+
assert ek.allclose(s.eval_1(si), value)
55+
56+
with pytest.raises(RuntimeError) as excinfo:
57+
s.eval_3(si)
58+
assert 'not implemented' in str(excinfo.value)
59+
60+
61+
def test_sample(variant_scalar_spectral):
62+
from mitsuba.render import SurfaceInteraction3f
63+
from mitsuba.core import MTS_WAVELENGTH_MIN, MTS_WAVELENGTH_MAX
64+
dlambda = MTS_WAVELENGTH_MAX - MTS_WAVELENGTH_MIN
65+
66+
value = 0.5
67+
s = make_spectrum(value)
68+
69+
si = SurfaceInteraction3f()
70+
assert ek.allclose(s.sample(si, 0), [MTS_WAVELENGTH_MIN, value * dlambda])
71+
assert ek.allclose(s.sample(si, .5), [
72+
MTS_WAVELENGTH_MIN + .5 * dlambda, value * dlambda])
73+
assert ek.allclose(s.sample(si, 1), [MTS_WAVELENGTH_MAX, value * dlambda])

src/spectra/uniform.cpp

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#include <mitsuba/render/texture.h>
2-
#include <mitsuba/render/interaction.h>
31
#include <mitsuba/core/properties.h>
2+
#include <mitsuba/render/interaction.h>
3+
#include <mitsuba/render/texture.h>
44

55
NAMESPACE_BEGIN(mitsuba)
66

@@ -11,7 +11,8 @@ NAMESPACE_BEGIN(mitsuba)
1111
Uniform spectrum (:monosp:`uniform`)
1212
------------------------------------
1313
14-
This spectrum returns a constant reflectance or emission value between 360 and 830nm.
14+
This spectrum returns a constant reflectance or emission value between 360 and
15+
830nm.
1516
1617
*/
1718

@@ -20,26 +21,40 @@ class UniformSpectrum final : public Texture<Float, Spectrum> {
2021
public:
2122
MTS_IMPORT_TYPES(Texture)
2223

23-
UniformSpectrum(const Properties &props) : Texture(props) {
24-
m_value = props.float_("value");
24+
UniformSpectrum(const Properties &props)
25+
: Texture(props), m_value(1.f), m_lambda_min(MTS_WAVELENGTH_MIN),
26+
m_lambda_max(MTS_WAVELENGTH_MAX) {
27+
if (props.has_property("value"))
28+
m_value = props.float_("value");
29+
30+
if (props.has_property("lambda_min"))
31+
m_lambda_min = max(props.float_("lambda_min"), MTS_WAVELENGTH_MIN);
32+
33+
if (props.has_property("lambda_max"))
34+
m_lambda_max = min(props.float_("lambda_max"), MTS_WAVELENGTH_MAX);
35+
36+
if (!(m_lambda_min < m_lambda_max))
37+
Throw(
38+
"UniformSpectrum: 'lambda_min' must be less than 'lambda_max'");
2539
}
2640

2741
UnpolarizedSpectrum eval(const SurfaceInteraction3f &si,
2842
Mask active) const override {
2943
MTS_MASKED_FUNCTION(ProfilerPhase::TextureEvaluate, active);
3044

3145
if constexpr (is_spectral_v<Spectrum>) {
32-
auto active_w = (si.wavelengths >= MTS_WAVELENGTH_MIN) &&
33-
(si.wavelengths <= MTS_WAVELENGTH_MAX);
46+
auto active_w = (si.wavelengths >= m_lambda_min) &&
47+
(si.wavelengths <= m_lambda_max);
3448

3549
return select(active_w, UnpolarizedSpectrum(m_value),
36-
UnpolarizedSpectrum(0.f));
50+
UnpolarizedSpectrum(0.f));
3751
} else {
3852
return m_value;
3953
}
4054
}
4155

42-
Float eval_1(const SurfaceInteraction3f & /* it */, Mask active) const override {
56+
Float eval_1(const SurfaceInteraction3f & /* it */,
57+
Mask active) const override {
4358
MTS_MASKED_FUNCTION(ProfilerPhase::TextureEvaluate, active);
4459
return m_value;
4560
}
@@ -48,24 +63,25 @@ class UniformSpectrum final : public Texture<Float, Spectrum> {
4863
MTS_MASKED_FUNCTION(ProfilerPhase::TextureEvaluate, active);
4964

5065
if constexpr (is_spectral_v<Spectrum>) {
51-
auto active_w = (si.wavelengths >= MTS_WAVELENGTH_MIN) &&
52-
(si.wavelengths <= MTS_WAVELENGTH_MAX);
66+
auto active_w = (si.wavelengths >= m_lambda_min) &&
67+
(si.wavelengths <= m_lambda_max);
5368

5469
return select(active_w,
55-
Wavelength(1.f / (MTS_WAVELENGTH_MAX - MTS_WAVELENGTH_MIN)), Wavelength(0.f));
70+
Wavelength(1.f / (m_lambda_max - m_lambda_min)),
71+
Wavelength(0.f));
5672
} else {
5773
NotImplementedError("pdf");
5874
}
5975
}
6076

61-
std::pair<Wavelength, UnpolarizedSpectrum> sample(const SurfaceInteraction3f &/*si*/,
62-
const Wavelength &sample,
63-
Mask active) const override {
77+
std::pair<Wavelength, UnpolarizedSpectrum>
78+
sample(const SurfaceInteraction3f & /*si*/, const Wavelength &sample,
79+
Mask active) const override {
6480
MTS_MASKED_FUNCTION(ProfilerPhase::TextureSample, active);
6581

6682
if constexpr (is_spectral_v<Spectrum>) {
67-
return { MTS_WAVELENGTH_MIN + (MTS_WAVELENGTH_MAX - MTS_WAVELENGTH_MIN) * sample,
68-
m_value * (MTS_WAVELENGTH_MAX - MTS_WAVELENGTH_MIN) };
83+
return { m_lambda_min + (m_lambda_max - m_lambda_min) * sample,
84+
m_value * (m_lambda_max - m_lambda_min) };
6985
} else {
7086
ENOKI_MARK_USED(sample);
7187
NotImplementedError("sample");
@@ -76,15 +92,25 @@ class UniformSpectrum final : public Texture<Float, Spectrum> {
7692

7793
void traverse(TraversalCallback *callback) override {
7894
callback->put_parameter("value", m_value);
95+
callback->put_parameter("value", m_lambda_min);
96+
callback->put_parameter("value", m_lambda_max);
7997
}
8098

8199
std::string to_string() const override {
82-
return tfm::format("UniformSpectrum[value=%f]", m_value);
100+
std::ostringstream oss;
101+
oss << "UniformSpectrum[" << std::endl
102+
<< " value = " << m_value << std::endl
103+
<< " lambda_min = " << m_lambda_min << std::endl
104+
<< " lambda_max = " << m_lambda_max << std::endl
105+
<< "]";
106+
return oss.str();
83107
}
84108

85109
MTS_DECLARE_CLASS()
86110
private:
87111
Float m_value;
112+
ScalarFloat m_lambda_min;
113+
ScalarFloat m_lambda_max;
88114
};
89115

90116
MTS_IMPLEMENT_CLASS_VARIANT(UniformSpectrum, Texture)

0 commit comments

Comments
 (0)