From ce08d4f14b7b9ff215065bfd0968cabbbb6b7657 Mon Sep 17 00:00:00 2001 From: Jonathan Stone Date: Wed, 12 Feb 2025 19:41:48 -0800 Subject: [PATCH] Additional HW closure improvements (#2227) - Simplify references to closureData.occlusion across BSDFs. - Merge and simplify code paths in chiang_hair_bsdf. --- .../genglsl/mx_burley_diffuse_bsdf.glsl | 3 +- .../pbrlib/genglsl/mx_chiang_hair_bsdf.glsl | 161 ++++++++---------- .../pbrlib/genglsl/mx_conductor_bsdf.glsl | 3 +- .../pbrlib/genglsl/mx_dielectric_bsdf.glsl | 3 +- .../genglsl/mx_generalized_schlick_bsdf.glsl | 3 +- .../genglsl/mx_oren_nayar_diffuse_bsdf.glsl | 3 +- libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl | 5 +- 7 files changed, 76 insertions(+), 105 deletions(-) diff --git a/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl b/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl index fa2e21699f..1399758e3d 100644 --- a/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl @@ -12,7 +12,6 @@ void mx_burley_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, f vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -22,7 +21,7 @@ void mx_burley_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, f float NdotL = clamp(dot(N, 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 = color * closureData.occlusion * weight * NdotL * M_PI_INV; bsdf.response *= mx_burley_diffuse(NdotV, NdotL, LdotH, roughness); } else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) diff --git a/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl index c9e49a9302..54853843d3 100644 --- a/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl @@ -186,113 +186,90 @@ void mx_hair_attenuation(float f, vec3 T, out vec3 Ap[4]) // Ap Ap[3] = Ap[2] * T * f / (vec3(1.0) - T * f); } -vec3 mx_chiang_hair_bsdf_impl( - vec3 L, - vec3 V, - vec3 tint_R, - vec3 tint_TT, - vec3 tint_TRT, - float ior, - vec2 roughness_R, - vec2 roughness_TT, - vec2 roughness_TRT, - float cuticle_angle, - vec3 absorption_coefficient, - vec3 N, - vec3 X -) -{ - N = mx_forward_facing_normal(N, V); - X = normalize(X - dot(X, N) * N); - vec3 Y = cross(N, X); - - float sinThetaO = dot(V, X); - float sinThetaI = dot(L, X); - float cosThetaO = mx_hair_transform_sin_cos(sinThetaO); - float cosThetaI = mx_hair_transform_sin_cos(sinThetaI); - - float y1 = dot(L, N); - float x1 = dot(L, Y); - float y2 = dot(V, N); - float x2 = dot(V, Y); - float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); - - vec3 k1_p = normalize(V - X * dot(V, X)); - float cosGammaO = dot(N, k1_p); - float sinGammaO = mx_hair_transform_sin_cos(cosGammaO); - if (dot(k1_p, Y) > 0.0) - sinGammaO = -sinGammaO; - float gammaO = asin(sinGammaO); - - float sinThetaT = sinThetaO / ior; - float cosThetaT = mx_hair_transform_sin_cos(sinThetaT); - float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, 1e-8); - float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0); - float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT); - float gammaT = asin(sinGammaT); - - // attenuation - vec3 Ap[4]; - float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior); - vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT)); - mx_hair_attenuation(fresnel, T, Ap); - - // parameters for each lobe - vec2 angles[4]; - float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2] - mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles); - - vec3 tint[4]; - tint[0] = tint_R; - tint[1] = tint_TT; - tint[2] = tint_TRT; - tint[3] = tint_TRT; - - roughness_R = clamp(roughness_R, 0.001, 1.0); - roughness_TT = clamp(roughness_TT, 0.001, 1.0); - roughness_TRT = clamp(roughness_TRT, 0.001, 1.0); - - vec2 vs[4]; - vs[0] = roughness_R; - vs[1] = roughness_TT; - vs[2] = roughness_TRT; - vs[3] = roughness_TRT; - - // R, TT, TRT, TRRT+ - vec3 F = vec3(0.0); - for (int i = 0; i <= 3; ++i) - { - tint[i] = max(tint[i], vec3(0.0)); - float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x); - float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT); - F += Mp * Np * tint[i] * Ap[i]; - } - - return F; -} - void mx_chiang_hair_bsdf(ClosureData closureData, vec3 tint_R, vec3 tint_TT, vec3 tint_TRT, float ior, vec2 roughness_R, vec2 roughness_TT, vec2 roughness_TRT, float cuticle_angle, vec3 absorption_coefficient, vec3 N, vec3 X, inout BSDF bsdf) { vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; + + N = mx_forward_facing_normal(N, V); bsdf.throughput = vec3(0.0); if (closureData.closureType == CLOSURE_TYPE_REFLECTION) { - vec3 F = mx_chiang_hair_bsdf_impl(L, V, tint_R, tint_TT, tint_TRT, ior, - roughness_R, roughness_TT, roughness_TRT, cuticle_angle, - absorption_coefficient, N, X); - bsdf.response = F * occlusion * M_PI_INV; + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + + float sinThetaO = dot(V, X); + float sinThetaI = dot(L, X); + float cosThetaO = mx_hair_transform_sin_cos(sinThetaO); + float cosThetaI = mx_hair_transform_sin_cos(sinThetaI); + + float y1 = dot(L, N); + float x1 = dot(L, Y); + float y2 = dot(V, N); + float x2 = dot(V, Y); + float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2); + + vec3 k1_p = normalize(V - X * dot(V, X)); + float cosGammaO = dot(N, k1_p); + float sinGammaO = mx_hair_transform_sin_cos(cosGammaO); + if (dot(k1_p, Y) > 0.0) + sinGammaO = -sinGammaO; + float gammaO = asin(sinGammaO); + + float sinThetaT = sinThetaO / ior; + float cosThetaT = mx_hair_transform_sin_cos(sinThetaT); + float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, M_FLOAT_EPS); + float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0); + float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT); + float gammaT = asin(sinGammaT); + + // attenuation + vec3 Ap[4]; + float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior); + vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT)); + mx_hair_attenuation(fresnel, T, Ap); + + // parameters for each lobe + vec2 angles[4]; + float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2] + mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles); + + vec3 tint[4]; + tint[0] = tint_R; + tint[1] = tint_TT; + tint[2] = tint_TRT; + tint[3] = tint_TRT; + + roughness_R = clamp(roughness_R, 0.001, 1.0); + roughness_TT = clamp(roughness_TT, 0.001, 1.0); + roughness_TRT = clamp(roughness_TRT, 0.001, 1.0); + + vec2 vs[4]; + vs[0] = roughness_R; + vs[1] = roughness_TT; + vs[2] = roughness_TRT; + vs[3] = roughness_TRT; + + // R, TT, TRT, TRRT+ + vec3 F = vec3(0.0); + for (int i = 0; i <= 3; ++i) + { + tint[i] = max(tint[i], vec3(0.0)); + float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x); + float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT); + F += Mp * Np * tint[i] * Ap[i]; + } + + bsdf.response = F * closureData.occlusion * M_PI_INV; } else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) { // This indirect term is a *very* rough approximation. - N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); FresnelData fd = mx_init_fresnel_dielectric(ior, 0.0, 1.0); vec3 F = mx_compute_fresnel(NdotV, fd); @@ -301,7 +278,7 @@ void mx_chiang_hair_bsdf(ClosureData closureData, vec3 tint_R, vec3 tint_TT, vec vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); float avgAlpha = mx_average_alpha(safeAlpha); - // Use GGX because the environment map for FIS is preintegrated with GGX. + // Use GGX to match the behavior of mx_environment_radiance. float F0 = mx_ior_to_f0(ior); vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; diff --git a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl index 3506f4a096..633f6d0d50 100644 --- a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl @@ -12,7 +12,6 @@ void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 i vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -40,7 +39,7 @@ void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 i vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F); // Note: NdotL is cancelled out - bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); + bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV); } else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) { diff --git a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl index 87a32d4590..4c59b21802 100644 --- a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl @@ -14,7 +14,6 @@ void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -45,7 +44,7 @@ void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp; bsdf.throughput = 1.0 - dirAlbedo * weight; - bsdf.response = D * F * G * comp * safeTint * occlusion * weight / (4.0 * NdotV); + bsdf.response = D * F * G * comp * safeTint * closureData.occlusion * weight / (4.0 * NdotV); } else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION) { diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index 79cb87cf1c..08c7311495 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -14,7 +14,6 @@ void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 col vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -48,7 +47,7 @@ void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 col bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight); // Note: NdotL is cancelled out - bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV); + bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV); } else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION) { diff --git a/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl b/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl index 190ac11f32..173a0abb6d 100644 --- a/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl @@ -12,7 +12,6 @@ void mx_oren_nayar_diffuse_bsdf(ClosureData closureData, float weight, vec3 colo vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -25,7 +24,7 @@ void mx_oren_nayar_diffuse_bsdf(ClosureData closureData, float weight, vec3 colo vec3 diffuse = energy_compensation ? mx_oren_nayar_compensated_diffuse(NdotV, NdotL, LdotV, roughness, color) : mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness) * color; - bsdf.response = diffuse * occlusion * weight * NdotL * M_PI_INV; + bsdf.response = diffuse * closureData.occlusion * weight * NdotL * M_PI_INV; } else if (closureData.closureType == CLOSURE_TYPE_INDIRECT) { diff --git a/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl b/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl index 505446dc74..203e47b81d 100644 --- a/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl @@ -10,7 +10,6 @@ void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roug vec3 V = closureData.V; vec3 L = closureData.L; - float occlusion = closureData.occlusion; N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); @@ -30,7 +29,7 @@ void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roug // We need to include NdotL from the light integral here // as in this case it's not cancelled out by the BRDF denominator. - bsdf.response = fr * NdotL * occlusion * weight; + bsdf.response = fr * NdotL * closureData.occlusion * weight; } else { @@ -38,7 +37,7 @@ void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roug vec3 fr = color * mx_zeltner_sheen_brdf(L, V, N, NdotV, roughness); dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness); - bsdf.response = dirAlbedo * fr * occlusion * weight; + bsdf.response = dirAlbedo * fr * closureData.occlusion * weight; } } else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)