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