Revision control

++ // Copyright (C) 2026 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #ifndef SHEEN_GLSLIB
++ #define SHEEN_GLSLIB 1
++
++ #ifndef M_PI
++ #define M_PI 3.14159265359
++ #endif
++
++ // Charlie sheen distribution (Estevez and Kulla 2017)
++ float qt_D_Charlie(in float sheenRoughness, in float NdotH)
++ {
++ float alpha = clamp(sheenRoughness * sheenRoughness, 0.000001, 1.0);
++ float invAlpha = 1.0 / alpha;
++ float cos2h = NdotH * NdotH;
++ float sin2h = max(1.0 - cos2h, 0.0078125); // 2^-7, so sin2h^2 does not underflow in fp16
++ return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * M_PI);
++ }
++
++ // Neubelt and Pettineo 2013 visibility, as permitted by KHR_materials_sheen
++ float qt_V_Neubelt(in float NdotL, in float NdotV)
++ {
++ return clamp(1.0 / (4.0 * (NdotL + NdotV - NdotL * NdotV)), 0.0, 1.0);
++ }
++
++ vec3 qt_sheenBSDF(in vec3 normal, in vec3 L, in vec3 V, in vec3 lightColor,
++ in vec3 sheenColor, in float sheenRoughness)
++ {
++ vec3 H = normalize(L + V);
++ float NdotL = clamp(dot(normal, L), 0.0, 1.0);
++ float NdotV = clamp(dot(normal, V), 0.0, 1.0);
++ float NdotH = clamp(dot(normal, H), 0.0, 1.0);
++
++ float D = qt_D_Charlie(sheenRoughness, NdotH);
++ float Vis = qt_V_Neubelt(NdotL, NdotV);
++ return sheenColor * D * Vis * NdotL * lightColor;
++ }
++
++ // Directional albedo of qt_D_Charlie with qt_V_Neubelt, fitted to the
++ // numerically integrated values with a maximum error of 0.03
++ float qt_E_sheen(in float NdotV, in float sheenRoughness)
++ {
++ float r = clamp(sheenRoughness, 0.0, 1.0);
++ float t = 1.0 / (r + 0.05);
++ float t2 = t * t;
++
++ float a = -1.3278 + 0.5106 * r - 0.2782 * t - 0.1400 * t2;
++ float b = 1.2805 - 0.4833 * r - 0.8451 * t - 0.0904 * t2;
++ float c = -0.8153 - 0.1470 * r + 0.3803 * t - 0.0222 * t2;
++
++ return clamp(exp((a + b * NdotV) * NdotV + c), 0.0, 1.0);
++ }
++
++ // Energy left for the layers beneath the sheen, from the view direction only
++ float qt_sheenAlbedoScaling(in vec3 sheenColor, in float NdotV, in float sheenRoughness)
++ {
++ float maxSheen = max(max(sheenColor.r, sheenColor.g), sheenColor.b);
++ return 1.0 - maxSheen * qt_E_sheen(NdotV, sheenRoughness);
++ }
++
++ #endif // SHEEN_GLSLIB