| 41 | } // namespace HLSL |
| 42 | |
| 43 | float3 ReverseExpToneMap(const float3& Color, float MiddleGray, float AverageLogLum) |
| 44 | { |
| 45 | // Exponential tone mapping is computed as follows: |
| 46 | // |
| 47 | // float LumScale = MiddleGray / AverageLogLum; |
| 48 | // float InitialLum = dot(RGB_TO_LUMINANCE, Color); |
| 49 | // float ScaledLum = InitialLum * LumScale; |
| 50 | // float3 ScaledColor = Color * LumScale; |
| 51 | // float ToneMappedLum = 1.0 - exp(-ScaledLum); |
| 52 | // float3 ToneMappedColor = ToneMappedLum * pow(Color / InitialLum, LuminanceSaturation); |
| 53 | // |
| 54 | // To reverse this operator, we will make the following assumptions: |
| 55 | // - The color is grayscale: |
| 56 | // - Color = (L, L, L) |
| 57 | // - InitialLum = L |
| 58 | // - LuminanceSaturation is 1.0 (this is the default value) |
| 59 | // |
| 60 | // With the assumption the math simplifies to: |
| 61 | // |
| 62 | // float3 ToneMappedColor = ToneMappedLum |
| 63 | // = 1.0 - exp(-ScaledLum) |
| 64 | // = 1.0 - exp(-InitialLum * LumScale) |
| 65 | // Thus |
| 66 | // |
| 67 | // ToneMappedLum = 1.0 - exp(-InitialLum * LumScale) |
| 68 | // |
| 69 | // And |
| 70 | // |
| 71 | // InitialLum = -log(1.0 - ToneMappedLum) / LumScale |
| 72 | // |
| 73 | |
| 74 | static constexpr float3 RGB_TO_LUMINANCE{0.212671f, 0.715160f, 0.072169f}; |
| 75 | |
| 76 | const float Luminance = dot(RGB_TO_LUMINANCE, Color); |
| 77 | if (Luminance == 0) |
| 78 | return float3{0, 0, 0}; |
| 79 | |
| 80 | float fLumScale = MiddleGray / AverageLogLum; |
| 81 | float ToneMappedLum = -std::log(std::max(1.0f - Luminance, 0.01f)) / fLumScale; |
| 82 | return Color * ToneMappedLum / Luminance; |
| 83 | } |
| 84 | |
| 85 | bool ToneMappingUpdateUI(HLSL::ToneMappingAttribs& Attribs, float* AverageLogLum) |
| 86 | { |