Skip to content

Commit 1b42acd

Browse files
Proposed improvements to energy conservation
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>
1 parent ddb959e commit 1b42acd

File tree

2 files changed

+74
-3
lines changed

2 files changed

+74
-3
lines changed

src/testrender/shading.cpp

Lines changed: 1 addition & 3 deletions
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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,41 @@ 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) +
152+
Vec2(-0.6303f, -2.323f) * x +
153+
Vec2(9.748f, 2.229f) * y +
154+
Vec2(-2.038f, -3.748f) * x * y +
155+
Vec2(29.34f, 1.424f) * x2 +
156+
Vec2(-8.245f, -0.7684f) * y2 +
157+
Vec2(-26.44f, 1.436f) * x2 * y +
158+
Vec2(19.99f, 0.2913f) * x * y2 +
159+
Vec2(-5.448f, 0.6286f) * x2 * y2;
160+
Vec2 den = Vec2(1.0f, 1.0f) +
161+
Vec2(-1.765f, 0.2281f) * x +
162+
Vec2(8.263f, 15.94f) * y +
163+
Vec2(11.53f, -55.83f) * x * y +
164+
Vec2(28.96f, 13.08f) * x2 +
165+
Vec2(-7.507f, 41.26f) * y2 +
166+
Vec2(-36.11f, 54.9f) * x2 * y +
167+
Vec2(15.86f, 300.2f) * x * y2 +
168+
Vec2(33.37f, -285.1f) * x2 * y2;
169+
float a = OIIO::clamp(num.x / den.x, 0.0f, 1.0f);
170+
float b = OIIO::clamp(num.y / den.y, 0.0f, 1.0f);
171+
return reflection_tint * (f0 * a + f90 * b);
172+
}
138173
};
139174

140175
struct MxConductorParams : public MxMicrofacetBaseParams {
@@ -151,6 +186,13 @@ struct MxConductorParams : public MxMicrofacetBaseParams {
151186

152187
OSL_HOSTDEVICE Color3 evalT(float cos_theta) const { return Color3(0.0f); }
153188

189+
OSL_HOSTDEVICE Color3 dirAlbedoR(float cos_theta) const
190+
{
191+
// TODO: Integrate the MaterialX fit for GGX directional albedo, which
192+
// may improve multiscatter compensation for conductors.
193+
return evalR(cos_theta);
194+
}
195+
154196
// Avoid function was declared but never referenced
155197
// float get_ior() const
156198
// {
@@ -180,6 +222,37 @@ struct MxGeneralizedSchlickParams : public MxMicrofacetBaseParams {
180222
* (Color3(1.0f)
181223
- fresnel_generalized_schlick(cos_theta, f0, f90, exponent));
182224
}
225+
226+
OSL_HOSTDEVICE Color3 dirAlbedoR(float cos_theta) const
227+
{
228+
// Rational quadratic fit for GGX directional albedo
229+
// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl
230+
float x = OIIO::clamp(cos_theta, 0.0f, 1.0f);
231+
float y = sqrtf(roughness_x * roughness_y); // average alpha
232+
float x2 = x * x;
233+
float y2 = y * y;
234+
Vec2 num = Vec2(0.1003f, 0.9345f) +
235+
Vec2(-0.6303f, -2.323f) * x +
236+
Vec2(9.748f, 2.229f) * y +
237+
Vec2(-2.038f, -3.748f) * x * y +
238+
Vec2(29.34f, 1.424f) * x2 +
239+
Vec2(-8.245f, -0.7684f) * y2 +
240+
Vec2(-26.44f, 1.436f) * x2 * y +
241+
Vec2(19.99f, 0.2913f) * x * y2 +
242+
Vec2(-5.448f, 0.6286f) * x2 * y2;
243+
Vec2 den = Vec2(1.0f, 1.0f) +
244+
Vec2(-1.765f, 0.2281f) * x +
245+
Vec2(8.263f, 15.94f) * y +
246+
Vec2(11.53f, -55.83f) * x * y +
247+
Vec2(28.96f, 13.08f) * x2 +
248+
Vec2(-7.507f, 41.26f) * y2 +
249+
Vec2(-36.11f, 54.9f) * x2 * y +
250+
Vec2(15.86f, 300.2f) * x * y2 +
251+
Vec2(33.37f, -285.1f) * x2 * y2;
252+
float a = OIIO::clamp(num.x / den.x, 0.0f, 1.0f);
253+
float b = OIIO::clamp(num.y / den.y, 0.0f, 1.0f);
254+
return reflection_tint * (f0 * a + f90 * b);
255+
}
183256
};
184257

185258
struct MxTranslucentParams {

0 commit comments

Comments
 (0)