Skip to content

Commit

Permalink
Add eval_attribute methods to BSDF
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastien Speierer authored and njroussel committed Jul 17, 2023
1 parent 9c8125f commit cfc425a
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 1 deletion.
8 changes: 8 additions & 0 deletions include/mitsuba/python/docstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,14 @@ Parameter ``si``:
A surface interaction data structure describing the underlying
surface position.)doc";

static const char *__doc_mitsuba_BSDF_has_attribute = R"doc()doc";

static const char *__doc_mitsuba_BSDF_eval_attribute = R"doc()doc";

static const char *__doc_mitsuba_BSDF_eval_attribute_1 = R"doc()doc";

static const char *__doc_mitsuba_BSDF_eval_attribute_3 = R"doc()doc";

static const char *__doc_mitsuba_BSDF_eval_null_transmission =
R"doc(Evaluate un-scattered transmission component of the BSDF
Expand Down
71 changes: 71 additions & 0 deletions include/mitsuba/render/bsdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,73 @@ class MI_EXPORT_LIB BSDF : public Object {
virtual Spectrum eval_null_transmission(const SurfaceInteraction3f &si,
Mask active = true) const;

/**
* \brief Returns whether this BSDF contains the specified attribute.
*
* \param name
* Name of the attribute
*/
virtual Mask has_attribute(const std::string &name, Mask active = true) const;

/**
* \brief Evaluate a specific BSDF attribute at the given surface interaction.
*
* BSDF attributes are user-provided fields that provide extra
* information at an intersection. An example of this would be a per-vertex
* or per-face color on a triangle mesh.
*
* \param name
* Name of the attribute to evaluate
*
* \param si
* Surface interaction associated with the query
*
* \return
* An unpolarized spectral power distribution or reflectance value
*/
virtual UnpolarizedSpectrum eval_attribute(const std::string &name,
const SurfaceInteraction3f &si,
Mask active = true) const;

/**
* \brief Monochromatic evaluation of a BSDF attribute at the given surface interaction
*
* This function differs from \ref eval_attribute() in that it provided raw access to
* scalar intensity/reflectance values without any color processing (e.g.
* spectral upsampling).
*
* \param name
* Name of the attribute to evaluate
*
* \param si
* Surface interaction associated with the query
*
* \return
* An scalar intensity or reflectance value
*/
virtual Float eval_attribute_1(const std::string &name,
const SurfaceInteraction3f &si,
Mask active = true) const;

/**
* \brief Trichromatic evaluation of a BSDF attribute at the given surface interaction
*
* This function differs from \ref eval_attribute() in that it provided raw access to
* RGB intensity/reflectance values without any additional color processing
* (e.g. RGB-to-spectral upsampling).
*
* \param name
* Name of the attribute to evaluate
*
* \param si
* Surface interaction associated with the query
*
* \return
* An trichromatic intensity or reflectance value
*/
virtual Color3f eval_attribute_3(const std::string &name,
const SurfaceInteraction3f &si,
Mask active = true) const;

// -----------------------------------------------------------------------
//! @{ \name BSDF property accessors (components, flags, etc)
Expand Down Expand Up @@ -600,6 +667,10 @@ DRJIT_VCALL_TEMPLATE_BEGIN(mitsuba::BSDF)
DRJIT_VCALL_METHOD(eval_pdf)
DRJIT_VCALL_METHOD(eval_pdf_sample)
DRJIT_VCALL_METHOD(eval_diffuse_reflectance)
DRJIT_VCALL_METHOD(has_attribute)
DRJIT_VCALL_METHOD(eval_attribute)
DRJIT_VCALL_METHOD(eval_attribute_1)
DRJIT_VCALL_METHOD(eval_attribute_3)
DRJIT_VCALL_GETTER(flags, uint32_t)
auto needs_differentials() const {
return has_flag(flags(), mitsuba::BSDFFlags::NeedsDifferentials);
Expand Down
36 changes: 36 additions & 0 deletions src/render/bsdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,42 @@ MI_VARIANT Spectrum BSDF<Float, Spectrum>::eval_diffuse_reflectance(
return eval(ctx, si, wo, active) * dr::Pi<Float>;
}


MI_VARIANT typename BSDF<Float, Spectrum>::Mask
BSDF<Float, Spectrum>::has_attribute(const std::string& /*name*/, Mask /*active*/) const {
return false;
}

MI_VARIANT typename BSDF<Float, Spectrum>::UnpolarizedSpectrum
BSDF<Float, Spectrum>::eval_attribute(const std::string & name,
const SurfaceInteraction3f & /*si*/,
Mask /*active*/) const {
if constexpr (dr::is_jit_v<Float>)
return 0.f;
else
Throw("Invalid attribute requested %s.", name.c_str());
}

MI_VARIANT Float
BSDF<Float, Spectrum>::eval_attribute_1(const std::string& name,
const SurfaceInteraction3f & /*si*/,
Mask /*active*/) const {
if constexpr (dr::is_jit_v<Float>)
return 0.f;
else
Throw("Invalid attribute requested %s.", name.c_str());
}

MI_VARIANT typename BSDF<Float, Spectrum>::Color3f
BSDF<Float, Spectrum>::eval_attribute_3(const std::string& name,
const SurfaceInteraction3f & /*si*/,
Mask /*active*/) const {
if constexpr (dr::is_jit_v<Float>)
return 0.f;
else
Throw("Invalid attribute requested %s.", name.c_str());
}

template <typename Index>
std::string type_mask_to_string(Index type_mask) {
std::ostringstream oss;
Expand Down
41 changes: 40 additions & 1 deletion src/render/python/bsdf_v.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,30 @@ MI_VARIANT class PyBSDF : public BSDF<Float, Spectrum> {
const Vector3f &wo,
Mask active) const override {
using Return = std::pair<Spectrum, Float>;
PYBIND11_OVERRIDE_PURE(Return, BSDF, eval_pdf, ctx, si, wo, active);
PYBIND11_OVERRIDE(Return, BSDF, eval_pdf, ctx, si, wo, active);
}

Spectrum eval_diffuse_reflectance(const SurfaceInteraction3f &si,
Mask active) const override {
PYBIND11_OVERRIDE_PURE(Spectrum, BSDF, eval_diffuse_reflectance, si, active);
}

Mask has_attribute(const std::string &name, Mask active) const override {
PYBIND11_OVERRIDE(Mask, BSDF, has_attribute, name, active);
}

UnpolarizedSpectrum eval_attribute(const std::string &name, const SurfaceInteraction3f &si, Mask active) const override {
PYBIND11_OVERRIDE(UnpolarizedSpectrum, BSDF, eval_attribute, name, si, active);
}

Float eval_attribute_1(const std::string &name, const SurfaceInteraction3f &si, Mask active) const override {
PYBIND11_OVERRIDE(Float, BSDF, eval_attribute_1, name, si, active);
}

Color3f eval_attribute_3(const std::string &name, const SurfaceInteraction3f &si, Mask active) const override {
PYBIND11_OVERRIDE(Color3f, BSDF, eval_attribute_3, name, si, active);
}

std::string to_string() const override {
PYBIND11_OVERRIDE_PURE(std::string, BSDF, to_string,);
}
Expand Down Expand Up @@ -120,6 +136,29 @@ template <typename Ptr, typename Cls> void bind_bsdf_generic(Cls &cls) {
[](Ptr bsdf, const SurfaceInteraction3f &si, Mask active) {
return bsdf->eval_diffuse_reflectance(si, active);
}, "si"_a, "active"_a = true, D(BSDF, eval_diffuse_reflectance))
.def("has_attribute",
[](Ptr bsdf, const std::string &name, const Mask &active) {
return bsdf->has_attribute(name, active);
},
"name"_a, "active"_a = true, D(BSDF, has_attribute))
.def("eval_attribute",
[](Ptr bsdf, const std::string &name,
const SurfaceInteraction3f &si, const Mask &active) {
return bsdf->eval_attribute(name, si, active);
},
"name"_a, "si"_a, "active"_a = true, D(BSDF, eval_attribute))
.def("eval_attribute_1",
[](Ptr bsdf, const std::string &name,
const SurfaceInteraction3f &si, const Mask &active) {
return bsdf->eval_attribute_1(name, si, active);
},
"name"_a, "si"_a, "active"_a = true, D(BSDF, eval_attribute_1))
.def("eval_attribute_3",
[](Ptr bsdf, const std::string &name,
const SurfaceInteraction3f &si, const Mask &active) {
return bsdf->eval_attribute_3(name, si, active);
},
"name"_a, "si"_a, "active"_a = true, D(BSDF, eval_attribute_3))
.def("flags", [](Ptr bsdf) { return bsdf->flags(); }, D(BSDF, flags))
.def("needs_differentials",
[](Ptr bsdf) { return bsdf->needs_differentials(); },
Expand Down
38 changes: 38 additions & 0 deletions src/render/tests/test_bsdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,41 @@ def test02_bs_construct(variant_scalar_rgb):
assert dr.allclose(bs.pdf, 0.0)
assert dr.allclose(bs.eta, 1.0)
assert bs.sampled_type == 0

def test03_bsdf_attributes(variants_vec_backends_once_rgb):

si = dr.zeros(mi.SurfaceInteraction3f)
si.uv = [0.5, 0.5]

color = [0.5, 0.6, 0.7]

bsdf = mi.load_dict({
'type': 'diffuse',
'reflectance': { 'type': 'rgb', 'value': color }
})

assert dr.all(bsdf.has_attribute('reflectance'))
assert not dr.all(bsdf.has_attribute('foo'))
assert dr.allclose(color, bsdf.eval_attribute('reflectance', si))
assert dr.allclose(0.0, bsdf.eval_attribute('foo', si))

# Now with a custom BSDF

class DummyBSDF(mi.BSDF):
def __init__(self, props):
mi.BSDF.__init__(self, props)
self.tint = props['tint']

def traverse(self, callback):
callback.put_object('tint', self.tint, mi.ParamFlags.Differentiable)

mi.register_bsdf('dummy', DummyBSDF)

bsdf = mi.load_dict({
'type': 'dummy',
'tint': { 'type': 'rgb', 'value': color }
})
assert dr.all(bsdf.has_attribute('tint'))
assert not dr.all(bsdf.has_attribute('foo'))
assert dr.allclose(color, bsdf.eval_attribute('tint', si))
assert dr.allclose(0.0, bsdf.eval_attribute('foo', si))

0 comments on commit cfc425a

Please sign in to comment.