1 Shader "Hidden/FXAA Preset 2" {
2 Properties {
3 _MainTex ("Base (RGB)", 2D) = "white" {}
4 }
5
6 SubShader {
7 Pass {
8 ZTest Always Cull Off ZWrite Off
9
10 CGPROGRAM
11 #pragma vertex vert
12 #pragma fragment frag
13 #include "UnityCG.cginc"
14 #pragma target 3.0
15
16 // doesn't make sense to have this on consoles, it'll fallback to FXAA2
17 #pragma exclude_renderers xbox360 ps3 gles
18
19
20 #define FXAA_HLSL_3 1
21 #define FXAA_PRESET 2
22
23
24 // Copyright (c) 2010 NVIDIA Corporation. All rights reserved.
25 //
26 // TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
27 // *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
28 // OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
29 // AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS
30 // BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES
31 // WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
32 // BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS)
33 // ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS
34 // BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
35
36 /*============================================================================
37
38 FXAA
39
40 ============================================================================*/
41
42 /*============================================================================
43 API PORTING
44 ============================================================================*/
45 #ifndef FXAA_GLSL_120
46 #define FXAA_GLSL_120 0
47 #endif
48 #ifndef FXAA_GLSL_130
49 #define FXAA_GLSL_130 0
50 #endif
51 #ifndef FXAA_HLSL_3
52 #define FXAA_HLSL_3 0
53 #endif
54 #ifndef FXAA_HLSL_4
55 #define FXAA_HLSL_4 0
56 #endif
57 /*--------------------------------------------------------------------------*/
58 #if FXAA_GLSL_120
59 // Requires,
60 // #version 120
61 // #extension GL_EXT_gpu_shader4 : enable
62 #define int2 ivec2
63 #define float2 vec2
64 #define float3 vec3
65 #define float4 vec4
66 #define FxaaBool3 bvec3
67 #define FxaaInt2 ivec2
68 #define FxaaFloat2 vec2
69 #define FxaaFloat3 vec3
70 #define FxaaFloat4 vec4
71 #define FxaaBool2Float(a) mix(0.0, 1.0, (a))
72 #define FxaaPow3(x, y) pow(x, y)
73 #define FxaaSel3(f, t, b) mix((f), (t), (b))
74 #define FxaaTex sampler2D
75 #endif
76 /*--------------------------------------------------------------------------*/
77 #if FXAA_GLSL_130
78 // Requires "#version 130" or better
79 #define int2 ivec2
80 #define float2 vec2
81 #define float3 vec3
82 #define float4 vec4
83 #define FxaaBool3 bvec3
84 #define FxaaInt2 ivec2
85 #define FxaaFloat2 vec2
86 #define FxaaFloat3 vec3
87 #define FxaaFloat4 vec4
88 #define FxaaBool2Float(a) mix(0.0, 1.0, (a))
89 #define FxaaPow3(x, y) pow(x, y)
90 #define FxaaSel3(f, t, b) mix((f), (t), (b))
91 #define FxaaTex sampler2D
92 #endif
93 /*--------------------------------------------------------------------------*/
94 #if FXAA_HLSL_3
95 #define int2 float2
96 #define FxaaInt2 float2
97 #define FxaaFloat2 float2
98 #define FxaaFloat3 float3
99 #define FxaaFloat4 float4
100 #define FxaaBool2Float(a) (a)
101 #define FxaaPow3(x, y) pow(x, y)
102 #define FxaaSel3(f, t, b) ((f)*(!b) + (t)*(b))
103 #define FxaaTex sampler2D
104 #endif
105 /*--------------------------------------------------------------------------*/
106 #if FXAA_HLSL_4
107 #define FxaaInt2 int2
108 #define FxaaFloat2 float2
109 #define FxaaFloat3 float3
110 #define FxaaFloat4 float4
111 #define FxaaBool2Float(a) (a)
112 #define FxaaPow3(x, y) pow(x, y)
113 #define FxaaSel3(f, t, b) ((f)*(!b) + (t)*(b))
114 struct FxaaTex { SamplerState smpl; Texture2D tex; };
115 #endif
116 /*--------------------------------------------------------------------------*/
117 #define FxaaToFloat3(a) FxaaFloat3((a), (a), (a))
118 /*--------------------------------------------------------------------------*/
119 float4 FxaaTexLod0(FxaaTex tex, float2 pos) {
120 #if FXAA_GLSL_120
121 return texture2DLod(tex, pos.xy, 0.0);
122 #endif
123 #if FXAA_GLSL_130
124 return textureLod(tex, pos.xy, 0.0);
125 #endif
126 #if FXAA_HLSL_3
127 return tex2Dlod(tex, float4(pos.xy, 0.0, 0.0));
128 #endif
129 #if FXAA_HLSL_4
130 return tex.tex.SampleLevel(tex.smpl, pos.xy, 0.0);
131 #endif
132 }
133 /*--------------------------------------------------------------------------*/
134 float4 FxaaTexGrad(FxaaTex tex, float2 pos, float2 grad) {
135 #if FXAA_GLSL_120
136 return texture2DGrad(tex, pos.xy, grad, grad);
137 #endif
138 #if FXAA_GLSL_130
139 return textureGrad(tex, pos.xy, grad, grad);
140 #endif
141 #if FXAA_HLSL_3
142 return tex2Dgrad(tex, pos.xy, grad, grad);
143 #endif
144 #if FXAA_HLSL_4
145 return tex.tex.SampleGrad(tex.smpl, pos.xy, grad, grad);
146 #endif
147 }
148 /*--------------------------------------------------------------------------*/
149 float4 FxaaTexOff(FxaaTex tex, float2 pos, int2 off, float2 rcpFrame) {
150 #if FXAA_GLSL_120
151 return texture2DLodOffset(tex, pos.xy, 0.0, off.xy);
152 #endif
153 #if FXAA_GLSL_130
154 return textureLodOffset(tex, pos.xy, 0.0, off.xy);
155 #endif
156 #if FXAA_HLSL_3
157 return tex2Dlod(tex, float4(pos.xy + (off * rcpFrame), 0, 0));
158 #endif
159 #if FXAA_HLSL_4
160 return tex.tex.SampleLevel(tex.smpl, pos.xy, 0.0, off.xy);
161 #endif
162 }
163
164 /*============================================================================
165 SRGB KNOBS
166 ------------------------------------------------------------------------------
167 FXAA_SRGB_ROP - Set to 1 when applying FXAA to an sRGB back buffer (DX10/11).
168 This will do the sRGB to linear transform,
169 as ROP will expect linear color from this shader,
170 and this shader works in non-linear color.
171 ============================================================================*/
172 #define FXAA_SRGB_ROP 0
173
174 /*============================================================================
175 DEBUG KNOBS
176 ------------------------------------------------------------------------------
177 All debug knobs draw FXAA-untouched pixels in FXAA computed luma (monochrome).
178
179 FXAA_DEBUG_PASSTHROUGH - Red for pixels which are filtered by FXAA with a
180 yellow tint on sub-pixel aliasing filtered by FXAA.
181 FXAA_DEBUG_HORZVERT - Blue for horizontal edges, gold for vertical edges.
182 FXAA_DEBUG_PAIR - Blue/green for the 2 pixel pair choice.
183 FXAA_DEBUG_NEGPOS - Red/blue for which side of center of span.
184 FXAA_DEBUG_OFFSET - Red/blue for -/+ x, gold/skyblue for -/+ y.
185 ============================================================================*/
186 #ifndef FXAA_DEBUG_PASSTHROUGH
187 #define FXAA_DEBUG_PASSTHROUGH 0
188 #endif
189 #ifndef FXAA_DEBUG_HORZVERT
190 #define FXAA_DEBUG_HORZVERT 0
191 #endif
192 #ifndef FXAA_DEBUG_PAIR
193 #define FXAA_DEBUG_PAIR 0
194 #endif
195 #ifndef FXAA_DEBUG_NEGPOS
196 #define FXAA_DEBUG_NEGPOS 0
197 #endif
198 #ifndef FXAA_DEBUG_OFFSET
199 #define FXAA_DEBUG_OFFSET 0
200 #endif
201 /*--------------------------------------------------------------------------*/
202 #if FXAA_DEBUG_PASSTHROUGH || FXAA_DEBUG_HORZVERT || FXAA_DEBUG_PAIR
203 #define FXAA_DEBUG 1
204 #endif
205 #if FXAA_DEBUG_NEGPOS || FXAA_DEBUG_OFFSET
206 #define FXAA_DEBUG 1
207 #endif
208 #ifndef FXAA_DEBUG
209 #define FXAA_DEBUG 0
210 #endif
211
212 /*============================================================================
213 COMPILE-IN KNOBS
214 ------------------------------------------------------------------------------
215 FXAA_PRESET - Choose compile-in knob preset 0-5.
216 ------------------------------------------------------------------------------
217 FXAA_EDGE_THRESHOLD - The minimum amount of local contrast required
218 to apply algorithm.
219 1.0/3.0 - too little
220 1.0/4.0 - good start
221 1.0/8.0 - applies to more edges
222 1.0/16.0 - overkill
223 ------------------------------------------------------------------------------
224 FXAA_EDGE_THRESHOLD_MIN - Trims the algorithm from processing darks.
225 Perf optimization.
226 1.0/32.0 - visible limit (smaller isn't visible)
227 1.0/16.0 - good compromise
228 1.0/12.0 - upper limit (seeing artifacts)
229 ------------------------------------------------------------------------------
230 FXAA_SEARCH_STEPS - Maximum number of search steps for end of span.
231 ------------------------------------------------------------------------------
232 FXAA_SEARCH_ACCELERATION - How much to accelerate search,
233 1 - no acceleration
234 2 - skip by 2 pixels
235 3 - skip by 3 pixels
236 4 - skip by 4 pixels
237 ------------------------------------------------------------------------------
238 FXAA_SEARCH_THRESHOLD - Controls when to stop searching.
239 1.0/4.0 - seems to be the best quality wise
240 ------------------------------------------------------------------------------
241 FXAA_SUBPIX_FASTER - Turn on lower quality but faster subpix path.
242 Not recomended, but used in preset 0.
243 ------------------------------------------------------------------------------
244 FXAA_SUBPIX - Toggle subpix filtering.
245 0 - turn off
246 1 - turn on
247 2 - turn on full (ignores FXAA_SUBPIX_TRIM and CAP)
248 ------------------------------------------------------------------------------
249 FXAA_SUBPIX_TRIM - Controls sub-pixel aliasing removal.
250 1.0/2.0 - low removal
251 1.0/3.0 - medium removal
252 1.0/4.0 - default removal
253 1.0/8.0 - high removal
254 0.0 - complete removal
255 ------------------------------------------------------------------------------
256 FXAA_SUBPIX_CAP - Insures fine detail is not completely removed.
257 This is important for the transition of sub-pixel detail,
258 like fences and wires.
259 3.0/4.0 - default (medium amount of filtering)
260 7.0/8.0 - high amount of filtering
261 1.0 - no capping of sub-pixel aliasing removal
262 ============================================================================*/
263 #ifndef FXAA_PRESET
264 #define FXAA_PRESET 3
265 #endif
266 /*--------------------------------------------------------------------------*/
267 #if (FXAA_PRESET == 0)
268 #define FXAA_EDGE_THRESHOLD (1.0/4.0)
269 #define FXAA_EDGE_THRESHOLD_MIN (1.0/12.0)
270 #define FXAA_SEARCH_STEPS 2
271 #define FXAA_SEARCH_ACCELERATION 4
272 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
273 #define FXAA_SUBPIX 1
274 #define FXAA_SUBPIX_FASTER 1
275 #define FXAA_SUBPIX_CAP (2.0/3.0)
276 #define FXAA_SUBPIX_TRIM (1.0/4.0)
277 #endif
278 /*--------------------------------------------------------------------------*/
279 #if (FXAA_PRESET == 1)
280 #define FXAA_EDGE_THRESHOLD (1.0/8.0)
281 #define FXAA_EDGE_THRESHOLD_MIN (1.0/16.0)
282 #define FXAA_SEARCH_STEPS 4
283 #define FXAA_SEARCH_ACCELERATION 3
284 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
285 #define FXAA_SUBPIX 1
286 #define FXAA_SUBPIX_FASTER 0
287 #define FXAA_SUBPIX_CAP (3.0/4.0)
288 #define FXAA_SUBPIX_TRIM (1.0/4.0)
289 #endif
290 /*--------------------------------------------------------------------------*/
291 #if (FXAA_PRESET == 2)
292 #define FXAA_EDGE_THRESHOLD (1.0/8.0)
293 #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
294 #define FXAA_SEARCH_STEPS 8
295 #define FXAA_SEARCH_ACCELERATION 2
296 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
297 #define FXAA_SUBPIX 1
298 #define FXAA_SUBPIX_FASTER 0
299 #define FXAA_SUBPIX_CAP (3.0/4.0)
300 #define FXAA_SUBPIX_TRIM (1.0/4.0)
301 #endif
302 /*--------------------------------------------------------------------------*/
303 #if (FXAA_PRESET == 3)
304 #define FXAA_EDGE_THRESHOLD (1.0/8.0)
305 #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
306 #define FXAA_SEARCH_STEPS 16
307 #define FXAA_SEARCH_ACCELERATION 1
308 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
309 #define FXAA_SUBPIX 1
310 #define FXAA_SUBPIX_FASTER 0
311 #define FXAA_SUBPIX_CAP (3.0/4.0)
312 #define FXAA_SUBPIX_TRIM (1.0/4.0)
313 #endif
314 /*--------------------------------------------------------------------------*/
315 #if (FXAA_PRESET == 4)
316 #define FXAA_EDGE_THRESHOLD (1.0/8.0)
317 #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
318 #define FXAA_SEARCH_STEPS 24
319 #define FXAA_SEARCH_ACCELERATION 1
320 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
321 #define FXAA_SUBPIX 1
322 #define FXAA_SUBPIX_FASTER 0
323 #define FXAA_SUBPIX_CAP (3.0/4.0)
324 #define FXAA_SUBPIX_TRIM (1.0/4.0)
325 #endif
326 /*--------------------------------------------------------------------------*/
327 #if (FXAA_PRESET == 5)
328 #define FXAA_EDGE_THRESHOLD (1.0/8.0)
329 #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0)
330 #define FXAA_SEARCH_STEPS 32
331 #define FXAA_SEARCH_ACCELERATION 1
332 #define FXAA_SEARCH_THRESHOLD (1.0/4.0)
333 #define FXAA_SUBPIX 1
334 #define FXAA_SUBPIX_FASTER 0
335 #define FXAA_SUBPIX_CAP (3.0/4.0)
336 #define FXAA_SUBPIX_TRIM (1.0/4.0)
337 #endif
338 /*--------------------------------------------------------------------------*/
339 #define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM))
340
341 /*============================================================================
342 HELPERS
343 ============================================================================*/
344 // Return the luma, the estimation of luminance from rgb inputs.
345 // This approximates luma using one FMA instruction,
346 // skipping normalization and tossing out blue.
347 // FxaaLuma() will range 0.0 to 2.963210702.
348 float FxaaLuma(float3 rgb) {
349 return rgb.y * (0.587/0.299) + rgb.x; }
350 /*--------------------------------------------------------------------------*/
351 float3 FxaaLerp3(float3 a, float3 b, float amountOfA) {
352 return (FxaaToFloat3(-amountOfA) * b) +
353 ((a * FxaaToFloat3(amountOfA)) + b); }
354 /*--------------------------------------------------------------------------*/
355 // Support any extra filtering before returning color.
356 float3 FxaaFilterReturn(float3 rgb) {
357 #if FXAA_SRGB_ROP
358 // Do sRGB encoded value to linear conversion.
359 return FxaaSel3(
360 rgb * FxaaToFloat3(1.0/12.92),
361 FxaaPow3(
362 rgb * FxaaToFloat3(1.0/1.055) + FxaaToFloat3(0.055/1.055),
363 FxaaToFloat3(2.4)),
364 rgb > FxaaToFloat3(0.04045));
365 #else
366 return rgb;
367 #endif
368 }
369
370 /*============================================================================
371 VERTEX SHADER
372 ============================================================================*/
373 float2 FxaaVertexShader(
374 // Both x and y range {-1.0 to 1.0 across screen}.
375 float2 inPos) {
376 float2 pos;
377 pos.xy = (inPos.xy * FxaaFloat2(0.5, 0.5)) + FxaaFloat2(0.5, 0.5);
378 return pos; }
379
380 /*============================================================================
381
382 PIXEL SHADER
383
384 ============================================================================*/
385 float3 FxaaPixelShader(
386 // Output of FxaaVertexShader interpolated across screen.
387 // xy -> actual texture position {0.0 to 1.0}
388 float2 pos,
389 // Input texture.
390 FxaaTex tex,
391 // RCPFRAME SHOULD PIXEL SHADER CONSTANTS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
392 // {1.0/frameWidth, 1.0/frameHeight}
393 float2 rcpFrame) {
394
395 /*----------------------------------------------------------------------------
396 EARLY EXIT IF LOCAL CONTRAST BELOW EDGE DETECT LIMIT
397 ------------------------------------------------------------------------------
398 Majority of pixels of a typical image do not require filtering,
399 often pixels are grouped into blocks which could benefit from early exit
400 right at the beginning of the algorithm.
401 Given the following neighborhood,
402
403 N
404 W M E
405 S
406
407 If the difference in local maximum and minimum luma (contrast "range")
408 is lower than a threshold proportional to the maximum local luma ("rangeMax"),
409 then the shader early exits (no visible aliasing).
410 This threshold is clamped at a minimum value ("FXAA_EDGE_THRESHOLD_MIN")
411 to avoid processing in really dark areas.
412 ----------------------------------------------------------------------------*/
413 float3 rgbN = FxaaTexOff(tex, pos.xy, FxaaInt2( 0,-1), rcpFrame).xyz;
414 float3 rgbW = FxaaTexOff(tex, pos.xy, FxaaInt2(-1, 0), rcpFrame).xyz;
415 float3 rgbM = FxaaTexOff(tex, pos.xy, FxaaInt2( 0, 0), rcpFrame).xyz;
416 float3 rgbE = FxaaTexOff(tex, pos.xy, FxaaInt2( 1, 0), rcpFrame).xyz;
417 float3 rgbS = FxaaTexOff(tex, pos.xy, FxaaInt2( 0, 1), rcpFrame).xyz;
418 float lumaN = FxaaLuma(rgbN);
419 float lumaW = FxaaLuma(rgbW);
420 float lumaM = FxaaLuma(rgbM);
421 float lumaE = FxaaLuma(rgbE);
422 float lumaS = FxaaLuma(rgbS);
423 float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));
424 float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));
425 float range = rangeMax - rangeMin;
426 #if FXAA_DEBUG
427 float lumaO = lumaM / (1.0 + (0.587/0.299));
428 #endif
429 if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD)) {
430 #if FXAA_DEBUG
431 return FxaaFilterReturn(FxaaToFloat3(lumaO));
432 #endif
433 return FxaaFilterReturn(rgbM); }
434 #if FXAA_SUBPIX > 0
435 #if FXAA_SUBPIX_FASTER
436 float3 rgbL = (rgbN + rgbW + rgbE + rgbS + rgbM) *
437 FxaaToFloat3(1.0/5.0);
438 #else
439 float3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS;
440 #endif
441 #endif
442
443 /*----------------------------------------------------------------------------
444 COMPUTE LOWPASS
445 ------------------------------------------------------------------------------
446 FXAA computes a local neighborhood lowpass value as follows,
447
448 (N + W + E + S)/4
449
450 Then uses the ratio of the contrast range of the lowpass
451 and the range found in the early exit check,
452 as a sub-pixel aliasing detection filter.
453 When FXAA detects sub-pixel aliasing (such as single pixel dots),
454 it later blends in "blendL" amount
455 of a lowpass value (computed in the next section) to the final result.
456 ----------------------------------------------------------------------------*/
457 #if FXAA_SUBPIX != 0
458 float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;
459 float rangeL = abs(lumaL - lumaM);
460 #endif
461 #if FXAA_SUBPIX == 1
462 float blendL = max(0.0,
463 (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE;
464 blendL = min(FXAA_SUBPIX_CAP, blendL);
465 #endif
466 #if FXAA_SUBPIX == 2
467 float blendL = rangeL / range;
468 #endif
469 #if FXAA_DEBUG_PASSTHROUGH
470 #if FXAA_SUBPIX == 0
471 float blendL = 0.0;
472 #endif
473 return FxaaFilterReturn(
474 FxaaFloat3(1.0, blendL/FXAA_SUBPIX_CAP, 0.0));
475 #endif
476
477 /*----------------------------------------------------------------------------
478 CHOOSE VERTICAL OR HORIZONTAL SEARCH
479 ------------------------------------------------------------------------------
480 FXAA uses the following local neighborhood,
481
482 NW N NE
483 W M E
484 SW S SE
485
486 To compute an edge amount for both vertical and horizontal directions.
487 Note edge detect filters like Sobel fail on single pixel lines through M.
488 FXAA takes the weighted average magnitude of the high-pass values
489 for rows and columns as an indication of local edge amount.
490
491 A lowpass value for anti-sub-pixel-aliasing is computed as
492 (N+W+E+S+M+NW+NE+SW+SE)/9.
493 This full box pattern has higher quality than other options.
494
495 Note following this block, both vertical and horizontal cases
496 flow in parallel (reusing the horizontal variables).
497 ----------------------------------------------------------------------------*/
498 float3 rgbNW = FxaaTexOff(tex, pos.xy, FxaaInt2(-1,-1), rcpFrame).xyz;
499 float3 rgbNE = FxaaTexOff(tex, pos.xy, FxaaInt2( 1,-1), rcpFrame).xyz;
500 float3 rgbSW = FxaaTexOff(tex, pos.xy, FxaaInt2(-1, 1), rcpFrame).xyz;
501 float3 rgbSE = FxaaTexOff(tex, pos.xy, FxaaInt2( 1, 1), rcpFrame).xyz;
502 #if (FXAA_SUBPIX_FASTER == 0) && (FXAA_SUBPIX > 0)
503 rgbL += (rgbNW + rgbNE + rgbSW + rgbSE);
504 rgbL *= FxaaToFloat3(1.0/9.0);
505 #endif
506 float lumaNW = FxaaLuma(rgbNW);
507 float lumaNE = FxaaLuma(rgbNE);
508 float lumaSW = FxaaLuma(rgbSW);
509 float lumaSE = FxaaLuma(rgbSE);
510 float edgeVert =
511 abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) +
512 abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) +
513 abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE));
514 float edgeHorz =
515 abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) +
516 abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) +
517 abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE));
518 bool horzSpan = edgeHorz >= edgeVert;
519 #if FXAA_DEBUG_HORZVERT
520 if(horzSpan) return FxaaFilterReturn(FxaaFloat3(1.0, 0.75, 0.0));
521 else return FxaaFilterReturn(FxaaFloat3(0.0, 0.50, 1.0));
522 #endif
523 float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;
524 if(!horzSpan) lumaN = lumaW;
525 if(!horzSpan) lumaS = lumaE;
526 float gradientN = abs(lumaN - lumaM);
527 float gradientS = abs(lumaS - lumaM);
528 lumaN = (lumaN + lumaM) * 0.5;
529 lumaS = (lumaS + lumaM) * 0.5;
530
531 /*----------------------------------------------------------------------------
532 CHOOSE SIDE OF PIXEL WHERE GRADIENT IS HIGHEST
533 ------------------------------------------------------------------------------
534 This chooses a pixel pair.
535 For "horzSpan == true" this will be a vertical pair,
536
537 [N] N
538 [M] or [M]
539 S [S]
540
541 Note following this block, both {N,M} and {S,M} cases
542 flow in parallel (reusing the {N,M} variables).
543
544 This pair of image rows or columns is searched below
545 in the positive and negative direction
546 until edge status changes
547 (or the maximum number of search steps is reached).
548 ----------------------------------------------------------------------------*/
549 bool pairN = gradientN >= gradientS;
550 #if FXAA_DEBUG_PAIR
551 if(pairN) return FxaaFilterReturn(FxaaFloat3(0.0, 0.0, 1.0));
552 else return FxaaFilterReturn(FxaaFloat3(0.0, 1.0, 0.0));
553 #endif
554 if(!pairN) lumaN = lumaS;
555 if(!pairN) gradientN = gradientS;
556 if(!pairN) lengthSign *= -1.0;
557 float2 posN;
558 posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);
559 posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);
560
561 /*----------------------------------------------------------------------------
562 CHOOSE SEARCH LIMITING VALUES
563 ------------------------------------------------------------------------------
564 Search limit (+/- gradientN) is a function of local gradient.
565 ----------------------------------------------------------------------------*/
566 gradientN *= FXAA_SEARCH_THRESHOLD;
567
568 /*----------------------------------------------------------------------------
569 SEARCH IN BOTH DIRECTIONS UNTIL FIND LUMA PAIR AVERAGE IS OUT OF RANGE
570 ------------------------------------------------------------------------------
571 This loop searches either in vertical or horizontal directions,
572 and in both the negative and positive direction in parallel.
573 This loop fusion is faster than searching separately.
574
575 The search is accelerated using FXAA_SEARCH_ACCELERATION length box filter
576 via anisotropic filtering with specified texture gradients.
577 ----------------------------------------------------------------------------*/
578 float2 posP = posN;
579 float2 offNP = horzSpan ?
580 FxaaFloat2(rcpFrame.x, 0.0) :
581 FxaaFloat2(0.0f, rcpFrame.y);
582 float lumaEndN = lumaN;
583 float lumaEndP = lumaN;
584 bool doneN = false;
585 bool doneP = false;
586 #if FXAA_SEARCH_ACCELERATION == 1
587 posN += offNP * FxaaFloat2(-1.0, -1.0);
588 posP += offNP * FxaaFloat2( 1.0, 1.0);
589 #endif
590 #if FXAA_SEARCH_ACCELERATION == 2
591 posN += offNP * FxaaFloat2(-1.5, -1.5);
592 posP += offNP * FxaaFloat2( 1.5, 1.5);
593 offNP *= FxaaFloat2(2.0, 2.0);
594 #endif
595 #if FXAA_SEARCH_ACCELERATION == 3
596 posN += offNP * FxaaFloat2(-2.0, -2.0);
597 posP += offNP * FxaaFloat2( 2.0, 2.0);
598 offNP *= FxaaFloat2(3.0, 3.0);
599 #endif
600 #if FXAA_SEARCH_ACCELERATION == 4
601 posN += offNP * FxaaFloat2(-2.5, -2.5);
602 posP += offNP * FxaaFloat2( 2.5, 2.5);
603 offNP *= FxaaFloat2(4.0, 4.0);
604 #endif
605 for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {
606 #if FXAA_SEARCH_ACCELERATION == 1
607 if(!doneN) lumaEndN =
608 FxaaLuma(FxaaTexLod0(tex, posN.xy).xyz);
609 if(!doneP) lumaEndP =
610 FxaaLuma(FxaaTexLod0(tex, posP.xy).xyz);
611 #else
612 if(!doneN) lumaEndN =
613 FxaaLuma(FxaaTexGrad(tex, posN.xy, offNP).xyz);
614 if(!doneP) lumaEndP =
615 FxaaLuma(FxaaTexGrad(tex, posP.xy, offNP).xyz);
616 #endif
617 doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN);
618 doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN);
619 if(doneN && doneP) break;
620 if(!doneN) posN -= offNP;
621 if(!doneP) posP += offNP; }
622
623 /*----------------------------------------------------------------------------
624 HANDLE IF CENTER IS ON POSITIVE OR NEGATIVE SIDE
625 ------------------------------------------------------------------------------
626 FXAA uses the pixel's position in the span
627 in combination with the values (lumaEnd*) at the ends of the span,
628 to determine filtering.
629
630 This step computes which side of the span the pixel is on.
631 On negative side if dstN < dstP,
632
633 posN pos posP
634 |-----------|------|------------------|
635 | | | |
636 |<--dstN--->|<---------dstP---------->|
637 |
638 span center
639
640 ----------------------------------------------------------------------------*/
641 float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;
642 float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;
643 bool directionN = dstN < dstP;
644 #if FXAA_DEBUG_NEGPOS
645 if(directionN) return FxaaFilterReturn(FxaaFloat3(1.0, 0.0, 0.0));
646 else return FxaaFilterReturn(FxaaFloat3(0.0, 0.0, 1.0));
647 #endif
648 lumaEndN = directionN ? lumaEndN : lumaEndP;
649
650 /*----------------------------------------------------------------------------
651 CHECK IF PIXEL IS IN SECTION OF SPAN WHICH GETS NO FILTERING
652 ------------------------------------------------------------------------------
653 If both the pair luma at the end of the span (lumaEndN)
654 and middle pixel luma (lumaM)
655 are on the same side of the middle pair average luma (lumaN),
656 then don't filter.
657
658 Cases,
659
660 (1.) "L",
661
662 lumaM
663 |
664 V XXXXXXXX <- other line averaged
665 XXXXXXX[X]XXXXXXXXXXX <- source pixel line
666 | . |
667 --------------------------
668 [ ]xxxxxx[x]xx[X]XXXXXX <- pair average
669 --------------------------
670 ^ ^ ^ ^
671 | | | |
672 . |<---->|<---------- no filter region
673 . | | |
674 . center | |
675 . | lumaEndN
676 . | .
677 . lumaN .
678 . .
679 |<--- span -->|
680
681
682 (2.) "^" and "-",
683
684 <- other line averaged
685 XXXXX[X]XXX <- source pixel line
686 | | |
687 --------------------------
688 [ ]xxxx[x]xx[ ] <- pair average
689 --------------------------
690 | | |
691 |<--->|<--->|<---------- filter both sides
692
693
694 (3.) "v" and inverse of "-",
695
696 XXXXXX XXXXXXXXX <- other line averaged
697 XXXXXXXXXXX[X]XXXXXXXXXXXX <- source pixel line
698 | | |
699 --------------------------
700 XXXX[X]xxxx[x]xx[X]XXXXXXX <- pair average
701 --------------------------
702 | | |
703 |<--->|<--->|<---------- don't filter both!
704
705
706 Note the "v" case for FXAA requires no filtering.
707 This is because the inverse of the "-" case is the "v".
708 Filtering "v" case turns open spans like this,
709
710 XXXXXXXXX
711
712 Into this (which is not desired),
713
714 x+. .+x
715 XXXXXXXXX
716
717 ----------------------------------------------------------------------------*/
718 if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))
719 lengthSign = 0.0;
720
721 /*----------------------------------------------------------------------------
722 COMPUTE SUB-PIXEL OFFSET AND FILTER SPAN
723 ------------------------------------------------------------------------------
724 FXAA filters using a bilinear texture fetch offset
725 from the middle pixel M towards the center of the pair (NM below).
726 Maximum filtering will be half way between pair.
727 Reminder, at this point in the code,
728 the {N,M} pair is also reused for all cases: {S,M}, {W,M}, and {E,M}.
729
730 +-------+
731 | | 0.5 offset
732 | N | |
733 | | V
734 +-------+....---
735 | |
736 | M...|....---
737 | | ^
738 +-------+ |
739 . . 0.0 offset
740 . S .
741 . .
742 .........
743
744 Position on span is used to compute sub-pixel filter offset using simple ramp,
745
746 posN posP
747 |\ |<------- 0.5 pixel offset into pair pixel
748 | \ |
749 | \ |
750 ---.......|...\..........|<------- 0.25 pixel offset into pair pixel
751 ^ | ^\ |
752 | | | \ |
753 V | | \ |
754 ---.......|===|==========|<------- 0.0 pixel offset (ie M pixel)
755 ^ . | ^ .
756 | . pos | .
757 | . . | .
758 | . . center .
759 | . . .
760 | |<->|<---------.-------- dstN
761 | . . .
762 | . |<-------->|<------- dstP
763 | . .
764 | |<------------>|<------- spanLength
765 |
766 subPixelOffset
767
768 ----------------------------------------------------------------------------*/
769 float spanLength = (dstP + dstN);
770 dstN = directionN ? dstN : dstP;
771 float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign;
772 #if FXAA_DEBUG_OFFSET
773 float ox = horzSpan ? 0.0 : subPixelOffset*2.0/rcpFrame.x;
774 float oy = horzSpan ? subPixelOffset*2.0/rcpFrame.y : 0.0;
775 if(ox < 0.0) return FxaaFilterReturn(
776 FxaaLerp3(FxaaToFloat3(lumaO),
777 FxaaFloat3(1.0, 0.0, 0.0), -ox));
778 if(ox > 0.0) return FxaaFilterReturn(
779 FxaaLerp3(FxaaToFloat3(lumaO),
780 FxaaFloat3(0.0, 0.0, 1.0), ox));
781 if(oy < 0.0) return FxaaFilterReturn(
782 FxaaLerp3(FxaaToFloat3(lumaO),
783 FxaaFloat3(1.0, 0.6, 0.2), -oy));
784 if(oy > 0.0) return FxaaFilterReturn(
785 FxaaLerp3(FxaaToFloat3(lumaO),
786 FxaaFloat3(0.2, 0.6, 1.0), oy));
787 return FxaaFilterReturn(FxaaFloat3(lumaO, lumaO, lumaO));
788 #endif
789 float3 rgbF = FxaaTexLod0(tex, FxaaFloat2(
790 pos.x + (horzSpan ? 0.0 : subPixelOffset),
791 pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz;
792 #if FXAA_SUBPIX == 0
793 return FxaaFilterReturn(rgbF);
794 #else
795 return FxaaFilterReturn(FxaaLerp3(rgbL, rgbF, blendL));
796 #endif
797 }
798
799
800
801 struct v2f {
802 float4 pos : SV_POSITION;
803 float2 uv : TEXCOORD0;
804 };
805
806 v2f vert (appdata_img v)
807 {
808 v2f o;
809 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
810 o.uv = v.texcoord.xy;
811 return o;
812 }
813
814 sampler2D _MainTex;
815 float4 _MainTex_TexelSize;
816
817 float4 frag (v2f i) : SV_Target
818 {
819 return float4(FxaaPixelShader(i.uv.xy, _MainTex, _MainTex_TexelSize.xy).xyz, 0.0f);
820 }
821
822 ENDCG
823 }
824 }
825
826 Fallback "Hidden/FXAA II"
827 }