Revision control
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #ifndef TONEMAPPPING_GLSLIB
++ #define TONEMAPPPING_GLSLIB 1
++
++ // This file is also included from the static shader skybox.frag, therefore pay
++ // attention that it should be suitable both as a generator-included and as a
++ // static-shader-included snippet. It may also be included from post-processing
++ // effect fragment shaders.
++
++ // Any changes to the calculations must be reflected in qssgcputonemapper_p.h.
++
++ #ifndef QSSG_ENABLE_LINEAR_TONEMAPPING
++ #define QSSG_ENABLE_LINEAR_TONEMAPPING 0
++ #endif
++ #ifndef QSSG_ENABLE_ACES_TONEMAPPING
++ #define QSSG_ENABLE_ACES_TONEMAPPING 0
++ #endif
++ #ifndef QSSG_ENABLE_HEJLDAWSON_TONEMAPPING
++ #define QSSG_ENABLE_HEJLDAWSON_TONEMAPPING 0
++ #endif
++ #ifndef QSSG_ENABLE_FILMIC_TONEMAPPING
++ #define QSSG_ENABLE_FILMIC_TONEMAPPING 0
++ #endif
++ #ifndef QSSG_FORCE_IBL_EXPOSURE
++ #define QSSG_FORCE_IBL_EXPOSURE 0
++ #endif
++
++ // The following methods are described in this article:
++
++ // The following 4 methods are the most accurate approximations
++ vec3 qt_linearTosRGB(vec3 color)
++ {
++ vec3 S1 = sqrt(color);
++ vec3 S2 = sqrt(S1);
++ vec3 S3 = sqrt(S2);
++ return 0.585122381 * S1 + 0.783140355 * S2 - 0.368262736 * S3;
++ }
++
++ vec3 qt_sRGBToLinear(vec3 srgbIn)
++ {
++ return srgbIn * (srgbIn * (srgbIn * 0.305306011 + 0.682171111) + 0.012522878);
++ }
++
++ vec4 qt_linearTosRGB(vec4 color)
++ {
++ return vec4(qt_linearTosRGB(color.rgb), color.a);
++ }
++
++ vec4 qt_sRGBToLinear(vec4 srgbIn)
++ {
++ return vec4(qt_sRGBToLinear(srgbIn.rgb), srgbIn.a);
++ }
++
++ const float GAMMA = 2.2;
++ const float INV_GAMMA = 1.0 / GAMMA;
++
++ // The following 4 methods are the fastest, but less accurate
++
++ vec3 qt_linearTosRGBFast(vec3 color)
++ {
++ return pow(color, vec3(INV_GAMMA));
++ }
++
++ vec3 qt_sRGBToLinearFast(vec3 srgbIn)
++ {
++ return vec3(pow(srgbIn.xyz, vec3(GAMMA)));
++ }
++
++ vec4 qt_linearTosRGBFast(vec4 color)
++ {
++ return vec4(pow(color.rgb, vec3(INV_GAMMA)), color.a);
++ }
++
++ vec4 qt_sRGBToLinearFast(vec4 srgbIn)
++ {
++ return vec4(pow(srgbIn.rgb, vec3(GAMMA)), srgbIn.a);
++ }
++
++ #if QSSG_ENABLE_ACES_TONEMAPPING
++ vec3 qt_toneMapACES(vec3 color)
++ {
++ const float A = 2.51;
++ const float B = 0.03;
++ const float C = 2.43;
++ const float D = 0.59;
++ const float E = 0.14;
++ return qt_linearTosRGB(clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0));
++ }
++ #endif
++
++ #if QSSG_ENABLE_HEJLDAWSON_TONEMAPPING
++ vec3 qt_tonemapHejlDawson(vec3 color)
++ {
++ color = max(vec3(0.0), color - vec3(0.004));
++ return (color * (6.2 * color + 0.5)) / (color * (6.2 * color + 1.7) + 0.06);
++ }
++ #endif
++
++ #if QSSG_ENABLE_FILMIC_TONEMAPPING
++ vec3 qt_toneMapFilmicSub(vec3 color)
++ {
++ const float A = 0.15;
++ const float B = 0.50;
++ const float C = 0.10;
++ const float D = 0.20;
++ const float E = 0.02;
++ const float F = 0.30;
++ return ((color * ( A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
++ }
++
++ vec3 qt_toneMapFilmic(vec3 color)
++ {
++ color = qt_toneMapFilmicSub(color * 2.0);
++ vec3 whiteScale = 1.0 / qt_toneMapFilmicSub(vec3(11.2, 11.2, 11.2));
++ return qt_linearTosRGB(color * whiteScale);
++ }
++ #endif
++
++ // Call this method to perform tonemapping with the correct tonemapper
++ vec3 qt_tonemap(vec3 color)
++ {
++ // ACES
++ #if QSSG_ENABLE_ACES_TONEMAPPING
++ return qt_toneMapACES(color);
++ #endif
++ // Hejl-Dawson
++ #if QSSG_ENABLE_HEJLDAWSON_TONEMAPPING
++ return qt_tonemapHejlDawson(color);
++ #endif
++
++ // Filmic
++ #if QSSG_ENABLE_FILMIC_TONEMAPPING
++ return qt_toneMapFilmic(color);
++ #endif
++
++ // Linear
++ #if QSSG_ENABLE_LINEAR_TONEMAPPING
++ return qt_linearTosRGB(color);
++ #endif
++
++ return color;
++ }
++
++ vec4 qt_tonemap(vec4 color)
++ {
++ return vec4(qt_tonemap(color.rgb), color.a);
++ }
++
++ #ifdef QSSG_RUNTIME_TONEMAPPING
++
++ // This overload chooses the correct tonemapper at runtime
++ vec3 qt_tonemap(vec3 color, bool sRgbsource, uint tonemap_mode)
++ {
++ const int LINEAR = 1;
++ const int ACES = 2;
++ const int HEJLDAWSON = 3;
++ const int FILMIC = 4;
++
++ if (sRgbsource && tonemap_mode == LINEAR)
++ return color;
++
++ vec3 linear_color = sRgbsource ? qt_sRGBToLinear(color) : color;
++
++ switch (tonemap_mode) {
++ #if QSSG_ENABLE_LINEAR_TONEMAPPING
++ case LINEAR:
++ return qt_linearTosRGB(linear_color);
++ #endif
++ #if QSSG_ENABLE_ACES_TONEMAPPING
++ case ACES:
++ return qt_toneMapACES(linear_color);
++ #endif
++ #if QSSG_ENABLE_HEJLDAWSON_TONEMAPPING
++ case HEJLDAWSON:
++ return qt_tonemapHejlDawson(linear_color);
++ #endif
++ #if QSSG_ENABLE_FILMIC_TONEMAPPING
++ case FILMIC:
++ return qt_toneMapFilmic(linear_color);
++ #endif
++ default:
++ return linear_color;
++ }
++ }
++
++ vec4 qt_tonemap(vec4 color, bool sRgbsource, uint tonemap_mode)
++ {
++ return vec4(qt_tonemap(color.rgb, sRgbsource, tonemap_mode), color.a);
++ }
++
++ #endif
++
++ vec3 qt_exposure(vec3 color, float exposure)
++ {
++ #if QSSG_ENABLE_ACES_TONEMAPPING || QSSG_ENABLE_HEJLDAWSON_TONEMAPPING || QSSG_ENABLE_FILMIC_TONEMAPPING || QSSG_ENABLE_LINEAR_TONEMAPPING || QSSG_FORCE_IBL_EXPOSURE
++ return vec3(vec3(1.0) - exp(-color * exposure));
++ #else
++ return color;
++ #endif
++ }
++
++ #endif // TONEMAPPPING_GLSLIB