@@ -26,20 +26,163 @@ Shader "Hidden/FXAA" {
2626 return o;
2727 }
2828
29- sampler2D _MainTex;
29+ sampler2D _MainTex, _LuminanceTex ;
3030 float4 _MainTex_TexelSize;
3131
32+ float _ContrastThreshold, _RelativeThreshold, _SubpixelBlending;
33+
3234 ENDCG
3335
36+ // Luminance Pass
37+ Pass {
38+ CGPROGRAM
39+ #pragma vertex vp
40+ #pragma fragment fp
41+
42+ float4 fp (v2f i) : SV_Target {
43+ return LinearRgbToLuminance (saturate (tex2D (_MainTex, i.uv).rgb));
44+ }
45+ ENDCG
46+ }
47+
48+ // Luminance Pass
3449 Pass {
3550 CGPROGRAM
3651 #pragma vertex vp
3752 #pragma fragment fp
3853
54+ #define EDGE_STEP_COUNT 10
55+ #define EDGE_STEPS 1 , 1.5 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 4
56+ #define EDGE_GUESS 8
57+
58+ static const float edgeSteps[EDGE_STEP_COUNT] = { EDGE_STEPS };
59+
3960 float4 fp (v2f i) : SV_Target {
4061 float4 col = tex2D (_MainTex, i.uv);
4162
42- return col;
63+ // Luminance Neighborhood
64+ float m = tex2D (_LuminanceTex, i.uv + float2 (0 , 0 ) * _MainTex_TexelSize.xy);
65+
66+ float n = tex2D (_LuminanceTex, i.uv + float2 (0 , 1 ) * _MainTex_TexelSize.xy);
67+ float e = tex2D (_LuminanceTex, i.uv + float2 (1 , 0 ) * _MainTex_TexelSize.xy);
68+ float s = tex2D (_LuminanceTex, i.uv + float2 (0 , -1 ) * _MainTex_TexelSize.xy);
69+ float w = tex2D (_LuminanceTex, i.uv + float2 (-1 , 0 ) * _MainTex_TexelSize.xy);
70+
71+ float ne = tex2D (_LuminanceTex, i.uv + float2 (1 , 1 ) * _MainTex_TexelSize.xy);
72+ float nw = tex2D (_LuminanceTex, i.uv + float2 (-1 , 1 ) * _MainTex_TexelSize.xy);
73+ float se = tex2D (_LuminanceTex, i.uv + float2 (1 , -1 ) * _MainTex_TexelSize.xy);
74+ float sw = tex2D (_LuminanceTex, i.uv + float2 (-1 , -1 ) * _MainTex_TexelSize.xy);
75+
76+ // Apply Thresholding From Cardinals
77+ float maxL = max (max (max (max (m, n), e), s), w);
78+ float minL = min (min (min (min (m, n), e), s), w);
79+ float contrast = maxL - minL;
80+
81+ if (contrast < max (_ContrastThreshold, _RelativeThreshold * maxL)) return col;
82+
83+ // Determine Blend Factor
84+ float filter = 2 * (n + e + s + w) + ne + nw + se + sw;
85+ filter *= 1.0f / 12.0f ;
86+ filter = abs (filter - m);
87+ filter = saturate (filter / contrast);
88+
89+ float blendFactor = smoothstep (0 , 1 , filter);
90+ blendFactor *= blendFactor * _SubpixelBlending;
91+
92+ // Edge Prediction
93+ float horizontal = abs (n + s - 2 * m) * 2 + abs (ne + se - 2 * e) + abs (nw + sw - 2 * w);
94+ float vertical = abs (e + w - 2 * m) * 2 + abs (ne + nw - 2 * n) + abs (se + sw - 2 * s);
95+ bool isHorizontal = horizontal >= vertical;
96+
97+ float pLuminance = isHorizontal ? n : e;
98+ float nLuminance = isHorizontal ? s : w;
99+ float pGradient = abs (pLuminance - m);
100+ float nGradient = abs (nLuminance - m);
101+
102+ float pixelStep = isHorizontal ? _MainTex_TexelSize.y : _MainTex_TexelSize.x;
103+
104+ float oppositeLuminance = pLuminance;
105+ float gradient = pGradient;
106+
107+ if (pGradient < nGradient) {
108+ pixelStep = -pixelStep;
109+ oppositeLuminance = nLuminance;
110+ gradient = nGradient;
111+ }
112+
113+ float2 uvEdge = i.uv;
114+ float2 edgeStep;
115+ if (isHorizontal) {
116+ uvEdge.y += pixelStep * 0.5f ;
117+ edgeStep = float2 (_MainTex_TexelSize.x, 0 );
118+ } else {
119+ uvEdge.x += pixelStep * 0.5f ;
120+ edgeStep = float2 (0 , _MainTex_TexelSize.y);
121+ }
122+
123+ float edgeLuminance = (m + oppositeLuminance) * 0.5f ;
124+ float gradientThreshold = gradient * 0.25f ;
125+
126+ float2 puv = uvEdge + edgeStep * edgeSteps[0 ];
127+ float pLuminanceDelta = tex2D (_LuminanceTex, puv) - edgeLuminance;
128+ bool pAtEnd = abs (pLuminanceDelta) >= gradientThreshold;
129+
130+ UNITY_UNROLL
131+ for (int j = 1 ; j < EDGE_STEP_COUNT && !pAtEnd; ++j) {
132+ puv += edgeStep * edgeSteps[j];
133+ pLuminanceDelta = tex2D (_LuminanceTex, puv) - edgeLuminance;
134+ pAtEnd = abs (pLuminanceDelta) >= gradientThreshold;
135+ }
136+
137+ if (!pAtEnd)
138+ puv += edgeStep * EDGE_GUESS;
139+
140+ float2 nuv = uvEdge - edgeStep * edgeSteps[0 ];
141+ float nLuminanceDelta = tex2D (_LuminanceTex, nuv) - edgeLuminance;
142+ bool nAtEnd = abs (nLuminanceDelta) >= gradientThreshold;
143+
144+ UNITY_UNROLL
145+ for (int k = 1 ; k < EDGE_STEP_COUNT && !nAtEnd; ++k) {
146+ nuv -= edgeStep * edgeSteps[k];
147+ nLuminanceDelta = tex2D (_LuminanceTex, nuv) - edgeLuminance;
148+ nAtEnd = abs (nLuminanceDelta) >= gradientThreshold;
149+ }
150+
151+ if (!nAtEnd)
152+ nuv -= edgeStep * EDGE_GUESS;
153+
154+
155+ float pDistance, nDistance;
156+ if (isHorizontal) {
157+ pDistance = puv.x - i.uv.x;
158+ nDistance = i.uv.x - nuv.x;
159+ } else {
160+ pDistance = puv.y - i.uv.y;
161+ nDistance = i.uv.y - nuv.y;
162+ }
163+
164+ float shortestDistance = nDistance;
165+ bool deltaSign = nLuminanceDelta >= 0 ;
166+
167+ if (pDistance <= nDistance) {
168+ shortestDistance = pDistance;
169+ deltaSign = pLuminanceDelta >= 0 ;
170+ }
171+
172+ if (deltaSign == (m - edgeLuminance >= 0 )) return col;
173+
174+ float edgeBlendFactor = 0.5f - shortestDistance / (pDistance + nDistance);
175+
176+ float finalBlendFactor = max (blendFactor, edgeBlendFactor);
177+
178+ float2 uv = i.uv;
179+
180+ if (isHorizontal)
181+ uv.y += pixelStep * finalBlendFactor;
182+ else
183+ uv.x += pixelStep * finalBlendFactor;
184+
185+ return tex2Dlod (_MainTex, float4 (uv, 0 , 0 ));
43186 }
44187 ENDCG
45188 }
0 commit comments