TonemappingAverageLuminance.ankiprog 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. ANKI_SPECIALIZATION_CONSTANT_UVEC2(INPUT_TEX_SIZE, 0, UVec2(1));
  6. #pragma anki start comp
  7. #define LOG_AVG 0
  8. #include <shaders/Common.glsl>
  9. #include <shaders/Tonemapping.glsl>
  10. const UVec2 WORKGROUP_SIZE = UVec2(32u, 32u);
  11. layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
  12. // Align the tex size to workgroup size
  13. const UVec2 ALIGNED_INPUT_TEX_SIZE = WORKGROUP_SIZE * ((INPUT_TEX_SIZE + WORKGROUP_SIZE - 1u) / WORKGROUP_SIZE);
  14. const UVec2 PIXELS_PER_TILE = ALIGNED_INPUT_TEX_SIZE / WORKGROUP_SIZE;
  15. layout(set = 0, binding = 0) uniform texture2D u_tex;
  16. #define TONEMAPPING_RESOURCE_AS_BUFFER 1
  17. #define TONEMAPPING_SET 0
  18. #define TONEMAPPING_BINDING 1
  19. #include <shaders/TonemappingResources.glsl>
  20. shared F32 s_avgLum[WORKGROUP_SIZE.x * WORKGROUP_SIZE.y];
  21. void main()
  22. {
  23. // Gather the log-average luminance of a tile. It will miss some pixels but not too many
  24. const U32 yStart = gl_LocalInvocationID.y * PIXELS_PER_TILE.y;
  25. const U32 xStart = gl_LocalInvocationID.x * PIXELS_PER_TILE.x;
  26. F32 avgLum = 0.0;
  27. ANKI_UNROLL for(U32 y = 0; y < PIXELS_PER_TILE.y; ++y)
  28. {
  29. ANKI_UNROLL for(U32 x = 0; x < PIXELS_PER_TILE.x; ++x)
  30. {
  31. const UVec2 uv = UVec2(xStart, yStart) + UVec2(x, y);
  32. if(uv.x >= INPUT_TEX_SIZE.x || uv.y >= INPUT_TEX_SIZE.y)
  33. {
  34. continue;
  35. }
  36. const Vec3 color = texelFetch(u_tex, IVec2(uv), 0).rgb;
  37. const F32 lum = computeLuminance(color);
  38. #if LOG_AVG
  39. avgLum += log(max(EPSILON, lum));
  40. #else
  41. avgLum += lum;
  42. #endif
  43. }
  44. }
  45. s_avgLum[gl_LocalInvocationIndex] = avgLum;
  46. memoryBarrierShared();
  47. barrier();
  48. // Gather the results into one
  49. ANKI_LOOP for(U32 s = (WORKGROUP_SIZE.x * WORKGROUP_SIZE.y) / 2u; s > 0u; s >>= 1u)
  50. {
  51. if(gl_LocalInvocationIndex < s)
  52. {
  53. s_avgLum[gl_LocalInvocationIndex] += s_avgLum[gl_LocalInvocationIndex + s];
  54. }
  55. memoryBarrierShared();
  56. barrier();
  57. }
  58. // Write the result
  59. ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
  60. {
  61. #if LOG_AVG
  62. const F32 crntLum = exp(s_avgLum[0] * (1.0 / F32(INPUT_TEX_SIZE.x * INPUT_TEX_SIZE.y)));
  63. #else
  64. const F32 crntLum = s_avgLum[0] * (1.0 / F32(INPUT_TEX_SIZE.x * INPUT_TEX_SIZE.y));
  65. #endif
  66. #if 1
  67. const F32 prevLum = u_averageLuminance;
  68. // Lerp between previous and new L value
  69. const F32 INTERPOLATION_FACTOR = 0.05;
  70. F32 finalAvgLum = mix(prevLum, crntLum, INTERPOLATION_FACTOR);
  71. #else
  72. F32 finalAvgLum = crntLum;
  73. #endif
  74. // This is a workaround because sometimes the avg lum becomes nan
  75. finalAvgLum = clamp(finalAvgLum, EPSILON, FLT_MAX);
  76. u_averageLuminance = finalAvgLum;
  77. u_exposureThreshold0 = computeExposure(u_averageLuminance, 0.0);
  78. }
  79. }
  80. #pragma anki end