From 8cb9ae1aebf078e009ab1d7def304c5df5d6b5e6 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Mon, 1 Apr 2024 14:37:10 -0700 Subject: [PATCH] GLSL improvements to Oren-Nayar diffuse (#1756) - Remove an extra factor of PI in the GLSL computation of Oren-Nayar diffuse, improving its alignment with corresponding implementations in OSL and MDL. - Include the required directional albedo factor when computing GLSL environment lighting for Oren-Nayar diffuse. - Add an analytic approximation for the directional albedo of Oren-Nayar diffuse, using a rational quadratic fit to Monte Carlo data. - Generalize the interfaces of mx_oren_nayar_diffuse and mx_burley_diffuse, enabling their use in tangent-space computations. --- .../genglsl/lib/mx_microfacet_diffuse.glsl | 81 ++++++++++++++++--- .../genglsl/mx_burley_diffuse_bsdf.glsl | 4 +- .../genglsl/mx_oren_nayar_diffuse_bsdf.glsl | 9 ++- .../TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx | 14 ---- .../pbrlib/bsdf/oren_nayar_diffuse.mtlx | 51 ++++++++++++ ...iffuse_btdf.mtlx => translucent_bsdf.mtlx} | 6 +- 6 files changed, 134 insertions(+), 31 deletions(-) delete mode 100644 resources/Materials/TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx create mode 100644 resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx rename resources/Materials/TestSuite/pbrlib/bsdf/{diffuse_btdf.mtlx => translucent_bsdf.mtlx} (71%) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl index 7a0ed28151..83d649ecca 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl @@ -1,29 +1,88 @@ #include "mx_microfacet.glsl" -// Based on the OSL implementation of Oren-Nayar diffuse, which is in turn -// based on https://mimosa-pudica.net/improved-oren-nayar.html. -float mx_oren_nayar_diffuse(vec3 L, vec3 V, vec3 N, float NdotL, float roughness) +// Based on the implementation of Oren-Nayar diffuse in Open Shading Language. +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage/blob/main/src/testrender/shading.cpp +float mx_oren_nayar_diffuse(float NdotV, float NdotL, float LdotV, float roughness) { - float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); float s = LdotV - NdotL * NdotV; float stinv = (s > 0.0f) ? s / max(NdotL, NdotV) : 0.0; - float sigma2 = mx_square(roughness * M_PI); + float sigma2 = mx_square(roughness); float A = 1.0 - 0.5 * (sigma2 / (sigma2 + 0.33)); float B = 0.45 * sigma2 / (sigma2 + 0.09); return A + B * stinv; } +// Rational quadratic fit to Monte Carlo data for Oren-Nayar directional albedo. +float mx_oren_nayar_diffuse_dir_albedo_analytic(float NdotV, float roughness) +{ + vec2 r = vec2(1.0, 1.0) + + vec2(-0.4297, -0.6076) * roughness + + vec2(-0.7632, -0.4993) * NdotV * roughness + + vec2(1.4385, 2.0315) * mx_square(roughness); + return r.x / r.y; +} + +float mx_oren_nayar_diffuse_dir_albedo_table_lookup(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 1 + if (textureSize($albedoTable, 0).x > 1) + { + return texture($albedoTable, vec2(NdotV, roughness)).b; + } +#endif + return 0.0; +} + +float mx_oren_nayar_diffuse_dir_albedo_monte_carlo(float NdotV, float roughness) +{ + NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0); + vec3 V = vec3(sqrt(1.0f - mx_square(NdotV)), 0, NdotV); + + float radiance = 0.0; + const int SAMPLE_COUNT = 64; + for (int i = 0; i < SAMPLE_COUNT; i++) + { + vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT); + + // Compute the incoming light direction. + vec3 L = mx_uniform_sample_hemisphere(Xi); + + // Compute dot products for this sample. + float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0); + float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); + + // Compute diffuse reflectance. + float reflectance = mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness); + + // Add the radiance contribution of this sample. + // uniform_pdf = 1 / (2 * PI) + // radiance = (reflectance * NdotL) / (uniform_pdf * PI); + radiance += reflectance * NdotL; + } + + // Apply global components and normalize. + radiance *= 2.0 / float(SAMPLE_COUNT); + + // Return the final directional albedo. + return radiance; +} + +float mx_oren_nayar_diffuse_dir_albedo(float NdotV, float roughness) +{ +#if DIRECTIONAL_ALBEDO_METHOD == 2 + float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_monte_carlo(NdotV, roughness); +#else + float dirAlbedo = mx_oren_nayar_diffuse_dir_albedo_analytic(NdotV, roughness); +#endif + return clamp(dirAlbedo, 0.0, 1.0); +} + // https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf // Section 5.3 -float mx_burley_diffuse(vec3 L, vec3 V, vec3 N, float NdotL, float roughness) +float mx_burley_diffuse(float NdotV, float NdotL, float LdotH, float roughness) { - vec3 H = normalize(L + V); - float LdotH = clamp(dot(L, H), M_FLOAT_EPS, 1.0); - float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - float F90 = 0.5 + (2.0 * roughness * mx_square(LdotH)); float refL = mx_fresnel_schlick(NdotL, 1.0, F90); float refV = mx_fresnel_schlick(NdotV, 1.0, F90); diff --git a/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl b/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl index ddf2fe4710..d9562d251a 100644 --- a/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl @@ -11,10 +11,12 @@ void mx_burley_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, normal = mx_forward_facing_normal(normal, V); + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0); + float LdotH = clamp(dot(L, normalize(L + V)), M_FLOAT_EPS, 1.0); bsdf.response = color * occlusion * weight * NdotL * M_PI_INV; - bsdf.response *= mx_burley_diffuse(L, V, normal, NdotL, roughness); + bsdf.response *= mx_burley_diffuse(NdotV, NdotL, LdotH, roughness); } void mx_burley_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf) diff --git a/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl b/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl index e32590d1e5..e80c413c29 100644 --- a/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl @@ -11,12 +11,14 @@ void mx_oren_nayar_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusi normal = mx_forward_facing_normal(normal, V); + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0); + float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0); bsdf.response = color * occlusion * weight * NdotL * M_PI_INV; if (roughness > 0.0) { - bsdf.response *= mx_oren_nayar_diffuse(L, V, normal, NdotL, roughness); + bsdf.response *= mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness); } } @@ -31,6 +33,9 @@ void mx_oren_nayar_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float normal = mx_forward_facing_normal(normal, V); - vec3 Li = mx_environment_irradiance(normal); + float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0); + + vec3 Li = mx_environment_irradiance(normal) * + mx_oren_nayar_diffuse_dir_albedo(NdotV, roughness); bsdf.response = Li * color * weight; } diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx deleted file mode 100644 index 6755bdae1b..0000000000 --- a/resources/Materials/TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx new file mode 100644 index 0000000000..3b2fdb8497 --- /dev/null +++ b/resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/diffuse_btdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx similarity index 71% rename from resources/Materials/TestSuite/pbrlib/bsdf/diffuse_btdf.mtlx rename to resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx index 6c9da887ed..0609ab6b44 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/diffuse_btdf.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/translucent_bsdf.mtlx @@ -1,12 +1,12 @@ - - + + - +