1
2 //
3 // modified and adapted DLAA code based on Dmitry Andreev's
4 // Directionally Localized Anti-Aliasing (DLAA)
5 //
6 // as seen in "The Force Unleashed 2"
7 //
8
9 Shader "Hidden/DLAA" {
10 Properties {
11 _MainTex ("Base (RGB)", 2D) = "white" {}
12 }
13
14 CGINCLUDE
15
16 #include "UnityCG.cginc"
17
18 uniform sampler2D _MainTex;
19 uniform float4 _MainTex_TexelSize;
20
21 struct v2f {
22 float4 pos : SV_POSITION;
23 float2 uv : TEXCOORD0;
24 };
25
26 #define LD( o, dx, dy ) o = tex2D( _MainTex, texCoord + float2( dx, dy ) * _MainTex_TexelSize.xy );
27
28 float GetIntensity( float3 col )
29 {
30 return dot( col, float3( 0.33f, 0.33f, 0.33f ) );
31 }
32
33 float4 highPassPre( float2 texCoord )
34 {
35 LD(float4 sCenter, 0.0,0.0)
36 LD(float4 sUpLeft, -1.0,-1.0)
37 LD(float4 sUpRight, 1.0,-1.0)
38 LD(float4 sDownLeft, -1.0,1.0)
39 LD(float4 sDownRight, 1.0,1.0)
40
41 float4 diff = 4.0f * abs( (sUpLeft + sUpRight + sDownLeft + sDownRight) - 4.0f * sCenter );
42 float edgeMask = GetIntensity(diff.xyz);
43
44 return float4(sCenter.rgb, edgeMask);
45 }
46
47 // Softer (5-pixel wide high-pass)
48 /*
49 void HighPassEdgeHV (out float4 edge_h, out float4 edge_v, float4 center, float4 w_h, float4 w_v, float2 texCoord) {
50 edge_h = abs( w_h - 4.0f * center ) / 4.0f;
51 edge_v = abs( w_v - 4.0f * center ) / 4.0f;
52 }
53
54 // Sharper (3-pixel wide high-pass)
55 void EdgeHV (out float4 edge_h, out float4 edge_v, float4 center, float2 texCoord) {
56 float4 left, right, top, bottom;
57
58 LD( left, -1, 0 )
59 LD( right, 1, 0 )
60 LD( top, 0, -1 )
61 LD( bottom, 0, 1 )
62
63 edge_h = abs( left + right - 2.0f * center ) / 2.0f;
64 edge_v = abs( top + bottom - 2.0f * center ) / 2.0f;
65 }
66 */
67
68 float4 edgeDetectAndBlur( float2 texCoord )
69 {
70 float lambda = 3.0f;
71 float epsilon = 0.1f;
72
73 //
74 // Short Edges
75 //
76
77 float4 center, left_01, right_01, top_01, bottom_01;
78
79 // sample 5x5 cross
80 LD( center, 0, 0 )
81 LD( left_01, -1.5, 0 )
82 LD( right_01, 1.5, 0 )
83 LD( top_01, 0,-1.5 )
84 LD( bottom_01, 0, 1.5 )
85
86
87 float4 w_h = 2.0f * ( left_01 + right_01 );
88 float4 w_v = 2.0f * ( top_01 + bottom_01 );
89
90
91 // Softer (5-pixel wide high-pass)
92 float4 edge_h = abs( w_h - 4.0f * center ) / 4.0f;
93 float4 edge_v = abs( w_v - 4.0f * center ) / 4.0f;
94
95
96 float4 blurred_h = ( w_h + 2.0f * center ) / 6.0f;
97 float4 blurred_v = ( w_v + 2.0f * center ) / 6.0f;
98
99 float edge_h_lum = GetIntensity( edge_h.xyz );
100 float edge_v_lum = GetIntensity( edge_v.xyz );
101 float blurred_h_lum = GetIntensity( blurred_h.xyz );
102 float blurred_v_lum = GetIntensity( blurred_v.xyz );
103
104 float edge_mask_h = saturate( ( lambda * edge_h_lum - epsilon ) / blurred_v_lum );
105 float edge_mask_v = saturate( ( lambda * edge_v_lum - epsilon ) / blurred_h_lum );
106
107 float4 clr = center;
108 clr = lerp( clr, blurred_h, edge_mask_v );
109 clr = lerp( clr, blurred_v, edge_mask_h ); // blurrier version
110
111 //
112 // Long Edges
113 //
114
115 float4 h0, h1, h2, h3, h4, h5, h6, h7;
116 float4 v0, v1, v2, v3, v4, v5, v6, v7;
117
118 // sample 16x16 cross (sparse-sample on X360, incremental kernel update on SPUs)
119 LD( h0, 1.5, 0 ) LD( h1, 3.5, 0 ) LD( h2, 5.5, 0 ) LD( h3, 7.5, 0 ) LD( h4, -1.5,0 ) LD( h5, -3.5,0 ) LD( h6, -5.5,0 ) LD( h7, -7.5,0 )
120 LD( v0, 0, 1.5 ) LD( v1, 0, 3.5 ) LD( v2, 0, 5.5 ) LD( v3, 0, 7.5 ) LD( v4, 0,-1.5 ) LD( v5, 0,-3.5 ) LD( v6, 0,-5.5 ) LD( v7, 0,-7.5 )
121
122 float long_edge_mask_h = ( h0.a + h1.a + h2.a + h3.a + h4.a + h5.a + h6.a + h7.a ) / 8.0f;
123 float long_edge_mask_v = ( v0.a + v1.a + v2.a + v3.a + v4.a + v5.a + v6.a + v7.a ) / 8.0f;
124
125 long_edge_mask_h = saturate( long_edge_mask_h * 2.0f - 1.0f );
126 long_edge_mask_v = saturate( long_edge_mask_v * 2.0f - 1.0f );
127
128 float4 left, right, top, bottom;
129
130 LD( left, -1, 0 )
131 LD( right, 1, 0 )
132 LD( top, 0, -1 )
133 LD( bottom, 0, 1 )
134
135 if ( long_edge_mask_h > 0 || long_edge_mask_v > 0 ) // faster but less resistant to noise (TFU2 X360)
136 //if ( abs( long_edge_mask_h - long_edge_mask_v ) > 0.2f ) // resistant to noise (TFU2 SPUs)
137 {
138 float4 long_blurred_h = ( h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7 ) / 8.0f;
139 float4 long_blurred_v = ( v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 ) / 8.0f;
140
141 float lb_h_lum = GetIntensity( long_blurred_h.xyz );
142 float lb_v_lum = GetIntensity( long_blurred_v.xyz );
143
144 float center_lum = GetIntensity( center.xyz );
145 float left_lum = GetIntensity( left.xyz );
146 float right_lum = GetIntensity( right.xyz );
147 float top_lum = GetIntensity( top.xyz );
148 float bottom_lum = GetIntensity( bottom.xyz );
149
150 float4 clr_v = center;
151 float4 clr_h = center;
152
153 // we had to hack this because DIV by 0 gives some artefacts on different platforms
154 float hx = center_lum == top_lum ? 0.0 : saturate( 0 + ( lb_h_lum - top_lum ) / ( center_lum - top_lum ) );
155 float hy = center_lum == bottom_lum ? 0.0 : saturate( 1 + ( lb_h_lum - center_lum ) / ( center_lum - bottom_lum ) );
156 float vx = center_lum == left_lum ? 0.0 : saturate( 0 + ( lb_v_lum - left_lum ) / ( center_lum - left_lum ) );
157 float vy = center_lum == right_lum ? 0.0 : saturate( 1 + ( lb_v_lum - center_lum ) / ( center_lum - right_lum ) );
158
159 float4 vhxy = float4( vx, vy, hx, hy );
160 //vhxy = vhxy == float4( 0, 0, 0, 0 ) ? float4( 1, 1, 1, 1 ) : vhxy;
161
162 clr_v = lerp( left , clr_v, vhxy.x );
163 clr_v = lerp( right , clr_v, vhxy.y );
164 clr_h = lerp( top , clr_h, vhxy.z );
165 clr_h = lerp( bottom, clr_h, vhxy.w );
166
167 clr = lerp( clr, clr_v, long_edge_mask_v );
168 clr = lerp( clr, clr_h, long_edge_mask_h );
169 }
170
171 return clr;
172 }
173
174 float4 edgeDetectAndBlurSharper(float2 texCoord)
175 {
176 float lambda = 3.0f;
177 float epsilon = 0.1f;
178
179 //
180 // Short Edges
181 //
182
183 float4 center, left_01, right_01, top_01, bottom_01;
184
185 // sample 5x5 cross
186 LD( center, 0, 0 )
187 LD( left_01, -1.5, 0 )
188 LD( right_01, 1.5, 0 )
189 LD( top_01, 0,-1.5 )
190 LD( bottom_01, 0, 1.5 )
191
192
193 float4 w_h = 2.0f * ( left_01 + right_01 );
194 float4 w_v = 2.0f * ( top_01 + bottom_01 );
195
196 // Sharper (3-pixel wide high-pass)
197 float4 left, right, top, bottom;
198
199 LD( left, -1, 0 )
200 LD( right, 1, 0 )
201 LD( top, 0, -1 )
202 LD( bottom, 0, 1 )
203
204 float4 edge_h = abs( left + right - 2.0f * center ) / 2.0f;
205 float4 edge_v = abs( top + bottom - 2.0f * center ) / 2.0f;
206
207 float4 blurred_h = ( w_h + 2.0f * center ) / 6.0f;
208 float4 blurred_v = ( w_v + 2.0f * center ) / 6.0f;
209
210 float edge_h_lum = GetIntensity( edge_h.xyz );
211 float edge_v_lum = GetIntensity( edge_v.xyz );
212 float blurred_h_lum = GetIntensity( blurred_h.xyz );
213 float blurred_v_lum = GetIntensity( blurred_v.xyz );
214
215 float edge_mask_h = saturate( ( lambda * edge_h_lum - epsilon ) / blurred_v_lum );
216 float edge_mask_v = saturate( ( lambda * edge_v_lum - epsilon ) / blurred_h_lum );
217
218 float4 clr = center;
219 clr = lerp( clr, blurred_h, edge_mask_v );
220 clr = lerp( clr, blurred_v, edge_mask_h * 0.5f ); // TFU2 uses 1.0f instead of 0.5f
221
222 //
223 // Long Edges
224 //
225
226 float4 h0, h1, h2, h3, h4, h5, h6, h7;
227 float4 v0, v1, v2, v3, v4, v5, v6, v7;
228
229 // sample 16x16 cross (sparse-sample on X360, incremental kernel update on SPUs)
230 LD( h0, 1.5, 0 ) LD( h1, 3.5, 0 ) LD( h2, 5.5, 0 ) LD( h3, 7.5, 0 ) LD( h4, -1.5,0 ) LD( h5, -3.5,0 ) LD( h6, -5.5,0 ) LD( h7, -7.5,0 )
231 LD( v0, 0, 1.5 ) LD( v1, 0, 3.5 ) LD( v2, 0, 5.5 ) LD( v3, 0, 7.5 ) LD( v4, 0,-1.5 ) LD( v5, 0,-3.5 ) LD( v6, 0,-5.5 ) LD( v7, 0,-7.5 )
232
233 float long_edge_mask_h = ( h0.a + h1.a + h2.a + h3.a + h4.a + h5.a + h6.a + h7.a ) / 8.0f;
234 float long_edge_mask_v = ( v0.a + v1.a + v2.a + v3.a + v4.a + v5.a + v6.a + v7.a ) / 8.0f;
235
236 long_edge_mask_h = saturate( long_edge_mask_h * 2.0f - 1.0f );
237 long_edge_mask_v = saturate( long_edge_mask_v * 2.0f - 1.0f );
238
239 //if ( long_edge_mask_h > 0 || long_edge_mask_v > 0 ) // faster but less resistant to noise (TFU2 X360)
240 if ( abs( long_edge_mask_h - long_edge_mask_v ) > 0.2f ) // resistant to noise (TFU2 SPUs)
241 {
242 float4 long_blurred_h = ( h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7 ) / 8.0f;
243 float4 long_blurred_v = ( v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 ) / 8.0f;
244
245 float lb_h_lum = GetIntensity( long_blurred_h.xyz );
246 float lb_v_lum = GetIntensity( long_blurred_v.xyz );
247
248 float center_lum = GetIntensity( center.xyz );
249 float left_lum = GetIntensity( left.xyz );
250 float right_lum = GetIntensity( right.xyz );
251 float top_lum = GetIntensity( top.xyz );
252 float bottom_lum = GetIntensity( bottom.xyz );
253
254 float4 clr_v = center;
255 float4 clr_h = center;
256
257 // we had to hack this because DIV by 0 gives some artefacts on different platforms
258 float hx = center_lum == top_lum ? 0.0 : saturate( 0 + ( lb_h_lum - top_lum ) / ( center_lum - top_lum ) );
259 float hy = center_lum == bottom_lum ? 0.0 : saturate( 1 + ( lb_h_lum - center_lum ) / ( center_lum - bottom_lum ) );
260 float vx = center_lum == left_lum ? 0.0 : saturate( 0 + ( lb_v_lum - left_lum ) / ( center_lum - left_lum ) );
261 float vy = center_lum == right_lum ? 0.0 : saturate( 1 + ( lb_v_lum - center_lum ) / ( center_lum - right_lum ) );
262
263 float4 vhxy = float4( vx, vy, hx, hy );
264 //vhxy = vhxy == float4( 0, 0, 0, 0 ) ? float4( 1, 1, 1, 1 ) : vhxy;
265
266 clr_v = lerp( left , clr_v, vhxy.x );
267 clr_v = lerp( right , clr_v, vhxy.y );
268 clr_h = lerp( top , clr_h, vhxy.z );
269 clr_h = lerp( bottom, clr_h, vhxy.w );
270
271 clr = lerp( clr, clr_v, long_edge_mask_v );
272 clr = lerp( clr, clr_h, long_edge_mask_h );
273 }
274
275 return clr;
276 }
277
278
279 v2f vert( appdata_img v ) {
280 v2f o;
281 o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
282
283 float2 uv = v.texcoord.xy;
284 o.uv.xy = uv;
285
286 return o;
287 }
288
289 half4 fragFirst (v2f i) : SV_Target {
290 return highPassPre (i.uv);
291 }
292
293 half4 fragSecond (v2f i) : SV_Target {
294 return edgeDetectAndBlur( i.uv );
295 }
296
297 half4 fragThird (v2f i) : SV_Target {
298 return edgeDetectAndBlurSharper( i.uv );
299 }
300
301 ENDCG
302
303 SubShader {
304 Pass {
305 ZTest Always Cull Off ZWrite Off
306
307 CGPROGRAM
308
309 #pragma vertex vert
310 #pragma fragment fragFirst
311 #pragma exclude_renderers d3d11_9x
312
313 ENDCG
314 }
315
316 Pass {
317 ZTest Always Cull Off ZWrite Off
318
319 CGPROGRAM
320
321 #pragma vertex vert
322 #pragma fragment fragSecond
323 #pragma target 3.0
324 #pragma exclude_renderers d3d11_9x
325
326 ENDCG
327 }
328
329 Pass {
330 ZTest Always Cull Off ZWrite Off
331
332 CGPROGRAM
333
334 #pragma vertex vert
335 #pragma fragment fragThird
336 #pragma target 3.0
337
338 ENDCG
339 }
340 }
341
342 Fallback off
343
344 }