TonemappingFunctions.hlsl 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Shaders/Common.hlsl>
  7. // A tick to compute log of base 10
  8. template<typename T>
  9. T log10(T x)
  10. {
  11. return log(x) / log(T(10));
  12. }
  13. template<typename T>
  14. T computeExposure(T avgLum, T threshold)
  15. {
  16. const T keyValue = T(1.03) - (T(2) / (T(2) + log10(avgLum + T(1))));
  17. const T linearExposure = (keyValue / avgLum);
  18. T exposure = log2(linearExposure);
  19. exposure -= threshold;
  20. return exp2(exposure);
  21. }
  22. template<typename T>
  23. vector<T, 3> computeExposedColor(vector<T, 3> color, vector<T, 3> avgLum, vector<T, 3> threshold)
  24. {
  25. return computeExposure(avgLum, threshold) * color;
  26. }
  27. // Uncharted 2 operator
  28. template<typename T>
  29. vector<T, 3> tonemapUncharted2(vector<T, 3> color)
  30. {
  31. constexpr T A = 0.15;
  32. constexpr T B = 0.50;
  33. constexpr T C = 0.10;
  34. constexpr T D = 0.20;
  35. constexpr T E = 0.02;
  36. constexpr T F = 0.30;
  37. return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
  38. }
  39. // See ACES in action and its inverse at https://www.desmos.com/calculator/n1lkpc6hwq
  40. template<typename T>
  41. vector<T, 3> tonemapACESFilm(vector<T, 3> x)
  42. {
  43. constexpr T kAcesA = 2.51;
  44. constexpr T kAcesB = 0.03;
  45. constexpr T kAcesC = 2.43;
  46. constexpr T kAcesD = 0.59;
  47. constexpr T kAcesE = 0.14;
  48. return saturate((x * (kAcesA * x + kAcesB)) / (x * (kAcesC * x + kAcesD) + kAcesE));
  49. }
  50. // https://www.desmos.com/calculator/n1lkpc6hwq
  51. template<typename T>
  52. vector<T, 3> invertTonemapACESFilm(vector<T, 3> x)
  53. {
  54. constexpr T kAcesA = 2.51;
  55. constexpr T kAcesB = 0.03;
  56. constexpr T kAcesC = 2.43;
  57. constexpr T kAcesD = 0.59;
  58. constexpr T kAcesE = 0.14;
  59. vector<T, 3> res = kAcesD * x - kAcesB;
  60. res += sqrt(x * x * (kAcesD * kAcesD - T(4) * kAcesE * kAcesC) + x * (T(4) * kAcesE * kAcesA - T(2) * kAcesB * kAcesD) + kAcesB * kAcesB);
  61. res /= T(2) * kAcesA - T(2) * kAcesC * x;
  62. return res;
  63. }
  64. // https://github.com/KhronosGroup/ToneMapping
  65. template<typename T>
  66. vector<T, 3> tonemapNatural(vector<T, 3> color)
  67. {
  68. const T startCompression = T(0.8 - 0.04);
  69. const T desaturation = T(0.15);
  70. const T x = min3(color);
  71. const T offset = x < T(0.08) ? x - T(6.25) * x * x : T(0.04);
  72. color -= offset;
  73. const T peak = max3(color);
  74. if(peak < startCompression)
  75. {
  76. return color;
  77. }
  78. const T d = T(1) - startCompression;
  79. const T newPeak = T(1) - d * d / (peak + d - startCompression);
  80. color *= newPeak / peak;
  81. const T g = T(1) / (desaturation * (peak - newPeak) + T(1));
  82. return lerp(newPeak, color, g);
  83. }
  84. template<typename T>
  85. vector<T, 3> invertTonemapNeutral(vector<T, 3> color)
  86. {
  87. const T startCompression = T(0.8 - 0.04);
  88. const T desaturation = T(0.15);
  89. const T peak = max3(color);
  90. if(peak > startCompression)
  91. {
  92. const T d = T(1) - startCompression;
  93. const T oldPeak = (d * d) / (T(1) - peak) - d + startCompression;
  94. const T fInv = desaturation * (oldPeak - peak) + T(1);
  95. const T f = T(1) / fInv;
  96. color = (color + (f - T(1)) * peak) * fInv;
  97. const T scale = oldPeak / peak;
  98. color *= scale;
  99. }
  100. const T y = min3(color);
  101. T offset = T(0.04);
  102. if(y < T(0.04))
  103. {
  104. const T x = sqrt(y / T(6.25));
  105. offset = x - T(6.25) * x * x;
  106. }
  107. color += offset;
  108. return color;
  109. }
  110. template<typename T>
  111. vector<T, 3> tonemap(vector<T, 3> color, vector<T, 3> exposure)
  112. {
  113. color *= exposure;
  114. return tonemapNatural(color);
  115. }
  116. template<typename T>
  117. vector<T, 3> invertTonemap(vector<T, 3> color, T exposure)
  118. {
  119. color = invertTonemapNeutral(color);
  120. color /= max(getEpsilon<T>(), exposure);
  121. return color;
  122. }
  123. template<typename T>
  124. vector<T, 3> tonemap(vector<T, 3> color, T avgLum, T threshold)
  125. {
  126. const T exposure = computeExposure(avgLum, threshold);
  127. return tonemap<T>(color, exposure);
  128. }
  129. // https://graphicrants.blogspot.com/2013/12/tone-mapping.html
  130. template<typename T>
  131. vector<T, 3> reinhardTonemap(vector<T, 3> colour)
  132. {
  133. // rgb / (1 + max(rgb))
  134. return colour / (T(1) + max(max(colour.r, colour.g), colour.b));
  135. }
  136. template<typename T>
  137. vector<T, 3> invertReinhardTonemap(vector<T, 3> colour)
  138. {
  139. // rgb / (1 - max(rgb))
  140. return colour / max(T(1.0 / 32768.0), T(1) - max(max(colour.r, colour.g), colour.b));
  141. }