Skip to content

Commit

Permalink
GLSL improvements to Oren-Nayar diffuse (AcademySoftwareFoundation#1756)
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
jstone-lucasfilm authored Apr 1, 2024
1 parent 5903479 commit 8cb9ae1
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 31 deletions.
81 changes: 70 additions & 11 deletions libraries/pbrlib/genglsl/lib/mx_microfacet_diffuse.glsl
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
4 changes: 3 additions & 1 deletion libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 7 additions & 2 deletions libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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;
}
14 changes: 0 additions & 14 deletions resources/Materials/TestSuite/pbrlib/bsdf/diffuse_brdf.mtlx

This file was deleted.

51 changes: 51 additions & 0 deletions resources/Materials/TestSuite/pbrlib/bsdf/oren_nayar_diffuse.mtlx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0"?>
<materialx version="1.38">
<nodegraph name="oren_nayar_diffuse">

<oren_nayar_diffuse_bsdf name="diffuse1" type="BSDF">
<input name="color" type="color3" value="0.6, 0.6, 0.6" />
<input name="roughness" type="float" value="0.0" />
</oren_nayar_diffuse_bsdf>
<surface name="surface1" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse1" />
</surface>
<output name="out1" type="surfaceshader" nodename="surface1" />

<oren_nayar_diffuse_bsdf name="diffuse2" type="BSDF">
<input name="color" type="color3" value="0.6, 0.6, 0.6" />
<input name="roughness" type="float" value="0.25" />
</oren_nayar_diffuse_bsdf>
<surface name="surface2" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse2" />
</surface>
<output name="out2" type="surfaceshader" nodename="surface2" />

<oren_nayar_diffuse_bsdf name="diffuse3" type="BSDF">
<input name="color" type="color3" value="0.6, 0.6, 0.6" />
<input name="roughness" type="float" value="0.5" />
</oren_nayar_diffuse_bsdf>
<surface name="surface3" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse3" />
</surface>
<output name="out3" type="surfaceshader" nodename="surface3" />

<oren_nayar_diffuse_bsdf name="diffuse4" type="BSDF">
<input name="color" type="color3" value="0.6, 0.6, 0.6" />
<input name="roughness" type="float" value="0.75" />
</oren_nayar_diffuse_bsdf>
<surface name="surface4" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse4" />
</surface>
<output name="out4" type="surfaceshader" nodename="surface4" />

<oren_nayar_diffuse_bsdf name="diffuse5" type="BSDF">
<input name="color" type="color3" value="0.6, 0.6, 0.6" />
<input name="roughness" type="float" value="1.0" />
</oren_nayar_diffuse_bsdf>
<surface name="surface5" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse5" />
</surface>
<output name="out5" type="surfaceshader" nodename="surface5" />

</nodegraph>
</materialx>
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0"?>
<materialx version="1.38">
<nodegraph name="test_diffuse_btdf">
<translucent_bsdf name="diffuse_btdf1" type="BSDF">
<nodegraph name="translucent_bsdf">
<translucent_bsdf name="translucent_bsdf" type="BSDF">
<input name="weight" type="float" value="0.6" />
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
</translucent_bsdf>
<surface name="surface1" type="surfaceshader">
<input name="bsdf" type="BSDF" nodename="diffuse_btdf1" />
<input name="bsdf" type="BSDF" nodename="translucent_bsdf" />
<input name="opacity" type="float" value="1.0" />
</surface>
<output name="out" type="surfaceshader" nodename="surface1" />
Expand Down

0 comments on commit 8cb9ae1

Please sign in to comment.