Revision control
++ // Copyright (C) 2014 NVIDIA Corporation.
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "bsdf.glsllib"
++ #include "tonemapping.glsllib"
++
++ #ifndef SAMPLE_PROBE_GLSLLIB
++ #define SAMPLE_PROBE_GLSLLIB 1
++
++ #ifndef QSSG_ENABLE_RGBE_LIGHT_PROBE
++ #define QSSG_ENABLE_RGBE_LIGHT_PROBE 0
++ #endif
++
++ #ifdef QQ3D_SHADER_META
++ /*{
++ "uniforms": [
++ { "type": "samplerCube", "name": "qt_lightProbe" },
++ { "type": "vec4", "name": "qt_lightProbeProperties" },
++ { "type": "mat3", "name": "qt_lightProbeOrientation", "condition": "QSSG_ENABLE_IBL_ORIENTATION" }
++ ]
++ }*/
++ #endif // QQ3D_SHADER_META
++
++ vec3 qt_textureProbe(samplerCube lightProbe, vec3 dir, float lod)
++ {
++ #if QSSG_ENABLE_RGBE_LIGHT_PROBE
++ vec4 ret = textureLod(lightProbe, dir, lod);
++ return ret.rgb * pow(2.0, ret.a * 255.0 - 128.0);
++ #else
++ return textureLod(lightProbe, dir, lod).rgb;
++ #endif
++ }
++
++ vec4 qt_sampleDiffuse(vec3 normal)
++ {
++ // Note: qt_lightProbeProperties.w = Exposure
++ if (qt_lightProbeProperties.w < 0.005)
++ return vec4(0.0);
++ vec3 smpDir = normal;
++ #if QSSG_ENABLE_IBL_ORIENTATION
++ smpDir = qt_lightProbeOrientation * smpDir;
++ #endif
++ float baseLevel = qt_lightProbeProperties.y;
++ // Irradiance map is contained in mip at baseLevel
++ vec3 val = qt_textureProbe(qt_lightProbe, smpDir, baseLevel);
++
++ if (qt_lightProbeProperties.z > -1.0) {
++ float ctr = 0.5 + 0.5 * qt_lightProbeProperties.z;
++ float vertWt = smoothstep(ctr * 0.25, ctr + 0.25, smpDir.y);
++ float wtScaled = mix(1.0, vertWt, qt_lightProbeProperties.z + 1.0);
++ val *= wtScaled;
++ }
++
++ return vec4(qt_exposure(val, qt_lightProbeProperties.w), 1.0);
++ }
++
++ // This method is used by DefaultMaterial for the specular term
++ vec4 qt_sampleGlossy(vec3 normal, vec3 viewDir, float rough)
++ {
++ // Note: qt_lightProbeProperties.w == Exposure
++ if (qt_lightProbeProperties.w < 0.005)
++ return vec4(0.0);
++
++ float sigma = smoothstep(0.0, 1.0, clamp(rough, 0.0001, 1.0));
++ vec3 ret = vec3(0, 0, 0);
++ vec3 smpDir = reflect(-viewDir, normal);
++ #if QSSG_ENABLE_IBL_ORIENTATION
++ smpDir = qt_lightProbeOrientation * smpDir;
++ #endif
++
++ // Compute the Geometric occlusion/self-shadowing term
++ float NdotL = clamp(dot(smpDir, normal), 0.0, 0.999995);
++ float k = sigma * 0.31830988618; // roughness / pi
++ float Gl = clamp((NdotL / (NdotL*(1.0-k) + k) + (1.0 - k*k)) * 0.5, 0.0, 1.0 );
++ float levels = qt_lightProbeProperties.y - 1.0;
++
++ vec3 outColor = qt_textureProbe(qt_lightProbe, smpDir, sigma * levels);
++ if (qt_lightProbeProperties.z > -1.0) {
++ float ctr = 0.5 + 0.5 * qt_lightProbeProperties.z;
++ float vertWt = smoothstep(ctr * 0.25, ctr + 0.25, smpDir.y);
++ float wtScaled = mix(1.0, vertWt, qt_lightProbeProperties.z + 1.0);
++ outColor *= wtScaled;
++ }
++
++ outColor = qt_exposure(outColor, qt_lightProbeProperties.w);
++
++ return vec4(Gl * outColor, 1.0);
++ }
++
++ // This method is used by the PrincipledMaterial for the IBL specular term.
++ vec4 qt_sampleGlossyPrincipled(vec3 normal, vec3 viewDir, vec3 F, float roughness)
++ {
++ if (qt_lightProbeProperties.w < 0.005)
++ return vec4(0.0);
++
++ // pre-filtered maps for each roughnesses level are stored in the mips
++ // higher than the value of qt_lightProbeOffset.w
++ float levels = qt_lightProbeProperties.y - 1.0;
++
++ float lod = clamp((roughness * 5), 0.0, levels);
++ vec3 smpDir = normalize(reflect(-viewDir, normal));
++ #if QSSG_ENABLE_IBL_ORIENTATION
++ smpDir = qt_lightProbeOrientation * smpDir;
++ #endif
++
++ vec3 specularSample = qt_textureProbe(qt_lightProbe, smpDir, lod);
++ vec2 brdf = qt_brdfApproximation(normal, viewDir, roughness);
++ if (qt_lightProbeProperties.z > -1.0) {
++ float ctr = 0.5 + 0.5 * qt_lightProbeProperties.z;
++ float vertWt = smoothstep(ctr * 0.25, ctr + 0.25, smpDir.y);
++ float wtScaled = mix(1.0, vertWt, qt_lightProbeProperties.z + 1.0);
++ specularSample *= wtScaled;
++ }
++
++ vec3 sampleColor = (specularSample * (F * brdf.x + brdf.y));
++
++ return vec4(qt_exposure(sampleColor, qt_lightProbeProperties.w), 1.0);
++ }
++
++ #if QSSG_ENABLE_ANISOTROPY
++ // The bent normal aims the reflection, the shading normal drives the BRDF
++ vec4 qt_sampleGlossyAnisotropic(vec3 normal, vec3 bentNormal, vec3 viewDir, vec3 F, float roughness)
++ {
++ if (qt_lightProbeProperties.w < 0.005)
++ return vec4(0.0);
++
++ float levels = qt_lightProbeProperties.y - 1.0;
++
++ float lod = clamp((roughness * 5), 0.0, levels);
++ vec3 smpDir = normalize(reflect(-viewDir, bentNormal));
++ #if QSSG_ENABLE_IBL_ORIENTATION
++ smpDir = qt_lightProbeOrientation * smpDir;
++ #endif
++
++ vec3 specularSample = qt_textureProbe(qt_lightProbe, smpDir, lod);
++ vec2 brdf = qt_brdfApproximation(normal, viewDir, roughness);
++ if (qt_lightProbeProperties.z > -1.0) {
++ float ctr = 0.5 + 0.5 * qt_lightProbeProperties.z;
++ float vertWt = smoothstep(ctr * 0.25, ctr + 0.25, smpDir.y);
++ float wtScaled = mix(1.0, vertWt, qt_lightProbeProperties.z + 1.0);
++ specularSample *= wtScaled;
++ }
++
++ vec3 sampleColor = (specularSample * (F * brdf.x + brdf.y));
++
++ return vec4(qt_exposure(sampleColor, qt_lightProbeProperties.w), 1.0);
++ }
++ #endif // QSSG_ENABLE_ANISOTROPY
++
++ #if QSSG_ENABLE_SHEEN
++ #include "sheen.glsllib"
++
++ // The Charlie lobe is much wider than GGX, so it has its own mip mapping
++ vec4 qt_sampleGlossySheen(vec3 normal, vec3 viewDir, vec3 sheenColor, float sheenRoughness)
++ {
++ if (qt_lightProbeProperties.w < 0.005)
++ return vec4(0.0);
++
++ float levels = qt_lightProbeProperties.y - 1.0;
++ float lod = clamp(1.0 + sheenRoughness * (levels - 1.0), 0.0, levels);
++ vec3 smpDir = normalize(reflect(-viewDir, normal));
++ #if QSSG_ENABLE_IBL_ORIENTATION
++ smpDir = qt_lightProbeOrientation * smpDir;
++ #endif
++
++ vec3 sheenSample = qt_textureProbe(qt_lightProbe, smpDir, lod);
++ if (qt_lightProbeProperties.z > -1.0) {
++ float ctr = 0.5 + 0.5 * qt_lightProbeProperties.z;
++ float vertWt = smoothstep(ctr * 0.25, ctr + 0.25, smpDir.y);
++ float wtScaled = mix(1.0, vertWt, qt_lightProbeProperties.z + 1.0);
++ sheenSample *= wtScaled;
++ }
++
++ // The albedo takes the place of the split-sum BRDF factor
++ float NdotV = clamp(dot(normal, viewDir), 0.0, 1.0);
++ vec3 sampleColor = sheenSample * sheenColor * qt_E_sheen(NdotV, sheenRoughness);
++
++ return vec4(qt_exposure(sampleColor, qt_lightProbeProperties.w), 1.0);
++ }
++ #endif // QSSG_ENABLE_SHEEN
++
++ #endif