mirror of
https://github.com/FriendshipIsEpic/FiE-Game.git
synced 2024-11-26 07:18:00 +01:00
218 lines
6.4 KiB
Text
218 lines
6.4 KiB
Text
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
|
|
}
|
|
}
|
|
}
|