|
|
- Shader "Hidden/Post FX/Eye Adaptation"
- {
- Properties
- {
- _MainTex("Texture", 2D) = "white" {}
- }
-
- CGINCLUDE
-
- #pragma target 4.5
- #pragma multi_compile __ AUTO_KEY_VALUE
- #include "UnityCG.cginc"
- #include "Common.cginc"
- #include "EyeAdaptation.cginc"
-
- // Eye adaptation pass
- float4 _Params; // x: lowPercent, y: highPercent, z: minBrightness, w: maxBrightness
- float2 _Speed; // x: down, y: up
- float4 _ScaleOffsetRes; // x: scale, y: offset, w: histogram pass width, h: histogram pass height
- float _ExposureCompensation;
-
- StructuredBuffer<uint> _Histogram;
-
- float GetBinValue(uint index, float maxHistogramValue)
- {
- return float(_Histogram[index]) * maxHistogramValue;
- }
-
- // Done in the vertex shader
- float FindMaxHistogramValue()
- {
- uint maxValue = 0u;
-
- for (uint i = 0; i < HISTOGRAM_BINS; i++)
- {
- uint h = _Histogram[i];
- maxValue = max(maxValue, h);
- }
-
- return float(maxValue);
- }
-
- void FilterLuminance(uint i, float maxHistogramValue, inout float4 filter)
- {
- float binValue = GetBinValue(i, maxHistogramValue);
-
- // Filter dark areas
- float offset = min(filter.z, binValue);
- binValue -= offset;
- filter.zw -= offset.xx;
-
- // Filter highlights
- binValue = min(filter.w, binValue);
- filter.w -= binValue;
-
- // Luminance at the bin
- float luminance = GetLuminanceFromHistogramBin(float(i) / float(HISTOGRAM_BINS), _ScaleOffsetRes.xy);
-
- filter.xy += float2(luminance * binValue, binValue);
- }
-
- float GetAverageLuminance(float maxHistogramValue)
- {
- // Sum of all bins
- uint i;
- float totalSum = 0.0;
-
- UNITY_LOOP
- for (i = 0; i < HISTOGRAM_BINS; i++)
- totalSum += GetBinValue(i, maxHistogramValue);
-
- // Skip darker and lighter parts of the histogram to stabilize the auto exposure
- // x: filtered sum
- // y: accumulator
- // zw: fractions
- float4 filter = float4(0.0, 0.0, totalSum * _Params.xy);
-
- UNITY_LOOP
- for (i = 0; i < HISTOGRAM_BINS; i++)
- FilterLuminance(i, maxHistogramValue, filter);
-
- // Clamp to user brightness range
- return clamp(filter.x / max(filter.y, EPSILON), _Params.z, _Params.w);
- }
-
- float GetExposureMultiplier(float avgLuminance)
- {
- avgLuminance = max(EPSILON, avgLuminance);
-
- #if AUTO_KEY_VALUE
- half keyValue = 1.03 - (2.0 / (2.0 + log2(avgLuminance + 1.0)));
- #else
- half keyValue = _ExposureCompensation;
- #endif
-
- half exposure = keyValue / avgLuminance;
-
- return exposure;
- }
-
- float InterpolateExposure(float newExposure, float oldExposure)
- {
- float delta = newExposure - oldExposure;
- float speed = delta > 0.0 ? _Speed.x : _Speed.y;
- float exposure = oldExposure + delta * (1.0 - exp2(-unity_DeltaTime.x * speed));
- //float exposure = oldExposure + delta * (unity_DeltaTime.x * speed);
- return exposure;
- }
-
- float4 FragAdaptProgressive(VaryingsDefault i) : SV_Target
- {
- float maxValue = 1.0 / FindMaxHistogramValue();
- float avgLuminance = GetAverageLuminance(maxValue);
- float exposure = GetExposureMultiplier(avgLuminance);
- float prevExposure = tex2D(_MainTex, (0.5).xx);
- exposure = InterpolateExposure(exposure, prevExposure);
- return exposure.xxxx;
- }
-
- float4 FragAdaptFixed(VaryingsDefault i) : SV_Target
- {
- float maxValue = 1.0 / FindMaxHistogramValue();
- float avgLuminance = GetAverageLuminance(maxValue);
- float exposure = GetExposureMultiplier(avgLuminance);
- return exposure.xxxx;
- }
-
- // ---- Editor stuff
- int _DebugWidth;
-
- struct VaryingsEditorHisto
- {
- float4 pos : SV_POSITION;
- float2 uv : TEXCOORD0;
- float maxValue : TEXCOORD1;
- float avgLuminance : TEXCOORD2;
- };
-
- VaryingsEditorHisto VertEditorHisto(AttributesDefault v)
- {
- VaryingsEditorHisto o;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.uv = v.texcoord.xy;
- o.maxValue = 1.0 / FindMaxHistogramValue();
- o.avgLuminance = GetAverageLuminance(o.maxValue);
- return o;
- }
-
- float4 FragEditorHisto(VaryingsEditorHisto i) : SV_Target
- {
- const float3 kRangeColor = float3(0.05, 0.4, 0.6);
- const float3 kAvgColor = float3(0.8, 0.3, 0.05);
-
- float4 color = float4(0.0, 0.0, 0.0, 0.7);
-
- uint ix = (uint)(round(i.uv.x * HISTOGRAM_BINS));
- float bin = saturate(float(_Histogram[ix]) * i.maxValue);
- float fill = step(i.uv.y, bin);
-
- // Min / max brightness markers
- float luminanceMin = GetHistogramBinFromLuminance(_Params.z, _ScaleOffsetRes.xy);
- float luminanceMax = GetHistogramBinFromLuminance(_Params.w, _ScaleOffsetRes.xy);
-
- color.rgb += fill.rrr;
-
- if (i.uv.x > luminanceMin && i.uv.x < luminanceMax)
- {
- color.rgb = fill.rrr * kRangeColor;
- color.rgb += kRangeColor;
- }
-
- // Current average luminance marker
- float luminanceAvg = GetHistogramBinFromLuminance(i.avgLuminance, _ScaleOffsetRes.xy);
- float avgPx = luminanceAvg * _DebugWidth;
-
- if (abs(i.pos.x - avgPx) < 2)
- color.rgb = kAvgColor;
-
- return color;
- }
-
- ENDCG
-
- SubShader
- {
- Cull Off ZWrite Off ZTest Always
-
- Pass
- {
- CGPROGRAM
-
- #pragma vertex VertDefault
- #pragma fragment FragAdaptProgressive
-
- ENDCG
- }
-
- Pass
- {
- CGPROGRAM
-
- #pragma vertex VertDefault
- #pragma fragment FragAdaptFixed
-
- ENDCG
- }
-
- Pass
- {
- CGPROGRAM
-
- #pragma vertex VertEditorHisto
- #pragma fragment FragEditorHisto
-
- ENDCG
- }
- }
- }
|