Revision control

++ // Copyright (C) 2026 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #ifndef ANISOTROPY_GLSLLIB
++ #define ANISOTROPY_GLSLLIB 1
++
++ #include "bsdf.glsllib"
++ #include "principledMaterialFresnel.glsllib" // qt_schlick
++
++ #ifndef M_PI
++ #define M_PI 3.14159265359
++ #endif
++
++ // KHR_materials_anisotropy: replaces the GGX distribution and visibility terms
++
++ // Fallback tangent for meshes without one (Duff et al. 2017)
++ vec3 qt_orthonormalTangent(in vec3 normal)
++ {
++ float s = normal.z >= 0.0 ? 1.0 : -1.0;
++ float a = -1.0 / (s + normal.z);
++ float b = normal.x * normal.y * a;
++ return vec3(1.0 + s * normal.x * normal.x * a, s * b, -s * normal.x);
++ }
++
++ float qt_D_GGX_anisotropic(in float NdotH, in float TdotH, in float BdotH, in float at, in float ab)
++ {
++ float a2 = at * ab;
++ vec3 f = vec3(ab * TdotH, at * BdotH, a2 * NdotH);
++ float w2 = a2 / dot(f, f);
++ return a2 * w2 * w2 / M_PI;
++ }
++
++ // Includes the 1/(4 NdotL NdotV) term, like qt_V_GGX
++ float qt_V_GGX_anisotropic(in float NdotL, in float NdotV, in float BdotV, in float TdotV,
++ in float TdotL, in float BdotL, in float at, in float ab)
++ {
++ float GGXV = NdotL * length(vec3(at * TdotV, ab * BdotV, NdotV));
++ float GGXL = NdotV * length(vec3(at * TdotL, ab * BdotL, NdotL));
++ return clamp(0.5 / (GGXV + GGXL), 0.0, 1.0);
++ }
++
++ vec4 qt_specularAnisotropicGGXBSDF(in vec3 normal, in vec3 tangent, in vec3 bitangent,
++ in vec3 L, in vec3 V, in vec3 lightSpecular,
++ in vec3 F0, in vec3 F90, in float at, in float ab)
++ {
++ float cNdotL = max(0.0, dot(normal, L));
++ float cNdotV = max(0.0, dot(normal, V));
++ vec3 H = normalize(V + L);
++ float cLdotH = max(0.0, dot(L, H));
++ float cNdotH = max(0.001, dot(normal, H)); // arguments for the distribution must not be 0
++
++ float GGX_D = qt_D_GGX_anisotropic(cNdotH, dot(tangent, H), dot(bitangent, H), at, ab);
++ float GGX_V = qt_V_GGX_anisotropic(cNdotL, cNdotV, dot(bitangent, V), dot(tangent, V),
++ dot(tangent, L), dot(bitangent, L), at, ab);
++
++ float cLdotH5 = qt_schlick(cLdotH);
++ vec3 F = mix(vec3(cLdotH5), F90, F0);
++
++ return vec4(cNdotL * GGX_D * F * GGX_V * lightSpecular, 1.0);
++ }
++
++ // Bent normal for image based lighting, as recommended by the extension
++ vec3 qt_anisotropicBentNormal(in vec3 normal, in vec3 viewDir, in vec3 bitangent,
++ in float strength, in float roughness)
++ {
++ vec3 bent = cross(bitangent, viewDir);
++ bent = normalize(cross(bent, bitangent));
++ // pow(1 - strength * (1 - roughness), 4)
++ float a = 1.0 - strength * (1.0 - roughness);
++ a = a * a;
++ a = a * a;
++ return normalize(mix(bent, normal, a));
++ }
++
++ #endif // ANISOTROPY_GLSLLIB