Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[✨ feature] Implement eval_roughness() for most BSDFs #589

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/mitsuba/python/docstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,13 @@ inexpensively. When this is not possible, the value is approximated by
evaluating the BSDF for a normal outgoing direction and returning this
value multiplied by pi. This is the default behaviour of this method.

Parameter ``si``:
A surface interaction data structure describing the underlying
surface position.)doc";

static const char *__doc_mitsuba_BSDF_eval_roughness =
R"doc(Evaluate the roughness

njroussel marked this conversation as resolved.
Show resolved Hide resolved
Parameter ``si``:
A surface interaction data structure describing the underlying
surface position.)doc";
Expand Down
18 changes: 18 additions & 0 deletions include/mitsuba/render/bsdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,23 @@ class MI_EXPORT_LIB BSDF : public Object {
virtual Spectrum eval_diffuse_reflectance(const SurfaceInteraction3f &si,
Mask active = true) const;

/**
* \brief Evaluate roughness
*
* This method approximates the roughness for a given
* direction. For some materials, an exact value can be computed
* inexpensively.
* When this is not possible, the value is approximated by
* evaluating the BSDF for a normal outgoing direction and returning this
* value multiplied by pi. This is the default behaviour of this method.
Comment on lines +525 to +530
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update this 😄

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't it be exactly the same? doesn't it under the hood call same methods as diffuse_reflectance_eval?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused.

Doesn't the default behaviour just return 1 currently? It doesn't use the BSDF evaluation at the normal direction.

*
* \param si
* A surface interaction data structure describing the underlying
* surface position.
*/
virtual Float eval_roughness(const SurfaceInteraction3f &si,
Mask active = true) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean I should indent it one more tab or one less?
Isn't it currently in line with diffuse_reflectance?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Mask active = true argument should be aligned with the opening parenthesis of the previous line. Like in the other methods. Do you see what I mean?


/// Return a human-readable representation of the BSDF
std::string to_string() const override = 0;

Expand Down Expand Up @@ -600,6 +617,7 @@ 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(eval_roughness)
DRJIT_VCALL_GETTER(flags, uint32_t)
auto needs_differentials() const {
return has_flag(flags(), mitsuba::BSDFFlags::NeedsDifferentials);
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/bumpmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ class BumpMap final : public BSDF<Float, Spectrum> {
return m_nested_bsdf->eval_diffuse_reflectance(si, active);
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_nested_bsdf->eval_roughness(si, active);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "BumpMap[" << std::endl
Expand Down
6 changes: 6 additions & 0 deletions src/bsdfs/conductor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ class SmoothConductor final : public BSDF<Float, Spectrum> {
return 0.f;
}

Float eval_roughness(const SurfaceInteraction3f & /*si*/,
Mask /*active*/) const override {
return Float(0.0f);
}


std::string to_string() const override {
std::ostringstream oss;
oss << "SmoothConductor[" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/mask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,11 @@ class MaskBSDF final : public BSDF<Float, Spectrum> {
return m_nested_bsdf->eval_diffuse_reflectance(si, active);
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_nested_bsdf->eval_roughness(si, active);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "Mask[" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/plastic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,11 @@ class SmoothPlastic final : public BSDF<Float, Spectrum> {
return m_diffuse_reflectance->eval(si, active);
}

Float eval_roughness(const SurfaceInteraction3f &/*si*/,
Mask /*active*/) const override {
return Float(0.0f);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "SmoothPlastic[" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/principled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,11 @@ class Principled final : public BSDF<Float, Spectrum> {
return m_base_color->eval(si, active);
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_roughness->eval_1(si, active);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "Principled BSDF :" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/principledthin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,11 @@ class PrincipledThin final : public BSDF<Float, Spectrum> {
return m_base_color->eval(si, active);
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_roughness->eval_1(si, active);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "The Thin Principled BSDF :" << std::endl
Expand Down
6 changes: 6 additions & 0 deletions src/bsdfs/roughconductor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,12 @@ class RoughConductor final : public BSDF<Float, Spectrum> {
return { F * value & active, dr::select(active, pdf, 0.f) };
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_alpha_u->eval_1(si, active);
}


std::string to_string() const override {
std::ostringstream oss;
oss << "RoughConductor[" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/roughdielectric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@ class RoughDielectric final : public BSDF<Float, Spectrum> {
dr::select(active, pdf * dr::abs(dwh_dwo), 0.f) };
}

Float eval_roughness(const SurfaceInteraction3f &si,
Mask active) const override {
return m_alpha_u->eval_1(si, active);
}

std::string to_string() const override {
std::ostringstream oss;
oss << "RoughDielectric[" << std::endl
Expand Down
5 changes: 5 additions & 0 deletions src/bsdfs/roughplastic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,11 @@ class RoughPlastic final : public BSDF<Float, Spectrum> {
return m_diffuse_reflectance->eval(si, active);
}

Float eval_roughness(const SurfaceInteraction3f & /*si*/,
Mask /*active*/) const override {
return m_alpha;
}

std::string to_string() const override {
std::ostringstream oss;
oss << "RoughPlastic[" << std::endl
Expand Down
39 changes: 39 additions & 0 deletions src/bsdfs/tests/test_twosided.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,42 @@ def test03_eval_diffuse_reflectance(variants_vec_rgb):

assert dr.allclose(dr.select(up, value - value_front, 0), 0.0)
assert dr.allclose(dr.select(up, 0, value - value_back), 0.0)



def test04_eval_roughness(variants_vec_rgb):
bsdf_front = mi.load_dict({
'type': 'roughconductor',
'alpha': 0.1
})
bsdf_back = mi.load_dict({
'type': 'principled',
'roughness': 0.5
})
bsdf = mi.load_dict({
'type': 'twosided',
'a': bsdf_front,
'b': bsdf_back,
})

si = mi.SurfaceInteraction3f()
si.t = 0.1
si.p = [0, 0, 0]
si.n = [0, 0, 1]
si.sh_frame = mi.Frame3f(si.n)

n = 5
epsilon = 0.0001
for u in dr.linspace(mi.Float, epsilon, 1 - epsilon, n):
for v in dr.linspace(mi.Float, epsilon, 1 - epsilon, n):
si.wi = mi.warp.square_to_uniform_sphere([u / float(n-1),
v / float(n-1)])
up = mi.Frame3f.cos_theta(si.wi) > 0.0

value = bsdf.eval_roughness(si)
value_front = bsdf_front.eval_roughness(si)
si.wi.z *= -1
value_back = bsdf_back.eval_roughness(si)

assert dr.allclose(dr.select(up, value - value_front, 0), 0.0)
assert dr.allclose(dr.select(up, 0, value - value_back), 0.0)
24 changes: 24 additions & 0 deletions src/bsdfs/twosided.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,30 @@ class TwoSidedBRDF final : public BSDF<Float, Spectrum> {
return result;
}
}
Float eval_roughness(const SurfaceInteraction3f &si_,
Mask active) const override {
SurfaceInteraction3f si(si_);

if (m_brdf[0] == m_brdf[1]) {
si.wi.z() = dr::abs(si.wi.z());
return m_brdf[0]->eval_roughness(si, active);
} else {
Float result = 0.f;
Mask front_side = Frame3f::cos_theta(si.wi) > 0.f && active,
back_side = Frame3f::cos_theta(si.wi) < 0.f && active;

if (dr::any_or<true>(front_side))
result = m_brdf[0]->eval_roughness(si, front_side);

if (dr::any_or<true>(back_side)) {
si.wi.z() *= -1.f;
dr::masked(result, back_side) =
m_brdf[1]->eval_roughness(si, back_side);
}

return result;
Comment on lines +286 to +305
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this logic to a separate function?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a concern of this PR? since such a refactoring is a different task than this, and should happen for other methods of this class, I would suggest doing that in another tab. Also, I am not too good at C++, and I cannot do such a refactoring without bad consequences :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with this. I'll refactor it with a lambda once it's merged.

}
}

std::string to_string() const override {
std::ostringstream oss;
Expand Down
15 changes: 14 additions & 1 deletion src/integrators/aov.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ output file.
Currently, the following AOVs types are available:

- :monosp:`albedo`: Albedo (diffuse reflectance) of the material.
- :monosp:`roughness`: Roughness of the material (returns 1.0 if not applicable).
- :monosp:`depth`: Distance from the pinhole.
- :monosp:`position`: World space position value.
- :monosp:`uv`: UV coordinates.
Expand All @@ -80,7 +81,7 @@ wide pixel reconstruction filter as it will result in fractional values.

The :monosp:`albedo` AOV will evaluate the diffuse reflectance
(\ref BSDF::eval_diffuse_reflectance) of the material. Note that depending on
the material, this value might only be an approximation.
the material, this value might only be an approximation. Likewise for the :monosp:`roughness`.
*/

template <typename Float, typename Spectrum>
Expand All @@ -91,6 +92,7 @@ class AOVIntegrator final : public SamplingIntegrator<Float, Spectrum> {

enum class Type {
Albedo,
Roughness,
Depth,
Position,
UV,
Expand Down Expand Up @@ -120,6 +122,10 @@ class AOVIntegrator final : public SamplingIntegrator<Float, Spectrum> {
m_aov_names.push_back(item[0] + ".R");
m_aov_names.push_back(item[0] + ".G");
m_aov_names.push_back(item[0] + ".B");
}
else if (item[1] == "roughness") {
m_aov_types.push_back(Type::Roughness);
m_aov_names.push_back(item[0] + ".R");
} else if (item[1] == "depth") {
m_aov_types.push_back(Type::Depth);
m_aov_names.push_back(item[0] + ".T");
Expand Down Expand Up @@ -244,6 +250,13 @@ class AOVIntegrator final : public SamplingIntegrator<Float, Spectrum> {
*aovs++ = rgb.b();
}
break;
case Type::Roughness: {
BSDFPtr bsdf = si.bsdf(ray);
Float rough = bsdf->eval_roughness(si, active);

*aovs++ = Float(rough);
}
break;
case Type::Depth:
*aovs++ = dr::select(si.is_valid(), si.t, 0.f);
break;
Expand Down
5 changes: 5 additions & 0 deletions src/render/bsdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ MI_VARIANT Spectrum BSDF<Float, Spectrum>::eval_diffuse_reflectance(
return eval(ctx, si, wo, active) * dr::Pi<Float>;
}

MI_VARIANT Float BSDF<Float, Spectrum>::eval_roughness(
const SurfaceInteraction3f & /* si */, Mask /* active */) const {
return 1.f;
njroussel marked this conversation as resolved.
Show resolved Hide resolved
}

template <typename Index>
std::string type_mask_to_string(Index type_mask) {
std::ostringstream oss;
Expand Down
8 changes: 8 additions & 0 deletions src/render/python/bsdf_v.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ MI_VARIANT class PyBSDF : public BSDF<Float, Spectrum> {
Mask active) const override {
PYBIND11_OVERRIDE_PURE(Spectrum, BSDF, eval_diffuse_reflectance, si, active);
}
Float eval_roughness(const SurfaceInteraction3f &si,
Comment on lines 66 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing new line here.

Mask active) const override {
PYBIND11_OVERRIDE_PURE(Float, BSDF, eval_roughness, si, active);
}

std::string to_string() const override {
PYBIND11_OVERRIDE_PURE(std::string, BSDF, to_string,);
Expand Down Expand Up @@ -112,6 +116,10 @@ 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("eval_roughness",
[](Ptr bsdf, const SurfaceInteraction3f &si, Mask active) {
return bsdf->eval_roughness(si, active);
}, "si"_a, "active"_a = true, D(BSDF, eval_roughness))
.def("flags", [](Ptr bsdf) { return bsdf->flags(); }, D(BSDF, flags))
.def("needs_differentials",
[](Ptr bsdf) { return bsdf->needs_differentials(); },
Expand Down