You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
6.4 KiB

  1. Shader "Hidden/Post FX/Eye Adaptation"
  2. {
  3. Properties
  4. {
  5. _MainTex("Texture", 2D) = "white" {}
  6. }
  7. CGINCLUDE
  8. #pragma target 4.5
  9. #pragma multi_compile __ AUTO_KEY_VALUE
  10. #include "UnityCG.cginc"
  11. #include "Common.cginc"
  12. #include "EyeAdaptation.cginc"
  13. // Eye adaptation pass
  14. float4 _Params; // x: lowPercent, y: highPercent, z: minBrightness, w: maxBrightness
  15. float2 _Speed; // x: down, y: up
  16. float4 _ScaleOffsetRes; // x: scale, y: offset, w: histogram pass width, h: histogram pass height
  17. float _ExposureCompensation;
  18. StructuredBuffer<uint> _Histogram;
  19. float GetBinValue(uint index, float maxHistogramValue)
  20. {
  21. return float(_Histogram[index]) * maxHistogramValue;
  22. }
  23. // Done in the vertex shader
  24. float FindMaxHistogramValue()
  25. {
  26. uint maxValue = 0u;
  27. for (uint i = 0; i < HISTOGRAM_BINS; i++)
  28. {
  29. uint h = _Histogram[i];
  30. maxValue = max(maxValue, h);
  31. }
  32. return float(maxValue);
  33. }
  34. void FilterLuminance(uint i, float maxHistogramValue, inout float4 filter)
  35. {
  36. float binValue = GetBinValue(i, maxHistogramValue);
  37. // Filter dark areas
  38. float offset = min(filter.z, binValue);
  39. binValue -= offset;
  40. filter.zw -= offset.xx;
  41. // Filter highlights
  42. binValue = min(filter.w, binValue);
  43. filter.w -= binValue;
  44. // Luminance at the bin
  45. float luminance = GetLuminanceFromHistogramBin(float(i) / float(HISTOGRAM_BINS), _ScaleOffsetRes.xy);
  46. filter.xy += float2(luminance * binValue, binValue);
  47. }
  48. float GetAverageLuminance(float maxHistogramValue)
  49. {
  50. // Sum of all bins
  51. uint i;
  52. float totalSum = 0.0;
  53. UNITY_LOOP
  54. for (i = 0; i < HISTOGRAM_BINS; i++)
  55. totalSum += GetBinValue(i, maxHistogramValue);
  56. // Skip darker and lighter parts of the histogram to stabilize the auto exposure
  57. // x: filtered sum
  58. // y: accumulator
  59. // zw: fractions
  60. float4 filter = float4(0.0, 0.0, totalSum * _Params.xy);
  61. UNITY_LOOP
  62. for (i = 0; i < HISTOGRAM_BINS; i++)
  63. FilterLuminance(i, maxHistogramValue, filter);
  64. // Clamp to user brightness range
  65. return clamp(filter.x / max(filter.y, EPSILON), _Params.z, _Params.w);
  66. }
  67. float GetExposureMultiplier(float avgLuminance)
  68. {
  69. avgLuminance = max(EPSILON, avgLuminance);
  70. #if AUTO_KEY_VALUE
  71. half keyValue = 1.03 - (2.0 / (2.0 + log2(avgLuminance + 1.0)));
  72. #else
  73. half keyValue = _ExposureCompensation;
  74. #endif
  75. half exposure = keyValue / avgLuminance;
  76. return exposure;
  77. }
  78. float InterpolateExposure(float newExposure, float oldExposure)
  79. {
  80. float delta = newExposure - oldExposure;
  81. float speed = delta > 0.0 ? _Speed.x : _Speed.y;
  82. float exposure = oldExposure + delta * (1.0 - exp2(-unity_DeltaTime.x * speed));
  83. //float exposure = oldExposure + delta * (unity_DeltaTime.x * speed);
  84. return exposure;
  85. }
  86. float4 FragAdaptProgressive(VaryingsDefault i) : SV_Target
  87. {
  88. float maxValue = 1.0 / FindMaxHistogramValue();
  89. float avgLuminance = GetAverageLuminance(maxValue);
  90. float exposure = GetExposureMultiplier(avgLuminance);
  91. float prevExposure = tex2D(_MainTex, (0.5).xx);
  92. exposure = InterpolateExposure(exposure, prevExposure);
  93. return exposure.xxxx;
  94. }
  95. float4 FragAdaptFixed(VaryingsDefault i) : SV_Target
  96. {
  97. float maxValue = 1.0 / FindMaxHistogramValue();
  98. float avgLuminance = GetAverageLuminance(maxValue);
  99. float exposure = GetExposureMultiplier(avgLuminance);
  100. return exposure.xxxx;
  101. }
  102. // ---- Editor stuff
  103. int _DebugWidth;
  104. struct VaryingsEditorHisto
  105. {
  106. float4 pos : SV_POSITION;
  107. float2 uv : TEXCOORD0;
  108. float maxValue : TEXCOORD1;
  109. float avgLuminance : TEXCOORD2;
  110. };
  111. VaryingsEditorHisto VertEditorHisto(AttributesDefault v)
  112. {
  113. VaryingsEditorHisto o;
  114. o.pos = UnityObjectToClipPos(v.vertex);
  115. o.uv = v.texcoord.xy;
  116. o.maxValue = 1.0 / FindMaxHistogramValue();
  117. o.avgLuminance = GetAverageLuminance(o.maxValue);
  118. return o;
  119. }
  120. float4 FragEditorHisto(VaryingsEditorHisto i) : SV_Target
  121. {
  122. const float3 kRangeColor = float3(0.05, 0.4, 0.6);
  123. const float3 kAvgColor = float3(0.8, 0.3, 0.05);
  124. float4 color = float4(0.0, 0.0, 0.0, 0.7);
  125. uint ix = (uint)(round(i.uv.x * HISTOGRAM_BINS));
  126. float bin = saturate(float(_Histogram[ix]) * i.maxValue);
  127. float fill = step(i.uv.y, bin);
  128. // Min / max brightness markers
  129. float luminanceMin = GetHistogramBinFromLuminance(_Params.z, _ScaleOffsetRes.xy);
  130. float luminanceMax = GetHistogramBinFromLuminance(_Params.w, _ScaleOffsetRes.xy);
  131. color.rgb += fill.rrr;
  132. if (i.uv.x > luminanceMin && i.uv.x < luminanceMax)
  133. {
  134. color.rgb = fill.rrr * kRangeColor;
  135. color.rgb += kRangeColor;
  136. }
  137. // Current average luminance marker
  138. float luminanceAvg = GetHistogramBinFromLuminance(i.avgLuminance, _ScaleOffsetRes.xy);
  139. float avgPx = luminanceAvg * _DebugWidth;
  140. if (abs(i.pos.x - avgPx) < 2)
  141. color.rgb = kAvgColor;
  142. return color;
  143. }
  144. ENDCG
  145. SubShader
  146. {
  147. Cull Off ZWrite Off ZTest Always
  148. Pass
  149. {
  150. CGPROGRAM
  151. #pragma vertex VertDefault
  152. #pragma fragment FragAdaptProgressive
  153. ENDCG
  154. }
  155. Pass
  156. {
  157. CGPROGRAM
  158. #pragma vertex VertDefault
  159. #pragma fragment FragAdaptFixed
  160. ENDCG
  161. }
  162. Pass
  163. {
  164. CGPROGRAM
  165. #pragma vertex VertEditorHisto
  166. #pragma fragment FragEditorHisto
  167. ENDCG
  168. }
  169. }
  170. }