Skip to content

Commit a2a7fb4

Browse files
authored
Incorporate diffuse MaterialX BSDFs to BSDL (#2092)
* Implement get_albedo() for BSDL imported BSDFs We forgot to forward the albedo function to BSDL and also to implement it for the latest MaterialX components added to BSDL recently. This led to not very good sampling quality. Signed-off-by: Alejandro Conty <aconty@imageworks.com> * Incorporate diffuse MaterialX BSDFs to BSDL This is just a code movement. The implementation was already there. Just relocated to the BSDL framework the following items: - burley_diffuse_bsdf - oren_nayar_diffuse_bsdf - translucent_bsdf There are sampling noise differences that require updating the tests, but otherwise images look identical. Signed-off-by: Alejandro Conty <aconty@imageworks.com> * Update testsuite refs and thresholds Due to the last two commits (BSDL albedo fix and diffuse MTX code movement) some references had to be updated due to noise differences. I'm also following the policy of keeping as few refs as possible and opening the thresholds so different platforms LSB differences are accepted. --------- Signed-off-by: Alejandro Conty <aconty@imageworks.com>
1 parent 3dd1d94 commit a2a7fb4

File tree

33 files changed

+482
-230
lines changed

33 files changed

+482
-230
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright Contributors to the Open Shading Language project.
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4+
5+
6+
#pragma once
7+
8+
#include <BSDL/bsdf_decl.h>
9+
10+
BSDL_ENTER_NAMESPACE
11+
12+
namespace mtx {
13+
14+
template<typename BSDF_ROOT> struct BurleyDiffuseLobe : public Lobe<BSDF_ROOT> {
15+
using Base = Lobe<BSDF_ROOT>;
16+
17+
struct Data {
18+
Imath::V3f N;
19+
Imath::C3f albedo;
20+
float roughness;
21+
Stringhash label;
22+
using lobe_type = BurleyDiffuseLobe<BSDF_ROOT>;
23+
};
24+
25+
template<typename D> static typename LobeRegistry<D>::Entry entry()
26+
{
27+
static_assert(
28+
std::is_base_of<Data, D>::value); // Make no other assumptions
29+
using R = LobeRegistry<D>;
30+
return { name(),
31+
{ R::param(&D::N), R::param(&D::albedo),
32+
R::param(&D::roughness), R::param(&D::label, "label"),
33+
R::close() } };
34+
}
35+
36+
template<typename T>
37+
BSDL_INLINE_METHOD BurleyDiffuseLobe(T*, const BsdfGlobals& globals,
38+
const Data& data);
39+
40+
static constexpr const char* name() { return "burley_diffuse_bsdf"; }
41+
42+
BSDL_INLINE_METHOD Power albedo_impl() const { return diff_albedo; }
43+
44+
BSDL_INLINE_METHOD Sample eval_impl(const Imath::V3f& wo,
45+
const Imath::V3f& wi) const;
46+
BSDL_INLINE_METHOD Sample sample_impl(const Imath::V3f& wo,
47+
const Imath::V3f& rnd) const;
48+
49+
private:
50+
static BSDL_INLINE_METHOD float fresnel(float cos_theta, float F90);
51+
52+
Power diff_albedo;
53+
float diff_roughness;
54+
};
55+
56+
} // namespace mtx
57+
58+
BSDL_LEAVE_NAMESPACE
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright Contributors to the Open Shading Language project.
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4+
5+
6+
#pragma once
7+
8+
#include <BSDL/MTX/bsdf_burley_diffuse_decl.h>
9+
10+
BSDL_ENTER_NAMESPACE
11+
12+
namespace mtx {
13+
14+
template<typename BSDF_ROOT>
15+
template<typename T>
16+
BSDL_INLINE_METHOD
17+
BurleyDiffuseLobe<BSDF_ROOT>::BurleyDiffuseLobe(T* lobe,
18+
const BsdfGlobals& globals,
19+
const Data& data)
20+
: Base(lobe, globals.visible_normal(data.N), 1.0f, globals.lambda_0, false)
21+
, diff_albedo(globals.wave(data.albedo))
22+
, diff_roughness(CLAMP(data.roughness, 0.0f, 1.0f))
23+
{
24+
Base::sample_filter = globals.get_sample_filter(Base::frame.Z, true);
25+
}
26+
27+
template<typename BSDF_ROOT>
28+
BSDL_INLINE_METHOD float
29+
BurleyDiffuseLobe<BSDF_ROOT>::fresnel(float cos_theta, float F90)
30+
{
31+
const float x = CLAMP(1.0f - cos_theta, 0.0f, 1.0f);
32+
return LERP(pown<5>(x), 1.0f, F90);
33+
}
34+
35+
template<typename BSDF_ROOT>
36+
BSDL_INLINE_METHOD Sample
37+
BurleyDiffuseLobe<BSDF_ROOT>::eval_impl(const Imath::V3f& wo,
38+
const Imath::V3f& wi) const
39+
{
40+
if (wo.z <= 0.0f || wi.z <= 0.0f)
41+
return {};
42+
43+
const Imath::V3f H = wi + wo;
44+
if (MAX_ABS_XYZ(H) < EPSILON)
45+
return {};
46+
// From "Physically Based Shading at Disney" by Brent Burley, section 5.3
47+
const Imath::V3f Hn = H.normalized();
48+
const float cosHI = CLAMP(wi.dot(Hn), 0.0f, 1.0f);
49+
const float cosNO = CLAMP(wo.z, 0.0f, 1.0f);
50+
const float cosNI = CLAMP(wi.z, 0.0f, 1.0f);
51+
// Loses energy with low roughness at grazing angles. Gains it at high roughness
52+
const float F90 = 0.5f + 2.0f * diff_roughness * SQR(cosHI);
53+
const float refL = fresnel(cosNI, F90);
54+
const float refV = fresnel(cosNO, F90);
55+
const float pdf = cosNI * ONEOVERPI;
56+
57+
return { wi, diff_albedo * (refL * refV), pdf, 1.0f };
58+
}
59+
60+
template<typename BSDF_ROOT>
61+
BSDL_INLINE_METHOD Sample
62+
BurleyDiffuseLobe<BSDF_ROOT>::sample_impl(const Imath::V3f& wo,
63+
const Imath::V3f& rnd) const
64+
{
65+
if (wo.z <= 0.0f)
66+
return {};
67+
68+
Imath::V3f wi = sample_cos_hemisphere(rnd.x, rnd.y);
69+
return eval_impl(wo, wi);
70+
}
71+
72+
} // namespace mtx
73+
74+
BSDL_LEAVE_NAMESPACE

src/libbsdl/include/BSDL/MTX/bsdf_dielectric_decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ template<typename BSDF_ROOT> struct DielectricLobe : public Lobe<BSDF_ROOT> {
149149
return !dorefr ? E_ms * wo_absorption : Power::ZERO();
150150
}
151151

152+
BSDL_INLINE_METHOD Power albedo_impl() const
153+
{
154+
return !dorefr ? refl_tint * (1 - E_ms) : Power::UNIT();
155+
}
156+
152157
BSDL_INLINE_METHOD bool single_wavelength() const { return dispersion; }
153158

154159
protected:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright Contributors to the Open Shading Language project.
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4+
5+
6+
#pragma once
7+
8+
#include <BSDL/bsdf_decl.h>
9+
10+
BSDL_ENTER_NAMESPACE
11+
12+
namespace mtx {
13+
14+
template<typename BSDF_ROOT>
15+
struct OrenNayarDiffuseLobe : public Lobe<BSDF_ROOT> {
16+
using Base = Lobe<BSDF_ROOT>;
17+
18+
struct Data {
19+
Imath::V3f N;
20+
Imath::C3f albedo;
21+
float roughness;
22+
int energy_compensation;
23+
Stringhash label;
24+
using lobe_type = OrenNayarDiffuseLobe<BSDF_ROOT>;
25+
};
26+
27+
template<typename D> static typename LobeRegistry<D>::Entry entry()
28+
{
29+
static_assert(
30+
std::is_base_of<Data, D>::value); // Make no other assumptions
31+
using R = LobeRegistry<D>;
32+
return { name(),
33+
{ R::param(&D::N), R::param(&D::albedo),
34+
R::param(&D::roughness),
35+
R::param(&D::energy_compensation, "energy_compensation"),
36+
R::param(&D::label, "label"), R::close() } };
37+
}
38+
39+
template<typename T>
40+
BSDL_INLINE_METHOD OrenNayarDiffuseLobe(T*, const BsdfGlobals& globals,
41+
const Data& data);
42+
43+
static constexpr const char* name() { return "oren_nayar_diffuse_bsdf"; }
44+
45+
BSDL_INLINE_METHOD Power albedo_impl() const { return diff_albedo; }
46+
47+
BSDL_INLINE_METHOD Sample eval_impl(const Imath::V3f& wo,
48+
const Imath::V3f& wi) const;
49+
BSDL_INLINE_METHOD Sample sample_impl(const Imath::V3f& wo,
50+
const Imath::V3f& rnd) const;
51+
52+
private:
53+
BSDL_INLINE_METHOD float E_FON_analytic(float mu) const;
54+
55+
static constexpr float constant1_FON = 0.5f - 2.0f / (3.0f * PI);
56+
static constexpr float constant2_FON = 2.0f / 3.0f - 28.0f / (15.0f * PI);
57+
58+
Power diff_albedo;
59+
float diff_roughness;
60+
bool do_energy_compensation;
61+
};
62+
63+
} // namespace mtx
64+
65+
BSDL_LEAVE_NAMESPACE
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright Contributors to the Open Shading Language project.
2+
// SPDX-License-Identifier: BSD-3-Clause
3+
// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
4+
5+
6+
#pragma once
7+
8+
#include <BSDL/MTX/bsdf_oren_nayar_diffuse_decl.h>
9+
10+
BSDL_ENTER_NAMESPACE
11+
12+
namespace mtx {
13+
14+
template<typename BSDF_ROOT>
15+
template<typename T>
16+
BSDL_INLINE_METHOD
17+
OrenNayarDiffuseLobe<BSDF_ROOT>::OrenNayarDiffuseLobe(
18+
T* lobe, const BsdfGlobals& globals, const Data& data)
19+
: Base(lobe, globals.visible_normal(data.N), 1.0f, globals.lambda_0, false)
20+
, diff_albedo(globals.wave(data.albedo))
21+
, diff_roughness(CLAMP(data.roughness, 0.0f, 1.0f))
22+
, do_energy_compensation(data.energy_compensation != 0)
23+
{
24+
Base::sample_filter = globals.get_sample_filter(Base::frame.Z, true);
25+
}
26+
27+
template<typename BSDF_ROOT>
28+
BSDL_INLINE_METHOD float
29+
OrenNayarDiffuseLobe<BSDF_ROOT>::E_FON_analytic(float mu) const
30+
{
31+
const float sigma = diff_roughness;
32+
const float AF = 1.0f / (1.0f + constant1_FON * sigma);
33+
const float BF = sigma * AF;
34+
const float Si = sqrtf(std::max(0.0f, 1.0f - mu * mu));
35+
const float G
36+
= Si * (BSDLConfig::Fast::acosf(mu) - Si * mu)
37+
+ 2.0f * ((Si / std::max(mu, 1e-7f)) * (1.0f - Si * Si * Si) - Si)
38+
* (1.0f / 3.0f);
39+
return AF + (BF * ONEOVERPI) * G;
40+
}
41+
42+
template<typename BSDF_ROOT>
43+
BSDL_INLINE_METHOD Sample
44+
OrenNayarDiffuseLobe<BSDF_ROOT>::eval_impl(const Imath::V3f& wo,
45+
const Imath::V3f& wi) const
46+
{
47+
const float cosNI = CLAMP(wi.z, 0.0f, 1.0f);
48+
const float cosNO = CLAMP(wo.z, 0.0f, 1.0f);
49+
if (cosNI <= 0.0f || cosNO <= 0.0f)
50+
return {};
51+
52+
const float cosIO = CLAMP(wo.dot(wi), -1.0f, 1.0f);
53+
const float s = cosIO - cosNI * cosNO;
54+
const float pdf = cosNI * ONEOVERPI;
55+
56+
if (!do_energy_compensation) {
57+
// Simplified math from: "A tiny improvement of Oren-Nayar reflectance model"
58+
// by Yasuhiro Fujii
59+
// http://mimosa-pudica.net/improved-oren-nayar.html
60+
// NOTE: This is using the math to match the original qualitative ON model
61+
// (QON in the paper above) and not the tweak proposed in the text which
62+
// is a slightly different BRDF (FON in the paper above). This is done for
63+
// backwards compatibility purposes only.
64+
const float s2 = SQR(diff_roughness);
65+
const float A = 1.0f - 0.50f * s2 / (s2 + 0.33f);
66+
const float B = 0.45f * s2 / (s2 + 0.09f);
67+
const float stinv = s > 0.0f ? s / std::max(cosNI, cosNO) : 0.0f;
68+
const float f_ss = A + B * stinv;
69+
return { wi, diff_albedo * f_ss, pdf, 1.0f };
70+
} else {
71+
// Code below from Jamie Portsmouth's tech report on Energy conversion Oren-Nayar
72+
// See slack thread for whitepaper:
73+
// https://academysoftwarefdn.slack.com/files/U03SWQFPD08/F06S50CUKV1/oren_nayar.pdf
74+
// rho should be the albedo which is a parameter of the closure in the Mx parameters
75+
// This only matters for the color-saturation aspect of the BRDF which is rather subtle anyway
76+
// and not always desireable for artists. Hardcoding to 1 leaves the coloring entirely up to the
77+
// closure weight.
78+
const float AF = 1.0f / (1.0f + constant1_FON * diff_roughness);
79+
const float stinv = s > 0.0f ? s / std::max(cosNI, cosNO) : s;
80+
const float f_ss = AF * (1.0f + diff_roughness * stinv);
81+
const float EFo = E_FON_analytic(cosNO);
82+
const float EFi = E_FON_analytic(cosNI);
83+
const float avgEF = AF * (1.0f + constant2_FON * diff_roughness);
84+
85+
const Power rho_ms(
86+
[&](int i) {
87+
return SQR(diff_albedo[i]) * avgEF
88+
/ (1 - diff_albedo[i] * std::max(0.0f, 1.0f - avgEF));
89+
},
90+
1);
91+
const float f_ms = std::max(1e-7f, 1.0f - EFo)
92+
* std::max(1e-7f, 1.0f - EFi)
93+
/ std::max(1e-7f, 1.0f - avgEF);
94+
95+
return { wi, diff_albedo * f_ss + rho_ms * f_ms, pdf, 1.0f };
96+
}
97+
}
98+
99+
template<typename BSDF_ROOT>
100+
BSDL_INLINE_METHOD Sample
101+
OrenNayarDiffuseLobe<BSDF_ROOT>::sample_impl(const Imath::V3f& wo,
102+
const Imath::V3f& rnd) const
103+
{
104+
if (wo.z <= 0.0f)
105+
return {};
106+
107+
const Imath::V3f wi = sample_cos_hemisphere(rnd.x, rnd.y);
108+
return eval_impl(wo, wi);
109+
}
110+
111+
} // namespace mtx
112+
113+
BSDL_LEAVE_NAMESPACE

src/libbsdl/include/BSDL/MTX/bsdf_schlick_decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ template<typename BSDF_ROOT> struct SchlickLobe : public Lobe<BSDF_ROOT> {
7373
return !dorefr ? Power(E_ms, 1) : Power::ZERO();
7474
}
7575

76+
BSDL_INLINE_METHOD Power albedo_impl() const
77+
{
78+
return !dorefr ? refl_tint * (1 - E_ms) : Power::UNIT();
79+
}
80+
7681
protected:
7782
BSDL_INLINE_METHOD Power get_tint(float cosNI) const;
7883

src/libbsdl/include/BSDL/MTX/bsdf_sheen_decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ template<typename BSDF_ROOT> struct SheenLobe : public Lobe<BSDF_ROOT> {
4141

4242
static constexpr const char* name() { return "sheen_bsdf"; }
4343

44-
BSDL_INLINE_METHOD Power albedo_impl() const { return Power(1 - Emiss, 1); }
44+
BSDL_INLINE_METHOD Power albedo_impl() const { return tint * (1 - Emiss); }
4545
BSDL_INLINE_METHOD Power filter_o(const Imath::V3f& wo) const
4646
{
4747
return Power(Emiss, 1);

0 commit comments

Comments
 (0)