Skip to content

Commit

Permalink
Envmap plugin load bitmap
Browse files Browse the repository at this point in the history
  • Loading branch information
Speierers committed Oct 19, 2022
1 parent 9ced0dd commit 9389c8d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 9 deletions.
39 changes: 30 additions & 9 deletions src/emitters/envmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ Environment emitter (:monosp:`envmap`)
- |string|
- Filename of the radiance-valued input image to be loaded; must be in latitude-longitude format.

* - bitmap
- :monosp:`Bitmap object`
- When creating a Environment emitter at runtime, e.g. from Python or C++,
an existing Bitmap image instance can be passed directly rather than
loading it from the filesystem with :paramtype:`filename`.

* - scale
- |Float|
- A scale factor that is applied to the radiance values stored in the input image. (Default: 1.0)
Expand Down Expand Up @@ -101,14 +107,28 @@ class EnvironmentMapEmitter final : public Emitter<Float, Spectrum> {
about the scene and default to the unit bounding sphere. */
m_bsphere = ScalarBoundingSphere3f(ScalarPoint3f(0.f), 1.f);

FileResolver *fs = Thread::thread()->file_resolver();
fs::path file_path = fs->resolve(props.string("filename"));
m_filename = file_path.filename().string();
ref<Bitmap> bitmap;

if (props.has_property("bitmap")) {
// Creates a Bitmap texture directly from an existing Bitmap object
if (props.has_property("filename"))
Throw("Cannot specify both \"bitmap\" and \"filename\".");
// Note: ref-counted, so we don't have to worry about lifetime
ref<Object> other = props.object("bitmap");
Bitmap *b = dynamic_cast<Bitmap *>(other.get());
if (!b)
Throw("Property \"bitmap\" must be a Bitmap instance.");
bitmap = b;
} else {
FileResolver *fs = Thread::thread()->file_resolver();
fs::path file_path = fs->resolve(props.string("filename"));
m_filename = file_path.filename().string();
bitmap = new Bitmap(file_path);
}

ref<Bitmap> bitmap = new Bitmap(file_path);
if (bitmap->width() < 2 || bitmap->height() < 3)
Throw("\"%s\": the environment map resolution must be at "
"least 2x3 pixels", m_filename);
Throw("\"%s\": the environment map resolution must be at least "
"2x3 pixels", (m_filename.empty() ? "<Bitmap>" : m_filename));

/* Convert to linear RGBA float bitmap, will undergo further
conversion into coefficients of a spectral upsampling model below */
Expand Down Expand Up @@ -452,9 +472,10 @@ class EnvironmentMapEmitter final : public Emitter<Float, Spectrum> {
std::string to_string() const override {
ScalarVector2u res = { m_data.shape(1), m_data.shape(0) };
std::ostringstream oss;
oss << "EnvironmentMapEmitter[" << std::endl
<< " filename = \"" << m_filename << "\"," << std::endl
<< " res = \"" << res << "\"," << std::endl
oss << "EnvironmentMapEmitter[" << std::endl;
if (!m_filename.empty())
oss << " filename = \"" << m_filename << "\"," << std::endl;
oss << " res = \"" << res << "\"," << std::endl
<< " bsphere = " << string::indent(m_bsphere) << std::endl
<< "]";
return oss.str();
Expand Down
38 changes: 38 additions & 0 deletions src/emitters/tests/test_envmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,41 @@ def test02_sampling_weights(variants_vec_backends_once_rgb):
ds.d = -ray.d
w4 = emitter.eval(si) / emitter.pdf_direction(si, ds) * dr.pi
assert dr.allclose(w4, w, rtol=1e-3)


def test03_load_bitmap(variants_all_rgb):
rng = mi.PCG32(size=102400)
sample = mi.Point2f(
rng.next_float32(),
rng.next_float32())
sample_2 = mi.Point2f(
rng.next_float32(),
rng.next_float32())

tempdir = tempfile.TemporaryDirectory()
fname = os.path.join(tempdir.name, 'out.exr')

# Sparse image with 1 pixel turned on
img = dr.zeros(mi.TensorXf, [100, 10])
img[40, 5] = 1
bmp = mi.Bitmap(img)
bmp.write(fname)

emitter_1 = mi.load_dict({
"type" : "envmap",
"filename" : fname
})

emitter_2 = mi.load_dict({
"type" : "envmap",
"bitmap" : bmp
})

# Test the sample_direction() interface
si = dr.zeros(mi.SurfaceInteraction3f)
ds, w = emitter_1.sample_direction(si, sample)
si.wi = -ds.d
w1 = emitter_1.eval(si)
w2 = emitter_2.eval(si)

assert dr.allclose(w1, w2, rtol=1e-3)

0 comments on commit 9389c8d

Please sign in to comment.