Skip to content

Commit

Permalink
Distant plugin test fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
leroyvn committed May 25, 2020
1 parent d1f2950 commit 26683f6
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 84 deletions.
26 changes: 9 additions & 17 deletions src/sensors/distant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ 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_BASE(Sensor, m_world_transform, m_film)
MTS_IMPORT_TYPES(Scene)

DistantSensor(const Properties &props) : Base(props) {
Expand Down Expand Up @@ -76,8 +76,6 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
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 {
Expand All @@ -88,8 +86,8 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
}

std::pair<Ray3f, Spectrum> sample_ray(Float time, Float wavelength_sample,
const Point2f &spatial_sample,
const Point2f & /*direction_sample*/,
const Point2f & /*film_sample*/,
const Point2f &aperture_sample,
Mask active) const override {
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
Ray3f ray;
Expand All @@ -109,7 +107,7 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
// 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);
warp::square_to_uniform_disk_concentric(aperture_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;
Expand All @@ -118,15 +116,12 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
}

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

std::pair<RayDifferential3f, Spectrum> sample_ray_differential(
Float time, Float wavelength_sample, const Point2f &spatial_sample,
const Point2f & /*direction_sample*/, Mask active) const override {
Float time, Float wavelength_sample, const Point2f & /*film_sample*/,
const Point2f &aperture_sample, Mask active) const override {
MTS_MASKED_FUNCTION(ProfilerPhase::EndpointSampleRay, active);
RayDifferential3f ray;
ray.time = time;
Expand All @@ -145,7 +140,7 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
// 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);
warp::square_to_uniform_disk_concentric(aperture_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;
Expand All @@ -158,10 +153,7 @@ MTS_VARIANT class DistantSensor final : public Sensor<Float, Spectrum> {
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)));
return std::make_pair(ray, wav_weight);
}

/// This sensor does not occupy any particular region of space, return an
Expand Down
136 changes: 69 additions & 67 deletions src/sensors/tests/test_distant.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,47 @@
import mitsuba


def xml_sensor(direction=None, target=None, xpixel=1):
def dict_sensor(direction=None, target=None, fwidth=1):
if direction is None:
xml_direction = ""
dict_direction = {}
else:
if type(direction) is not str:
direction = ",".join([str(x) for x in direction])
xml_direction = f"""<vector name="direction" value="{direction}"/>"""
dict_direction = {"direction": direction}

if target is None:
xml_target = ""
dict_target = {}
else:
if type(target) is not str:
target = ",".join([str(x) for x in target])
xml_target = f"""<point name="target" value="{target}"/>"""
dict_target = {"target": target}

xml_film = f"""<film type="hdrfilm">
<integer name="width" value="{xpixel}"/>
<integer name="height" value="1"/>
<rfilter type="box"/>
</film>"""
dict_film = {
"type": "hdrfilm",
"width": fwidth,
"height": 1,
"rfilter": {"type": "box"}
}

return f"""<sensor version="2.0.0" type="distant">
{xml_direction}
{xml_target}
{xml_film}
</sensor>"""
return {
"type": "distant",
**dict_direction,
**dict_target,
"film": dict_film,
}


def make_sensor(direction=None, target=None, xpixel=1):
from mitsuba.core.xml import load_string
return load_string(xml_sensor(direction, target, xpixel))
def make_sensor(direction=None, target=None, fwidth=1):
from mitsuba.core.xml import load_dict
return load_dict(dict_sensor(direction, target, fwidth))


def test_construct(variant_scalar_rgb):
from mitsuba.core.xml import load_string
from mitsuba.core.xml import load_string, load_dict

# Construct without parameters (wrong film size)
with pytest.raises(RuntimeError):
sensor = load_string("""<sensor version="2.0.0" type="distant"/>""")
sensor = load_dict({"type": "distant"})

# Construct with wrong film size
with pytest.raises(RuntimeError):
sensor = make_sensor(xpixel=2)
sensor = make_sensor(fwidth=2)

# Construct with minimal parameters
sensor = make_sensor()
Expand Down Expand Up @@ -110,16 +108,15 @@ def test_sample_ray(variant_scalar_rgb, direction, target, ray_kind):


def make_scene(direction=[0, 0, -1], target=None):
from mitsuba.core.xml import load_string
from mitsuba.core.xml import load_dict

scene_xml = f"""
<scene version="2.0.0">
{xml_sensor(direction, target)}
<shape type="rectangle"/>
</scene>
"""
dict_scene = {
"type": "scene",
"sensor": dict_sensor(direction, target),
"surface": {"type": "rectangle"}
}

return load_string(scene_xml)
return load_dict(dict_scene)


@pytest.mark.parametrize("target", [[0, 0, 0], [0.5, 0, 1]])
Expand All @@ -143,12 +140,12 @@ def test_target(variant_scalar_rgb, target):
@pytest.mark.parametrize("direction", [[0, 0, -1], [0.5, 0.5, -1]])
def test_intersection(variant_scalar_rgb, direction):
# Check if the sensor correctly casts rays spread uniformly in the scene
direction = ek.normalize(direction)
direction = list(ek.normalize(direction))
scene = make_scene(direction=direction)
sensor = scene.sensors()[0]
sampler = sensor.sampler()

n_rays = 10000
n_rays = 1000
isect = np.empty((n_rays, 3))

for i in range(n_rays):
Expand All @@ -168,7 +165,7 @@ def test_intersection(variant_scalar_rgb, direction):
# Average intersection locations should be (in average) centered
# around (0, 0, 0)
isect_valid = isect[~np.isnan(isect).all(axis=1)]
assert np.allclose(isect_valid[:, :2].mean(axis=0), 0., atol=1e-2)
assert np.allclose(isect_valid[:, :2].mean(axis=0), 0., atol=5e-2)
assert np.allclose(isect_valid[:, 2], 0., atol=1e-5)

# Check number of invalid intersections
Expand All @@ -177,42 +174,47 @@ def test_intersection(variant_scalar_rgb, direction):
# slanting factor (cos theta) w.r.t the sensor's direction
n_invalid = np.count_nonzero(np.isnan(isect).all(axis=1))
assert np.allclose(n_invalid / n_rays, 1. - 2. / np.pi *
ek.dot(direction, [0, 0, -1]), atol=1e-2)
ek.dot(direction, [0, 0, -1]), atol=0.1)


@pytest.mark.parametrize("radiance", [10**x for x in range(-3, 4)])
def test_render(variant_scalar_rgb, radiance):
# Test render results with a simple scene
from mitsuba.core.xml import load_string
import numpy as np

scene_xml = """
<scene version="2.0.0">
<default name="radiance" value="1.0"/>
<default name="spp" value="1"/>
<integrator type="path"/>
<sensor type="distant">
<film type="hdrfilm">
<integer name="width" value="1"/>
<integer name="height" value="1"/>
<string name="pixel_format" value="rgb"/>
<rfilter type="box"/>
</film>
<sampler type="independent">
<integer name="sample_count" value="$spp"/>
</sampler>
</sensor>
<emitter type="constant">
<spectrum name="radiance" value="$radiance"/>
</emitter>
</scene>
"""

scene = load_string(scene_xml, spp=1, radiance=radiance)
from mitsuba.core.xml import load_dict
from mitsuba.core import Bitmap, Struct

def dict_scene(radiance=1.0, spp=1):
return {
"type": "scene",
"shape": {
"type": "rectangle",
"bsdf": {"type": "conductor"},
},
"integrator": {"type": "path"},
"sensor": {
"type": "distant",
"film": {
"type": "hdrfilm",
"width": 1,
"height": 1,
"pixel_format": "rgb",
"rfilter": {"type": "box"},
},
"sampler": {
"type": "independent",
"sample_count": spp
},
},
"emitter": {
"type": "constant",
"radiance": {
"type": "spectrum",
"value": radiance
}
}
}

scene = load_dict(dict_scene(spp=1, radiance=radiance))
sensor = scene.sensors()[0]
scene.integrator().render(scene, sensor)
img = sensor.film().bitmap()
Expand Down

0 comments on commit 26683f6

Please sign in to comment.