Skip to content

Commit ac63a5a

Browse files
testrender: Improvements to energy conservation between layered BSDFs (#1935)
This changelist proposes improvements to the energy conservation between layered BSDFs in OSL. The rational quadratic fit for GGX directional albedo from the MaterialX project has been integrated into `dielectric_bsdf` and `generalized_schlick_bsdf`, improving visual parity with MaterialX GLSL and MDL. Signed-off-by: Jonathan Stone <jstone@lucasfilm.com> --------- Signed-off-by: Jonathan Stone <jstone@lucasfilm.com> Signed-off-by: Larry Gritz <lg@larrygritz.com> Co-authored-by: Larry Gritz <lg@larrygritz.com>
1 parent ffc5b90 commit ac63a5a

File tree

5 files changed

+62
-3
lines changed

5 files changed

+62
-3
lines changed

src/testrender/shading.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -885,10 +885,8 @@ struct MxMicrofacet final : public BSDF, MxMicrofacetParams {
885885
// if transmission is enabled, punt on
886886
if (EnableTransmissionLobe)
887887
return Color3(1.0f);
888-
// FIXME: this heuristic is not particularly good, and looses energy
889-
// compared to the reference solution
890888

891-
return MxMicrofacetParams::evalR(
889+
return MxMicrofacetParams::dirAlbedoR(
892890
get_fresnel_angle(MxMicrofacetParams::N.dot(wo)));
893891
}
894892

src/testrender/shading.h

+61
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,35 @@ struct MxDielectricParams : public MxMicrofacetBaseParams {
135135
{
136136
return transmission_tint * (1.0f - fresnel_dielectric(cos_theta, ior));
137137
}
138+
139+
OSL_HOSTDEVICE Color3 dirAlbedoR(float cos_theta) const
140+
{
141+
float iorRatio = (ior - 1.0f) / (ior + 1.0f);
142+
Color3 f0(iorRatio * iorRatio);
143+
Color3 f90(1.0f);
144+
145+
// Rational quadratic fit for GGX directional albedo
146+
// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl
147+
float x = OIIO::clamp(cos_theta, 0.0f, 1.0f);
148+
float y = sqrtf(roughness_x * roughness_y); // average alpha
149+
float x2 = x * x;
150+
float y2 = y * y;
151+
Vec2 num = Vec2(0.1003f, 0.9345f) + Vec2(-0.6303f, -2.323f) * x
152+
+ Vec2(9.748f, 2.229f) * y + Vec2(-2.038f, -3.748f) * x * y
153+
+ Vec2(29.34f, 1.424f) * x2 + Vec2(-8.245f, -0.7684f) * y2
154+
+ Vec2(-26.44f, 1.436f) * x2 * y
155+
+ Vec2(19.99f, 0.2913f) * x * y2
156+
+ Vec2(-5.448f, 0.6286f) * x2 * y2;
157+
Vec2 den = Vec2(1.0f, 1.0f) + Vec2(-1.765f, 0.2281f) * x
158+
+ Vec2(8.263f, 15.94f) * y + Vec2(11.53f, -55.83f) * x * y
159+
+ Vec2(28.96f, 13.08f) * x2 + Vec2(-7.507f, 41.26f) * y2
160+
+ Vec2(-36.11f, 54.9f) * x2 * y
161+
+ Vec2(15.86f, 300.2f) * x * y2
162+
+ Vec2(33.37f, -285.1f) * x2 * y2;
163+
float a = OIIO::clamp(num.x / den.x, 0.0f, 1.0f);
164+
float b = OIIO::clamp(num.y / den.y, 0.0f, 1.0f);
165+
return reflection_tint * (f0 * a + f90 * b);
166+
}
138167
};
139168

140169
struct MxConductorParams : public MxMicrofacetBaseParams {
@@ -151,6 +180,13 @@ struct MxConductorParams : public MxMicrofacetBaseParams {
151180

152181
OSL_HOSTDEVICE Color3 evalT(float cos_theta) const { return Color3(0.0f); }
153182

183+
OSL_HOSTDEVICE Color3 dirAlbedoR(float cos_theta) const
184+
{
185+
// TODO: Integrate the MaterialX fit for GGX directional albedo, which
186+
// may improve multiscatter compensation for conductors.
187+
return evalR(cos_theta);
188+
}
189+
154190
// Avoid function was declared but never referenced
155191
// float get_ior() const
156192
// {
@@ -180,6 +216,31 @@ struct MxGeneralizedSchlickParams : public MxMicrofacetBaseParams {
180216
* (Color3(1.0f)
181217
- fresnel_generalized_schlick(cos_theta, f0, f90, exponent));
182218
}
219+
220+
OSL_HOSTDEVICE Color3 dirAlbedoR(float cos_theta) const
221+
{
222+
// Rational quadratic fit for GGX directional albedo
223+
// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl
224+
float x = OIIO::clamp(cos_theta, 0.0f, 1.0f);
225+
float y = sqrtf(roughness_x * roughness_y); // average alpha
226+
float x2 = x * x;
227+
float y2 = y * y;
228+
Vec2 num = Vec2(0.1003f, 0.9345f) + Vec2(-0.6303f, -2.323f) * x
229+
+ Vec2(9.748f, 2.229f) * y + Vec2(-2.038f, -3.748f) * x * y
230+
+ Vec2(29.34f, 1.424f) * x2 + Vec2(-8.245f, -0.7684f) * y2
231+
+ Vec2(-26.44f, 1.436f) * x2 * y
232+
+ Vec2(19.99f, 0.2913f) * x * y2
233+
+ Vec2(-5.448f, 0.6286f) * x2 * y2;
234+
Vec2 den = Vec2(1.0f, 1.0f) + Vec2(-1.765f, 0.2281f) * x
235+
+ Vec2(8.263f, 15.94f) * y + Vec2(11.53f, -55.83f) * x * y
236+
+ Vec2(28.96f, 13.08f) * x2 + Vec2(-7.507f, 41.26f) * y2
237+
+ Vec2(-36.11f, 54.9f) * x2 * y
238+
+ Vec2(15.86f, 300.2f) * x * y2
239+
+ Vec2(33.37f, -285.1f) * x2 * y2;
240+
float a = OIIO::clamp(num.x / den.x, 0.0f, 1.0f);
241+
float b = OIIO::clamp(num.y / den.y, 0.0f, 1.0f);
242+
return reflection_tint * (f0 * a + f90 * b);
243+
}
183244
};
184245

185246
struct MxTranslucentParams {
Binary file not shown.
Binary file not shown.
-10 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)