ExposureHistogram.hlsl 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. #ifndef UNITY_POSTFX_EXPOSURE_HISTOGRAM
  2. #define UNITY_POSTFX_EXPOSURE_HISTOGRAM
  3. // Optimal values for PS4/GCN
  4. // Using a group size of 32x32 seems to be a bit faster on Kepler/Maxwell
  5. // Don't forget to update 'AutoExposureRenderer.cs' if you change these values !
  6. #define HISTOGRAM_BINS 128
  7. #define HISTOGRAM_TEXELS HISTOGRAM_BINS / 4
  8. #if SHADER_API_GLES3
  9. #define HISTOGRAM_THREAD_X 16
  10. #define HISTOGRAM_THREAD_Y 8
  11. #else
  12. #define HISTOGRAM_THREAD_X 16
  13. #define HISTOGRAM_THREAD_Y 16
  14. #endif
  15. float GetHistogramBinFromLuminance(float value, float2 scaleOffset)
  16. {
  17. return saturate(log2(value) * scaleOffset.x + scaleOffset.y);
  18. }
  19. float GetLuminanceFromHistogramBin(float bin, float2 scaleOffset)
  20. {
  21. return exp2((bin - scaleOffset.y) / scaleOffset.x);
  22. }
  23. float GetBinValue(StructuredBuffer<uint> buffer, uint index, float maxHistogramValue)
  24. {
  25. return float(buffer[index]) * maxHistogramValue;
  26. }
  27. float FindMaxHistogramValue(StructuredBuffer<uint> buffer)
  28. {
  29. uint maxValue = 0u;
  30. for (uint i = 0; i < HISTOGRAM_BINS; i++)
  31. {
  32. uint h = buffer[i];
  33. maxValue = max(maxValue, h);
  34. }
  35. return float(maxValue);
  36. }
  37. void FilterLuminance(StructuredBuffer<uint> buffer, uint i, float maxHistogramValue, float2 scaleOffset, inout float4 filter)
  38. {
  39. float binValue = GetBinValue(buffer, i, maxHistogramValue);
  40. // Filter dark areas
  41. float offset = min(filter.z, binValue);
  42. binValue -= offset;
  43. filter.zw -= offset.xx;
  44. // Filter highlights
  45. binValue = min(filter.w, binValue);
  46. filter.w -= binValue;
  47. // Luminance at the bin
  48. float luminance = GetLuminanceFromHistogramBin(float(i) / float(HISTOGRAM_BINS), scaleOffset);
  49. filter.xy += float2(luminance * binValue, binValue);
  50. }
  51. float GetAverageLuminance(StructuredBuffer<uint> buffer, float4 params, float maxHistogramValue, float2 scaleOffset)
  52. {
  53. // Sum of all bins
  54. uint i;
  55. float totalSum = 0.0;
  56. UNITY_UNROLL
  57. for (i = 0; i < HISTOGRAM_BINS; i++)
  58. totalSum += GetBinValue(buffer, i, maxHistogramValue);
  59. // Skip darker and lighter parts of the histogram to stabilize the auto exposure
  60. // x: filtered sum
  61. // y: accumulator
  62. // zw: fractions
  63. float4 filter = float4(0.0, 0.0, totalSum * params.xy);
  64. UNITY_UNROLL
  65. for (i = 0; i < HISTOGRAM_BINS; i++)
  66. FilterLuminance(buffer, i, maxHistogramValue, scaleOffset, filter);
  67. // Clamp to user brightness range
  68. return clamp(filter.x / max(filter.y, EPSILON), params.z, params.w);
  69. }
  70. #endif // UNITY_POSTFX_EXPOSURE_HISTOGRAM