diff --git a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl index c7731508f8..92bb567947 100644 --- a/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_environment_fis.glsl @@ -5,10 +5,13 @@ vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distributio // Generate tangent frame. X = normalize(X - dot(X, N) * N); vec3 Y = cross(N, X); - mat3 tangentToWorld = mat3(X, Y, N); + vec3 bentNormal = mx_bent_normal_anisotropy(N, V, X, Y, alpha); + X = normalize(X - dot(X, bentNormal) * bentNormal); + Y = cross(bentNormal, X); + mat3 tangentToWorld = mat3(X, Y, bentNormal); // Transform the view vector to tangent space. - V = vec3(dot(V, X), dot(V, Y), dot(V, N)); + V = vec3(dot(V, X), dot(V, Y), dot(V, bentNormal)); // Compute derived properties. float NdotV = clamp(V.z, M_FLOAT_EPS, 1.0); diff --git a/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl b/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl index bcf368c0fc..ba53e85efd 100644 --- a/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_environment_prefilter.glsl @@ -10,7 +10,10 @@ float mx_latlong_alpha_to_lod(float alpha) vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd) { N = mx_forward_facing_normal(N, V); - vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N); + X = normalize(X - dot(X, N) * N); + vec3 Y = cross(N, X); + vec3 bentNormal = mx_bent_normal_anisotropy(N, V, X, Y, alpha); + vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, bentNormal); float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0); diff --git a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl index e8bb637657..e861a19407 100644 --- a/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl @@ -192,6 +192,31 @@ float mx_average_alpha(vec2 alpha) return sqrt(alpha.x * alpha.y); } +// Approximate anisotropic IBL with a bent normal from alpha.x / alpha.y. +// https://google.github.io/filament/Filament.md.html Section Anisotropy +vec3 mx_bent_normal_anisotropy(vec3 N, vec3 V, vec3 X, vec3 Y, vec2 alpha) +{ + float maxAlpha = max(max(alpha.x, alpha.y), M_FLOAT_EPS); + float minOverMax = min(alpha.x, alpha.y) / maxAlpha; + float anisotropy = 1.0 - clamp(minOverMax, 0.0, 1.0); + float anisotropySign = (alpha.x >= alpha.y) ? 1.0 : -1.0; + float signedAnisotropy = anisotropy * anisotropySign; + + vec3 anisotropicDirection = (signedAnisotropy >= 0.0) ? Y : X; + vec3 anisotropicTangent = cross(anisotropicDirection, V); + float tangentLenSq = dot(anisotropicTangent, anisotropicTangent); + vec3 anisotropicNormal = (tangentLenSq > M_FLOAT_EPS) ? + normalize(cross(anisotropicTangent, anisotropicDirection)) : N; + + float roughness = clamp(sqrt(mx_average_alpha(alpha)), 0.0, 1.0); + float bend = abs(signedAnisotropy) * (1.0 - roughness); + float normalWeight = 1.0 - bend; + normalWeight *= normalWeight; + normalWeight *= normalWeight; + + return normalize(mix(anisotropicNormal, N, normalWeight)); +} + // Convert a real-valued index of refraction to normal-incidence reflectivity. float mx_ior_to_f0(float ior) {