PPEyeAdaptation.bsl 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include "$ENGINE$\PPBase.bslinc"
  2. #include "$ENGINE$\PPEyeAdaptationCommon.bslinc"
  3. technique PPEyeAdaptation
  4. {
  5. mixin PPBase;
  6. mixin PPEyeAdaptationParams;
  7. code
  8. {
  9. #define NUM_BUCKETS (THREADGROUP_SIZE_X * THREADGROUP_SIZE_Y)
  10. Texture2D gHistogramTex;
  11. /**
  12. * Returns luminance of the histogram bucket.
  13. *
  14. * @param pos Position of the histogram bucket in range [0, 1].
  15. * @return Luminance of the bucket.
  16. */
  17. float calcHistogramLuminance(float pos)
  18. {
  19. return exp2((pos - gEyeAdaptationParams[0].y) / gEyeAdaptationParams[0].x);
  20. }
  21. /**
  22. * Returns value of the histogram bucket.
  23. *
  24. * @param histogram Texture containing the histogram buckets in the first row.
  25. * @param bucketIdx Index of the bucket. Caller must ensure it is in valid range.
  26. * @return Value of the needed histogram bucket.
  27. */
  28. float getHistogramValue(Texture2D histogram, uint bucketIdx)
  29. {
  30. uint texelIdx = bucketIdx / 4;
  31. float4 packedValue = histogram.Load(int3(texelIdx, 0, 0));
  32. float4 mask = float4(
  33. (bucketIdx % 4) == 0,
  34. (bucketIdx % 4) == 1,
  35. (bucketIdx % 4) == 2,
  36. (bucketIdx % 4) == 3);
  37. return dot(packedValue, mask);
  38. }
  39. /**
  40. * Calculates the sum of all values in the histogram.
  41. *
  42. * @param histogram Texture containing the histogram buckets in the first row.
  43. * @return Sum of all the values in the histogram.
  44. */
  45. float calcHistogramSum(Texture2D histogram)
  46. {
  47. float sum = 0;
  48. for(uint i = 0; i < NUM_BUCKETS; i++)
  49. sum += getHistogramValue(histogram, i);
  50. return sum;
  51. }
  52. /**
  53. * Calculates the average luminance in the histogram, while ignoring the outlier values that may skew the result.
  54. *
  55. * @param histogram Texture containing the histogram buckets in the first row.
  56. * @param low Sum below which to ignore values (removing lower end outliers), in range [0, histogramSum].
  57. * @param high Sum above which to ignore values (removing higher end outliers), in range [0, histogramSum].
  58. * Must be higher than @low.
  59. * @return Average luminance in the histogram.
  60. */
  61. float calcHistogramAverageLuminance(Texture2D histogram, float low, float high)
  62. {
  63. float2 sumAndWeight = float2(0.0f, 0.0f);
  64. for(uint i = 0; i < NUM_BUCKETS; i++)
  65. {
  66. float value = getHistogramValue(histogram, i);
  67. // Ignore any values below the @low parameter, and then shift the valid range
  68. // by the amount we ignored. Eventually the low end of the range reaches zero
  69. // and values are no longer ignored.
  70. float offset = min(value, low);
  71. value = value - offset;
  72. low -= offset;
  73. high -= offset;
  74. // Ignore any values above the @high parameter, and then shift the valid range.
  75. value = min(value, high);
  76. high -= value;
  77. float histogramPos = i / (float)NUM_BUCKETS;
  78. float luminance = calcHistogramLuminance(histogramPos);
  79. sumAndWeight += float2(luminance, 1) * value;
  80. }
  81. return sumAndWeight.x / max(0.0001f, sumAndWeight.y);
  82. }
  83. /**
  84. * Calculates the eye adaptation from the luminance in the provided histogram. Eye adaptation value will be
  85. * used for automatically scaling expsure based on scene brightness.
  86. *
  87. * @param histogram Texture containing the histogram buckets in the first row.
  88. * @return Ideal eye adaptation value for the provided luminance.
  89. */
  90. float calcEyeAdaptation(Texture2D histogram)
  91. {
  92. float sum = calcHistogramSum(histogram);
  93. float lowRange = gEyeAdaptationParams[0].z * sum;
  94. float highRange = gEyeAdaptationParams[0].w * sum;
  95. float avgLuminance = calcHistogramAverageLuminance(histogram, lowRange, highRange);
  96. avgLuminance = clamp(avgLuminance, gEyeAdaptationParams[1].x, gEyeAdaptationParams[1].y);
  97. return avgLuminance;
  98. }
  99. float4 fsmain(VStoFS input) : SV_Target0
  100. {
  101. float exposureScale = gEyeAdaptationParams[2].x;
  102. float targetAdaptation = calcEyeAdaptation(gHistogramTex);
  103. float oldExposure = gHistogramTex.Load(int3(0, 1, 0)).x;
  104. float oldAdaptation = exposureScale / oldExposure; // Assuming same exposure scale as last frame
  105. float frameDelta = gEyeAdaptationParams[2].y;
  106. float smoothAdaptation = smoothEyeAdaptation(oldAdaptation, targetAdaptation, frameDelta);
  107. return exposureScale / smoothAdaptation; // Returns exposure
  108. }
  109. };
  110. };