From 9cfe69b0d0f248c69f384514601545ecd7418744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Thu, 18 Aug 2022 11:38:02 +0200 Subject: [PATCH 01/11] Improve thin-film effect. Add support for base layer wavelength-dependent complex refraction index. Add (limited) support for thin-film to generalized_schlick_bsdf. --- .../genglsl/lib/mx_microfacet_specular.glsl | 235 +++++++++++------- .../genglsl/mx_generalized_schlick_bsdf.glsl | 6 +- .../TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx | 20 ++ 3 files changed, 165 insertions(+), 96 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 24f6eaca03..0db2c11aef 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -227,6 +227,12 @@ float mx_f0_to_ior(float F0) return (1.0 + sqrtF0) / (1.0 - sqrtF0); } +vec3 mx_f0_to_ior_colored(vec3 F0) +{ + vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99)); + return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0); +} + // https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ float mx_fresnel_dielectric(float cosTheta, float ior) { @@ -247,11 +253,11 @@ float mx_fresnel_dielectric(float cosTheta, float ior) } // https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ -vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) +void mx_fresnel_conductor_polarized(vec3 cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) { - cosTheta = clamp(cosTheta, 0.0, 1.0); - float cosTheta2 = cosTheta * cosTheta; - float sinTheta2 = 1.0 - cosTheta2; + cosTheta = clamp(cosTheta, vec3(0.0), vec3(1.0)); + vec3 cosTheta2 = cosTheta * cosTheta; + vec3 sinTheta2 = 1.0 - cosTheta2; vec3 n2 = n * n; vec3 k2 = k * k; @@ -260,138 +266,177 @@ vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) vec3 t1 = a2plusb2 + cosTheta2; vec3 a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); vec3 t2 = 2.0 * a * cosTheta; - vec3 rs = (t1 - t2) / (t1 + t2); + Rs = (t1 - t2) / (t1 + t2); vec3 t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2; vec3 t4 = t2 * sinTheta2; - vec3 rp = rs * (t3 - t4) / (t3 + t4); - - return 0.5 * (rp + rs); + Rp = Rs * (t3 - t4) / (t3 + t4); } -// Fresnel for dielectric/dielectric interface and polarized light. -void mx_fresnel_dielectric_polarized(float cosTheta, float n1, float n2, out vec2 F, out vec2 phi) +void mx_fresnel_conductor_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) { - float eta2 = mx_square(n1 / n2); - float st2 = 1.0 - cosTheta*cosTheta; - - // Check for total internal reflection - if(eta2*st2 > 1.0) - { - F = vec2(1.0); - float s = sqrt(st2 - 1.0/eta2) / cosTheta; - phi = 2.0 * atan(vec2(-eta2 * s, -s)); - return; - } - - float cosTheta_t = sqrt(1.0 - eta2 * st2); - vec2 r = vec2((n2*cosTheta - n1*cosTheta_t) / (n2*cosTheta + n1*cosTheta_t), - (n1*cosTheta - n2*cosTheta_t) / (n1*cosTheta + n2*cosTheta_t)); - F = mx_square(r); - phi.x = (r.x < 0.0) ? M_PI : 0.0; - phi.y = (r.y < 0.0) ? M_PI : 0.0; + vec3 n = eta2 / eta1; + vec3 k = kappa2 / eta1; + mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs); } -// Fresnel for dielectric/conductor interface and polarized light. -// TODO: Optimize this functions and support wavelength dependent complex refraction index. -void mx_fresnel_conductor_polarized(float cosTheta, float n1, float n2, float k, out vec2 F, out vec2 phi) +vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) { - if (k == 0.0) - { - // Use dielectric formula to avoid numerical issues - mx_fresnel_dielectric_polarized(cosTheta, n1, n2, F, phi); - return; - } - - float A = mx_square(n2) * (1.0 - mx_square(k)) - mx_square(n1) * (1.0 - mx_square(cosTheta)); - float B = sqrt(mx_square(A) + mx_square(2.0 * mx_square(n2) * k)); - float U = sqrt((A+B) / 2.0); - float V = sqrt((B-A) / 2.0); - - F.y = (mx_square(n1*cosTheta - U) + mx_square(V)) / (mx_square(n1*cosTheta + U) + mx_square(V)); - phi.y = atan(2.0*n1 * V*cosTheta, mx_square(U) + mx_square(V) - mx_square(n1*cosTheta)) + M_PI; - - F.x = (mx_square(mx_square(n2) * (1.0 - mx_square(k)) * cosTheta - n1*U) + mx_square(2.0 * mx_square(n2) * k * cosTheta - n1*V)) / - (mx_square(mx_square(n2) * (1.0 - mx_square(k)) * cosTheta + n1*U) + mx_square(2.0 * mx_square(n2) * k * cosTheta + n1*V)); - phi.x = atan(2.0 * n1 * mx_square(n2) * cosTheta * (2.0*k*U - (1.0 - mx_square(k)) * V), mx_square(mx_square(n2) * (1.0 + mx_square(k)) * cosTheta) - mx_square(n1) * (mx_square(U) + mx_square(V))); + vec3 Rp, Rs; + mx_fresnel_conductor_polarized(vec3(cosTheta), n, k, Rp, Rs); + return 0.5 * (Rp + Rs); } -// Depolarization functions for natural light -float mx_depolarize(vec2 v) -{ - return 0.5 * (v.x + v.y); -} -vec3 mx_depolarize(vec3 s, vec3 p) +// Phase shift due to a conducting material +void mx_fresnel_conductor_phase_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) { - return 0.5 * (s + p); + vec3 k2 = kappa2 / eta2; + vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; + vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; + vec3 B = sqrt(A*A + mx_square(2*eta2*eta2*k2)); + vec3 U = sqrt((A+B)/2.0); + vec3 V = max(vec3(0.0), sqrt((B-A)/2.0)); + + phiS = atan(2*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); + phiP = atan(2*eta1*eta2*eta2*cosTheta * (2*k2*U - (vec3(1.0)-k2*k2) * V), + mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); } // Evaluation XYZ sensitivity curves in Fourier space -vec3 mx_eval_sensitivity(float opd, float shift) +vec3 mx_eval_sensitivity(vec3 opd, vec3 shift) { // Use Gaussian fits, given by 3 parameters: val, pos and var - float phase = 2.0*M_PI * opd; + vec3 phase = 2.0*M_PI * opd; vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); vec3 xyz = val * sqrt(2.0*M_PI * var) * cos(pos * phase + shift) * exp(- var * phase*phase); - xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift) * exp(- 4.5282e+09 * phase*phase); + xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase[0] + shift[0]) * exp(- 4.5282e+09 * phase[0]*phase[0]); return xyz / 1.0685e-7; } // A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence // https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html -vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickness, float tf_ior) +vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickness, float tf_ior, + vec3 f0, vec3 f90, float exponent, bool use_schlick) { // Convert nm -> m float d = tf_thickness * 1.0e-9; // Assume vacuum on the outside - float eta1 = 1.0; - float eta2 = max(tf_ior, eta1); + vec3 eta1 = vec3(1.0); + vec3 eta2 = max(vec3(tf_ior), eta1); + vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(f0) : ior; + vec3 kappa3 = use_schlick ? vec3(0.0) : extinction; + + // Compute the Spectral versions of the Fresnel reflectance and + // transmitance for each interface. + vec3 R12p, T121p, R23p, R12s, T121s, R23s; + + // Reflected and transmitted parts in the thin film + // Note: This part needs to compute the new ray direction cosTheta2 + // as cosTheta2 is wavelength dependent. + vec3 scale = eta1 / eta2; //(cosTheta > 0) ? eta1[i]/eta2[i] : eta2[i]/eta1[i]; + vec3 cosThetaTSqr = 1 - (1-cosTheta*cosTheta) * scale*scale; + + vec3 cosTheta2 = sqrt(cosThetaTSqr); + mx_fresnel_conductor_polarized(vec3(cosTheta), eta1, eta2, vec3(0.0), R12p, R12s); + + // Reflected part by the base + if (use_schlick) + { + vec3 f = mx_fresnel_schlick(cosTheta, f0, f90, exponent); + R23p = 0.5 * f; + R23s = 0.5 * f; + } + else + { + mx_fresnel_conductor_polarized(cosTheta2, eta2, eta3, kappa3, R23p, R23s); + } + + // Check for total internal reflection + for (int i = 0; i < 3; ++i) + { + if (cosThetaTSqr[i] <= 0.0f) + { + R12s[i] = 1.0; + R12p[i] = 1.0; + } + } + + // Compute the transmission coefficients + T121p = 1.0 - R12p; + T121s = 1.0 - R12s; // Optical path difference - float cosTheta2 = sqrt(1.0 - mx_square(eta1/eta2) * (1.0 - mx_square(cosTheta))); - float D = 2.0 * eta2 * d * cosTheta2; + vec3 D = 2.0 * eta2 * d * cosTheta2; + vec3 Dphi = 2.0 * M_PI * D / vec3(580.0, 550.0, 450.0); - // First interface - vec2 R12, phi12; - mx_fresnel_dielectric_polarized(cosTheta, eta1, eta2, R12, phi12); - vec2 T121 = vec2(1.0) - R12; - vec2 phi21 = vec2(M_PI) - phi12; + vec3 phi21p, phi21s, phi23p, phi23s, r123s, r123p; + + // Evaluate the phase shift + mx_fresnel_conductor_phase_polarized(vec3(cosTheta), vec3(1.0), eta2, vec3(0.0), phi21p, phi21s); + if (use_schlick) + { + phi23p = vec3( + (eta3[0] < eta2[0]) ? M_PI : 0.0, + (eta3[1] < eta2[1]) ? M_PI : 0.0, + (eta3[2] < eta2[2]) ? M_PI : 0.0); + phi23s = phi23p; + } + else + { + mx_fresnel_conductor_phase_polarized(cosTheta2, eta2, eta3, kappa3, phi23p, phi23s); + } - // Second interface - vec2 R23, phi23; - mx_fresnel_conductor_polarized(cosTheta2, eta2, ior.x, extinction.x, R23, phi23); + phi21p = vec3(M_PI) - phi21p; + phi21s = vec3(M_PI) - phi21s; - // Phase shift - vec2 phi2 = phi21 + phi23; + r123p = max(vec3(0.0), sqrt(R12p*R23p)); + r123s = max(vec3(0.0), sqrt(R12s*R23s)); - // Compound terms - vec3 R = vec3(0.0); - vec2 R123 = R12*R23; - vec2 r123 = sqrt(R123); - vec2 Rs = mx_square(T121)*R23 / (1.0-R123); + // Evaluate iridescence term + vec3 I = vec3(0.0); + vec3 C0, Cm, Sm; + + // Iridescence term using spectral antialiasing for Parallel polarization + + vec3 S0 = vec3(1.0); // Reflectance term for m=0 (DC term amplitude) - vec2 C0 = R12 + Rs; - vec3 S0 = mx_eval_sensitivity(0.0, 0.0); - R += mx_depolarize(C0) * S0; + vec3 Rs = (T121p*T121p*R23p) / (vec3(1.0) - R12p*R23p); + C0 = R12p + Rs; + I += C0 * S0; // Reflectance term for m>0 (pairs of diracs) - vec2 Cm = Rs - T121; - for (int m=1; m<=3; ++m) + Cm = Rs - T121p; + for (int m=1; m<=2; ++m) { - Cm *= r123; - vec3 SmS = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*phi2.x); - vec3 SmP = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*phi2.y); - R += mx_depolarize(Cm.x*SmS, Cm.y*SmP); + Cm *= r123p; + Sm = 2.0 * mx_eval_sensitivity(m*D, m*(phi23p+phi21p)); + I += Cm*Sm; + } + + // Iridescence term using spectral antialiasing for Perpendicular polarization + + // Reflectance term for m=0 (DC term amplitude) + vec3 Rp = (T121s*T121s*R23s) / (vec3(1.0) - R12s*R23s); + C0 = R12s + Rp; + I += C0 * S0; + + // Reflectance term for m>0 (pairs of diracs) + Cm = Rp - T121s ; + for (int m=1; m<=2; ++m) + { + Cm *= r123s; + Sm = 2.0 * mx_eval_sensitivity(m*D, m*(phi23s+phi21s)); + I += Cm*Sm; } // Convert back to RGB reflectance - R = clamp(XYZ_TO_RGB * R, vec3(0.0), vec3(1.0)); + I = clamp(XYZ_TO_RGB * I, vec3(0.0), vec3(1.0)); - return R; + return I; } FresnelData mx_init_fresnel_data(int model) @@ -423,12 +468,14 @@ FresnelData mx_init_fresnel_schlick(vec3 F0) return fd; } -FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F90, float exponent) +FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F90, float exponent, float tf_thickness, float tf_ior) { FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); fd.F0 = F0; fd.F90 = F90; fd.exponent = exponent; + fd.tf_thickness = tf_thickness; + fd.tf_ior = tf_ior; return fd; } @@ -461,13 +508,15 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) { return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction); } - else if (fd.model == FRESNEL_MODEL_SCHLICK) + else if (fd.model == FRESNEL_MODEL_SCHLICK && fd.tf_thickness == 0.0) { return mx_fresnel_schlick(cosTheta, fd.F0, fd.F90, fd.exponent); } else { - return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior); + return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior, + fd.F0, fd.F90, fd.exponent, + fd.model == FRESNEL_MODEL_SCHLICK); } } diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index dc05ad0391..a82c572523 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -20,7 +20,7 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus float avgAlpha = mx_average_alpha(safeAlpha); vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - FresnelData fd = mx_init_fresnel_schlick(color0, color90, exponent); + FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); @@ -44,7 +44,7 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd = mx_init_fresnel_schlick(color0, color90, exponent); + FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); @@ -73,7 +73,7 @@ void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd = mx_init_fresnel_schlick(color0, color90, exponent); + FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx index 9cc20abc53..8575c3aa13 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx @@ -156,4 +156,24 @@ + + + + + + + + + + + + + + + + + + + + From 02466e93a1c09a5314d36c013e27e3488b9486ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Sat, 13 Aug 2022 20:37:29 +0200 Subject: [PATCH 02/11] Add iridescence to glTF PBR. --- libraries/bxdf/gltf_pbr.mtlx | 41 ++++++++++++++++++- .../Examples/GltfPbr/gltf_pbr_default.mtlx | 3 ++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/libraries/bxdf/gltf_pbr.mtlx b/libraries/bxdf/gltf_pbr.mtlx index 1012fe143f..fc7a3739d9 100644 --- a/libraries/bxdf/gltf_pbr.mtlx +++ b/libraries/bxdf/gltf_pbr.mtlx @@ -13,6 +13,9 @@ + + + @@ -147,11 +150,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx b/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx index 1d65eb782a..501d454831 100644 --- a/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx +++ b/resources/Materials/Examples/GltfPbr/gltf_pbr_default.mtlx @@ -13,6 +13,9 @@ + + + From cc5c19de2494c0e3b6999de4e1ba34febaeb4278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Fri, 19 Aug 2022 10:40:41 +0200 Subject: [PATCH 03/11] Workaround GLSL codegen issues in glTF PBR. --- libraries/bxdf/gltf_pbr.mtlx | 62 ++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/libraries/bxdf/gltf_pbr.mtlx b/libraries/bxdf/gltf_pbr.mtlx index fc7a3739d9..a97f26d73e 100644 --- a/libraries/bxdf/gltf_pbr.mtlx +++ b/libraries/bxdf/gltf_pbr.mtlx @@ -141,25 +141,50 @@ - + - - - + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - + - - + + @@ -168,6 +193,25 @@ + + + + + + + + + + + + + + + + + + @@ -175,7 +219,7 @@ - + From 879af1a2fc511884ac6a3e12e1ed568683e0294a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Tue, 30 Aug 2022 21:31:37 +0200 Subject: [PATCH 04/11] Fix implicit casts from int to float in shader code. --- .../pbrlib/genglsl/lib/mx_microfacet_specular.glsl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 0db2c11aef..7038bc6b81 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -293,12 +293,12 @@ void mx_fresnel_conductor_phase_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, v vec3 k2 = kappa2 / eta2; vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; - vec3 B = sqrt(A*A + mx_square(2*eta2*eta2*k2)); + vec3 B = sqrt(A*A + mx_square(2.0*eta2*eta2*k2)); vec3 U = sqrt((A+B)/2.0); vec3 V = max(vec3(0.0), sqrt((B-A)/2.0)); - phiS = atan(2*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); - phiP = atan(2*eta1*eta2*eta2*cosTheta * (2*k2*U - (vec3(1.0)-k2*k2) * V), + phiS = atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta)); + phiP = atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V), mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V)); } @@ -337,7 +337,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne // Note: This part needs to compute the new ray direction cosTheta2 // as cosTheta2 is wavelength dependent. vec3 scale = eta1 / eta2; //(cosTheta > 0) ? eta1[i]/eta2[i] : eta2[i]/eta1[i]; - vec3 cosThetaTSqr = 1 - (1-cosTheta*cosTheta) * scale*scale; + vec3 cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; vec3 cosTheta2 = sqrt(cosThetaTSqr); mx_fresnel_conductor_polarized(vec3(cosTheta), eta1, eta2, vec3(0.0), R12p, R12s); @@ -413,7 +413,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne for (int m=1; m<=2; ++m) { Cm *= r123p; - Sm = 2.0 * mx_eval_sensitivity(m*D, m*(phi23p+phi21p)); + Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+phi21p)); I += Cm*Sm; } @@ -429,7 +429,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne for (int m=1; m<=2; ++m) { Cm *= r123s; - Sm = 2.0 * mx_eval_sensitivity(m*D, m*(phi23s+phi21s)); + Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+phi21s)); I += Cm*Sm; } From 6941f57ca59d2c160a177f6dbf4913f19f179764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Wed, 31 Aug 2022 22:33:59 +0200 Subject: [PATCH 05/11] Add separate init function for thin film Schlick Fresnel. --- .../genglsl/lib/mx_microfacet_specular.glsl | 16 ++++++++-- .../genglsl/mx_generalized_schlick_bsdf.glsl | 30 +++++++++++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 7038bc6b81..eae3f36c17 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -5,6 +5,7 @@ const int FRESNEL_MODEL_DIELECTRIC = 0; const int FRESNEL_MODEL_CONDUCTOR = 1; const int FRESNEL_MODEL_SCHLICK = 2; const int FRESNEL_MODEL_AIRY = 3; +const int FRESNEL_MODEL_SCHLICK_AIRY = 3; // XYZ to CIE 1931 RGB color space (using neutral E illuminant) const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); @@ -468,12 +469,21 @@ FresnelData mx_init_fresnel_schlick(vec3 F0) return fd; } -FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F90, float exponent, float tf_thickness, float tf_ior) +FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F90, float exponent) { FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK); fd.F0 = F0; fd.F90 = F90; fd.exponent = exponent; + return fd; +} + +FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F90, float exponent, float tf_thickness, float tf_ior) +{ + FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK_AIRY); + fd.F0 = F0; + fd.F90 = F90; + fd.exponent = exponent; fd.tf_thickness = tf_thickness; fd.tf_ior = tf_ior; return fd; @@ -508,7 +518,7 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) { return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction); } - else if (fd.model == FRESNEL_MODEL_SCHLICK && fd.tf_thickness == 0.0) + else if (fd.model == FRESNEL_MODEL_SCHLICK) { return mx_fresnel_schlick(cosTheta, fd.F0, fd.F90, fd.exponent); } @@ -516,7 +526,7 @@ vec3 mx_compute_fresnel(float cosTheta, FresnelData fd) { return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior, fd.F0, fd.F90, fd.exponent, - fd.model == FRESNEL_MODEL_SCHLICK); + fd.model == FRESNEL_MODEL_SCHLICK_AIRY); } } diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl index a82c572523..11d1568fd6 100644 --- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl +++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl @@ -20,7 +20,15 @@ void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlus float avgAlpha = mx_average_alpha(safeAlpha); vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N)); - FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + FresnelData fd; + if (bsdf.thickness > 0.0) + { + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + } + else + { + fd = mx_init_fresnel_schlick(color0, color90, exponent); + } vec3 F = mx_compute_fresnel(VdotH, fd); float D = mx_ggx_NDF(Ht, safeAlpha); float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha); @@ -44,7 +52,15 @@ void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + FresnelData fd; + if (bsdf.thickness > 0.0) + { + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + } + else + { + fd = mx_init_fresnel_schlick(color0, color90, exponent); + } vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); @@ -73,7 +89,15 @@ void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec N = mx_forward_facing_normal(N, V); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); - FresnelData fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + FresnelData fd; + if (bsdf.thickness > 0.0) + { + fd = mx_init_fresnel_schlick_airy(color0, color90, exponent, bsdf.thickness, bsdf.ior); + } + else + { + fd = mx_init_fresnel_schlick(color0, color90, exponent); + } vec3 F = mx_compute_fresnel(NdotV, fd); vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0); From 81882d1e542726efc54af226085ef7111da98c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Wed, 14 Sep 2022 19:47:09 +0200 Subject: [PATCH 06/11] Fix dielectric Fresnel. --- libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index eae3f36c17..18563facb6 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -5,7 +5,7 @@ const int FRESNEL_MODEL_DIELECTRIC = 0; const int FRESNEL_MODEL_CONDUCTOR = 1; const int FRESNEL_MODEL_SCHLICK = 2; const int FRESNEL_MODEL_AIRY = 3; -const int FRESNEL_MODEL_SCHLICK_AIRY = 3; +const int FRESNEL_MODEL_SCHLICK_AIRY = 4; // XYZ to CIE 1931 RGB color space (using neutral E illuminant) const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968); From 684e916ea903aac8295277e679ef2a2278283de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Wed, 14 Sep 2022 20:40:30 +0200 Subject: [PATCH 07/11] Add missing averaging of parallel and perpendicular polarized contribution. --- libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 18563facb6..1fd3042a43 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -434,6 +434,9 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne I += Cm*Sm; } + // Average parallel and perpendicular polarization + I *= 0.5; + // Convert back to RGB reflectance I = clamp(XYZ_TO_RGB * I, vec3(0.0), vec3(1.0)); From 468abcb2a10bdcd87fe1f9dbd4eb9e5e1ade24b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Sun, 18 Sep 2022 14:42:37 +0200 Subject: [PATCH 08/11] Optimize performance. --- .../genglsl/lib/mx_microfacet_specular.glsl | 124 ++++++++++++------ 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index 1fd3042a43..a4bfd94486 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -253,28 +253,57 @@ float mx_fresnel_dielectric(float cosTheta, float ior) return 0.5 * x * x * (1.0 + y * y); } -// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/ -void mx_fresnel_conductor_polarized(vec3 cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) +void mx_fresnel_dielectric_polarized(float cosTheta, float n, out float Rp, out float Rs) +{ + if (cosTheta < 0.0) { + Rp = 1.0; + Rs = 1.0; + return; + } + + float cosTheta2 = cosTheta * cosTheta; + float sinTheta2 = 1.0 - cosTheta2; + float n2 = n * n; + + float t0 = n2 - sinTheta2; + float a2plusb2 = sqrt(t0 * t0); + float t1 = a2plusb2 + cosTheta2; + float a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); + float t2 = 2.0 * a * cosTheta; + Rs = (t1 - t2) / (t1 + t2); + + float t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2; + float t4 = t2 * sinTheta2; + Rp = Rs * (t3 - t4) / (t3 + t4); +} + +void mx_fresnel_dielectric_polarized(float cosTheta, float eta1, float eta2, out float Rp, out float Rs) { - cosTheta = clamp(cosTheta, vec3(0.0), vec3(1.0)); - vec3 cosTheta2 = cosTheta * cosTheta; - vec3 sinTheta2 = 1.0 - cosTheta2; + float n = eta2 / eta1; + mx_fresnel_dielectric_polarized(cosTheta, n, Rp, Rs); +} + +void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs) +{ + cosTheta = clamp(cosTheta, 0.0, 1.0); + float cosTheta2 = cosTheta * cosTheta; + float sinTheta2 = 1.0 - cosTheta2; vec3 n2 = n * n; vec3 k2 = k * k; - vec3 t0 = n2 - k2 - sinTheta2; + vec3 t0 = n2 - k2 - vec3(sinTheta2); vec3 a2plusb2 = sqrt(t0 * t0 + 4.0 * n2 * k2); - vec3 t1 = a2plusb2 + cosTheta2; + vec3 t1 = a2plusb2 + vec3(cosTheta2); vec3 a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0)); vec3 t2 = 2.0 * a * cosTheta; Rs = (t1 - t2) / (t1 + t2); - vec3 t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2; + vec3 t3 = cosTheta2 * a2plusb2 + vec3(sinTheta2 * sinTheta2); vec3 t4 = t2 * sinTheta2; Rp = Rs * (t3 - t4) / (t3 + t4); } -void mx_fresnel_conductor_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) +void mx_fresnel_conductor_polarized(float cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) { vec3 n = eta2 / eta1; vec3 k = kappa2 / eta1; @@ -284,12 +313,25 @@ void mx_fresnel_conductor_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, vec3 ka vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k) { vec3 Rp, Rs; - mx_fresnel_conductor_polarized(vec3(cosTheta), n, k, Rp, Rs); + mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs); return 0.5 * (Rp + Rs); } +// Phase shift due to a dielectric material +void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta2, out float phiP, out float phiS) +{ + float cosB = cos(atan(eta2 / eta1)); // Brewster's angle + if (eta2 > eta1) { + phiP = cosTheta < cosB ? M_PI : 0.0f; + phiS = 0; + } else { + phiP = cosTheta < cosB ? 0.0f : M_PI; + phiS = M_PI; + } +} + // Phase shift due to a conducting material -void mx_fresnel_conductor_phase_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) +void mx_fresnel_conductor_phase_polarized(float cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) { vec3 k2 = kappa2 / eta2; vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; @@ -304,15 +346,15 @@ void mx_fresnel_conductor_phase_polarized(vec3 cosTheta, vec3 eta1, vec3 eta2, v } // Evaluation XYZ sensitivity curves in Fourier space -vec3 mx_eval_sensitivity(vec3 opd, vec3 shift) +vec3 mx_eval_sensitivity(float opd, vec3 shift) { // Use Gaussian fits, given by 3 parameters: val, pos and var - vec3 phase = 2.0*M_PI * opd; + float phase = 2.0*M_PI * opd; vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13); vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06); vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09); vec3 xyz = val * sqrt(2.0*M_PI * var) * cos(pos * phase + shift) * exp(- var * phase*phase); - xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase[0] + shift[0]) * exp(- 4.5282e+09 * phase[0]*phase[0]); + xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase); return xyz / 1.0685e-7; } @@ -325,44 +367,39 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne float d = tf_thickness * 1.0e-9; // Assume vacuum on the outside - vec3 eta1 = vec3(1.0); - vec3 eta2 = max(vec3(tf_ior), eta1); + float eta1 = 1.0; + float eta2 = max(tf_ior, eta1); vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(f0) : ior; vec3 kappa3 = use_schlick ? vec3(0.0) : extinction; // Compute the Spectral versions of the Fresnel reflectance and // transmitance for each interface. - vec3 R12p, T121p, R23p, R12s, T121s, R23s; + float R12p, T121p, R12s, T121s; + vec3 R23p, R23s; // Reflected and transmitted parts in the thin film - // Note: This part needs to compute the new ray direction cosTheta2 - // as cosTheta2 is wavelength dependent. - vec3 scale = eta1 / eta2; //(cosTheta > 0) ? eta1[i]/eta2[i] : eta2[i]/eta1[i]; - vec3 cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; - - vec3 cosTheta2 = sqrt(cosThetaTSqr); - mx_fresnel_conductor_polarized(vec3(cosTheta), eta1, eta2, vec3(0.0), R12p, R12s); + mx_fresnel_dielectric_polarized(cosTheta, eta1, eta2, R12p, R12s); // Reflected part by the base + float scale = eta1 / eta2; + float cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale; + float cosTheta2 = sqrt(cosThetaTSqr); if (use_schlick) { - vec3 f = mx_fresnel_schlick(cosTheta, f0, f90, exponent); + vec3 f = mx_fresnel_schlick(cosTheta2, f0, f90, exponent); R23p = 0.5 * f; R23s = 0.5 * f; } else { - mx_fresnel_conductor_polarized(cosTheta2, eta2, eta3, kappa3, R23p, R23s); + mx_fresnel_conductor_polarized(cosTheta2, vec3(eta2), eta3, kappa3, R23p, R23s); } // Check for total internal reflection - for (int i = 0; i < 3; ++i) + if (cosThetaTSqr <= 0.0f) { - if (cosThetaTSqr[i] <= 0.0f) - { - R12s[i] = 1.0; - R12p[i] = 1.0; - } + R12s = 1.0; + R12p = 1.0; } // Compute the transmission coefficients @@ -370,28 +407,29 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne T121s = 1.0 - R12s; // Optical path difference - vec3 D = 2.0 * eta2 * d * cosTheta2; + float D = 2.0 * eta2 * d * cosTheta2; vec3 Dphi = 2.0 * M_PI * D / vec3(580.0, 550.0, 450.0); - vec3 phi21p, phi21s, phi23p, phi23s, r123s, r123p; + float phi21p, phi21s; + vec3 phi23p, phi23s, r123s, r123p; // Evaluate the phase shift - mx_fresnel_conductor_phase_polarized(vec3(cosTheta), vec3(1.0), eta2, vec3(0.0), phi21p, phi21s); + mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2, phi21p, phi21s); if (use_schlick) { phi23p = vec3( - (eta3[0] < eta2[0]) ? M_PI : 0.0, - (eta3[1] < eta2[1]) ? M_PI : 0.0, - (eta3[2] < eta2[2]) ? M_PI : 0.0); + (eta3[0] < eta2) ? M_PI : 0.0, + (eta3[1] < eta2) ? M_PI : 0.0, + (eta3[2] < eta2) ? M_PI : 0.0); phi23s = phi23p; } else { - mx_fresnel_conductor_phase_polarized(cosTheta2, eta2, eta3, kappa3, phi23p, phi23s); + mx_fresnel_conductor_phase_polarized(cosTheta2, vec3(eta2), eta3, kappa3, phi23p, phi23s); } - phi21p = vec3(M_PI) - phi21p; - phi21s = vec3(M_PI) - phi21s; + phi21p = M_PI - phi21p; + phi21s = M_PI - phi21s; r123p = max(vec3(0.0), sqrt(R12p*R23p)); r123s = max(vec3(0.0), sqrt(R12s*R23s)); @@ -414,7 +452,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne for (int m=1; m<=2; ++m) { Cm *= r123p; - Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+phi21p)); + Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+vec3(phi21p))); I += Cm*Sm; } @@ -430,7 +468,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne for (int m=1; m<=2; ++m) { Cm *= r123s; - Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+phi21s)); + Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+vec3(phi21s))); I += Cm*Sm; } From a1a3fd561e1ff6a09ce710f6b89a9d1a8fd68f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Sun, 18 Sep 2022 14:53:19 +0200 Subject: [PATCH 09/11] Add test with conductor BSDF in base layer. --- .../TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx index 8575c3aa13..a6bc23bfa2 100644 --- a/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx +++ b/resources/Materials/TestSuite/pbrlib/bsdf/thin_film_bsdf.mtlx @@ -157,6 +157,26 @@ + + + + + + + + + + + + + + + + + + + + From 81e8e3bd8ed80854048f1da0a57f174cdf6b65b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Sun, 18 Sep 2022 15:27:52 +0200 Subject: [PATCH 10/11] Optimize performance even more. --- .../genglsl/lib/mx_microfacet_specular.glsl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index a4bfd94486..e2f27e0135 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -303,7 +303,7 @@ void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, Rp = Rs * (t3 - t4) / (t3 + t4); } -void mx_fresnel_conductor_polarized(float cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) +void mx_fresnel_conductor_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs) { vec3 n = eta2 / eta1; vec3 k = kappa2 / eta1; @@ -331,8 +331,15 @@ void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta } // Phase shift due to a conducting material -void mx_fresnel_conductor_phase_polarized(float cosTheta, vec3 eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) +void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS) { + if (kappa2 == vec3(0, 0, 0) && eta2.x == eta2.y && eta2.y == eta2.z) { + // Use dielectric formula to increase performance + mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiP.x, phiS.x); + phiP = phiP.xxx; + phiS = phiS.xxx; + return; + } vec3 k2 = kappa2 / eta2; vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta; vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr; @@ -392,7 +399,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne } else { - mx_fresnel_conductor_polarized(cosTheta2, vec3(eta2), eta3, kappa3, R23p, R23s); + mx_fresnel_conductor_polarized(cosTheta2, eta2, eta3, kappa3, R23p, R23s); } // Check for total internal reflection @@ -425,7 +432,7 @@ vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickne } else { - mx_fresnel_conductor_phase_polarized(cosTheta2, vec3(eta2), eta3, kappa3, phi23p, phi23s); + mx_fresnel_conductor_phase_polarized(cosTheta2, eta2, eta3, kappa3, phi23p, phi23s); } phi21p = M_PI - phi21p; From 2594557a7c6325f9e26fd64a6217f963232f8a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4u=C3=9Fler?= Date: Sun, 18 Sep 2022 21:22:06 +0200 Subject: [PATCH 11/11] Fix literal type. --- libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index e2f27e0135..f347317fa2 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -323,7 +323,7 @@ void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta float cosB = cos(atan(eta2 / eta1)); // Brewster's angle if (eta2 > eta1) { phiP = cosTheta < cosB ? M_PI : 0.0f; - phiS = 0; + phiS = 0.0f; } else { phiP = cosTheta < cosB ? 0.0f : M_PI; phiS = M_PI;