DLAA.shader 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  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. Shader "Hidden/DLAA" {
  9. Properties {
  10. _MainTex ("Base (RGB)", 2D) = "white" {}
  11. }
  12. CGINCLUDE
  13. #include "UnityCG.cginc"
  14. uniform sampler2D _MainTex;
  15. uniform float4 _MainTex_TexelSize;
  16. struct v2f {
  17. float4 pos : SV_POSITION;
  18. float2 uv : TEXCOORD0;
  19. };
  20. #define LD( o, dx, dy ) o = tex2D( _MainTex, texCoord + float2( dx, dy ) * _MainTex_TexelSize.xy );
  21. float GetIntensity( float3 col )
  22. {
  23. return dot( col, float3( 0.33f, 0.33f, 0.33f ) );
  24. }
  25. float4 highPassPre( float2 texCoord )
  26. {
  27. LD(float4 sCenter, 0.0,0.0)
  28. LD(float4 sUpLeft, -1.0,-1.0)
  29. LD(float4 sUpRight, 1.0,-1.0)
  30. LD(float4 sDownLeft, -1.0,1.0)
  31. LD(float4 sDownRight, 1.0,1.0)
  32. float4 diff = 4.0f * abs( (sUpLeft + sUpRight + sDownLeft + sDownRight) - 4.0f * sCenter );
  33. float edgeMask = GetIntensity(diff.xyz);
  34. return float4(sCenter.rgb, edgeMask);
  35. }
  36. // Softer (5-pixel wide high-pass)
  37. /*
  38. void HighPassEdgeHV (out float4 edge_h, out float4 edge_v, float4 center, float4 w_h, float4 w_v, float2 texCoord) {
  39. edge_h = abs( w_h - 4.0f * center ) / 4.0f;
  40. edge_v = abs( w_v - 4.0f * center ) / 4.0f;
  41. }
  42. // Sharper (3-pixel wide high-pass)
  43. void EdgeHV (out float4 edge_h, out float4 edge_v, float4 center, float2 texCoord) {
  44. float4 left, right, top, bottom;
  45. LD( left, -1, 0 )
  46. LD( right, 1, 0 )
  47. LD( top, 0, -1 )
  48. LD( bottom, 0, 1 )
  49. edge_h = abs( left + right - 2.0f * center ) / 2.0f;
  50. edge_v = abs( top + bottom - 2.0f * center ) / 2.0f;
  51. }
  52. */
  53. float4 edgeDetectAndBlur( float2 texCoord )
  54. {
  55. float lambda = 3.0f;
  56. float epsilon = 0.1f;
  57. //
  58. // Short Edges
  59. //
  60. float4 center, left_01, right_01, top_01, bottom_01;
  61. // sample 5x5 cross
  62. LD( center, 0, 0 )
  63. LD( left_01, -1.5, 0 )
  64. LD( right_01, 1.5, 0 )
  65. LD( top_01, 0,-1.5 )
  66. LD( bottom_01, 0, 1.5 )
  67. float4 w_h = 2.0f * ( left_01 + right_01 );
  68. float4 w_v = 2.0f * ( top_01 + bottom_01 );
  69. // Softer (5-pixel wide high-pass)
  70. float4 edge_h = abs( w_h - 4.0f * center ) / 4.0f;
  71. float4 edge_v = abs( w_v - 4.0f * center ) / 4.0f;
  72. float4 blurred_h = ( w_h + 2.0f * center ) / 6.0f;
  73. float4 blurred_v = ( w_v + 2.0f * center ) / 6.0f;
  74. float edge_h_lum = GetIntensity( edge_h.xyz );
  75. float edge_v_lum = GetIntensity( edge_v.xyz );
  76. float blurred_h_lum = GetIntensity( blurred_h.xyz );
  77. float blurred_v_lum = GetIntensity( blurred_v.xyz );
  78. float edge_mask_h = saturate( ( lambda * edge_h_lum - epsilon ) / blurred_v_lum );
  79. float edge_mask_v = saturate( ( lambda * edge_v_lum - epsilon ) / blurred_h_lum );
  80. float4 clr = center;
  81. clr = lerp( clr, blurred_h, edge_mask_v );
  82. clr = lerp( clr, blurred_v, edge_mask_h ); // blurrier version
  83. //
  84. // Long Edges
  85. //
  86. float4 h0, h1, h2, h3, h4, h5, h6, h7;
  87. float4 v0, v1, v2, v3, v4, v5, v6, v7;
  88. // sample 16x16 cross (sparse-sample on X360, incremental kernel update on SPUs)
  89. 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 )
  90. 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 )
  91. float long_edge_mask_h = ( h0.a + h1.a + h2.a + h3.a + h4.a + h5.a + h6.a + h7.a ) / 8.0f;
  92. float long_edge_mask_v = ( v0.a + v1.a + v2.a + v3.a + v4.a + v5.a + v6.a + v7.a ) / 8.0f;
  93. long_edge_mask_h = saturate( long_edge_mask_h * 2.0f - 1.0f );
  94. long_edge_mask_v = saturate( long_edge_mask_v * 2.0f - 1.0f );
  95. float4 left, right, top, bottom;
  96. LD( left, -1, 0 )
  97. LD( right, 1, 0 )
  98. LD( top, 0, -1 )
  99. LD( bottom, 0, 1 )
  100. if ( long_edge_mask_h > 0 || long_edge_mask_v > 0 ) // faster but less resistant to noise (TFU2 X360)
  101. //if ( abs( long_edge_mask_h - long_edge_mask_v ) > 0.2f ) // resistant to noise (TFU2 SPUs)
  102. {
  103. float4 long_blurred_h = ( h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7 ) / 8.0f;
  104. float4 long_blurred_v = ( v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 ) / 8.0f;
  105. float lb_h_lum = GetIntensity( long_blurred_h.xyz );
  106. float lb_v_lum = GetIntensity( long_blurred_v.xyz );
  107. float center_lum = GetIntensity( center.xyz );
  108. float left_lum = GetIntensity( left.xyz );
  109. float right_lum = GetIntensity( right.xyz );
  110. float top_lum = GetIntensity( top.xyz );
  111. float bottom_lum = GetIntensity( bottom.xyz );
  112. float4 clr_v = center;
  113. float4 clr_h = center;
  114. // we had to hack this because DIV by 0 gives some artefacts on different platforms
  115. float hx = center_lum == top_lum ? 0.0 : saturate( 0 + ( lb_h_lum - top_lum ) / ( center_lum - top_lum ) );
  116. float hy = center_lum == bottom_lum ? 0.0 : saturate( 1 + ( lb_h_lum - center_lum ) / ( center_lum - bottom_lum ) );
  117. float vx = center_lum == left_lum ? 0.0 : saturate( 0 + ( lb_v_lum - left_lum ) / ( center_lum - left_lum ) );
  118. float vy = center_lum == right_lum ? 0.0 : saturate( 1 + ( lb_v_lum - center_lum ) / ( center_lum - right_lum ) );
  119. float4 vhxy = float4( vx, vy, hx, hy );
  120. //vhxy = vhxy == float4( 0, 0, 0, 0 ) ? float4( 1, 1, 1, 1 ) : vhxy;
  121. clr_v = lerp( left , clr_v, vhxy.x );
  122. clr_v = lerp( right , clr_v, vhxy.y );
  123. clr_h = lerp( top , clr_h, vhxy.z );
  124. clr_h = lerp( bottom, clr_h, vhxy.w );
  125. clr = lerp( clr, clr_v, long_edge_mask_v );
  126. clr = lerp( clr, clr_h, long_edge_mask_h );
  127. }
  128. return clr;
  129. }
  130. float4 edgeDetectAndBlurSharper(float2 texCoord)
  131. {
  132. float lambda = 3.0f;
  133. float epsilon = 0.1f;
  134. //
  135. // Short Edges
  136. //
  137. float4 center, left_01, right_01, top_01, bottom_01;
  138. // sample 5x5 cross
  139. LD( center, 0, 0 )
  140. LD( left_01, -1.5, 0 )
  141. LD( right_01, 1.5, 0 )
  142. LD( top_01, 0,-1.5 )
  143. LD( bottom_01, 0, 1.5 )
  144. float4 w_h = 2.0f * ( left_01 + right_01 );
  145. float4 w_v = 2.0f * ( top_01 + bottom_01 );
  146. // Sharper (3-pixel wide high-pass)
  147. float4 left, right, top, bottom;
  148. LD( left, -1, 0 )
  149. LD( right, 1, 0 )
  150. LD( top, 0, -1 )
  151. LD( bottom, 0, 1 )
  152. float4 edge_h = abs( left + right - 2.0f * center ) / 2.0f;
  153. float4 edge_v = abs( top + bottom - 2.0f * center ) / 2.0f;
  154. float4 blurred_h = ( w_h + 2.0f * center ) / 6.0f;
  155. float4 blurred_v = ( w_v + 2.0f * center ) / 6.0f;
  156. float edge_h_lum = GetIntensity( edge_h.xyz );
  157. float edge_v_lum = GetIntensity( edge_v.xyz );
  158. float blurred_h_lum = GetIntensity( blurred_h.xyz );
  159. float blurred_v_lum = GetIntensity( blurred_v.xyz );
  160. float edge_mask_h = saturate( ( lambda * edge_h_lum - epsilon ) / blurred_v_lum );
  161. float edge_mask_v = saturate( ( lambda * edge_v_lum - epsilon ) / blurred_h_lum );
  162. float4 clr = center;
  163. clr = lerp( clr, blurred_h, edge_mask_v );
  164. clr = lerp( clr, blurred_v, edge_mask_h * 0.5f ); // TFU2 uses 1.0f instead of 0.5f
  165. //
  166. // Long Edges
  167. //
  168. float4 h0, h1, h2, h3, h4, h5, h6, h7;
  169. float4 v0, v1, v2, v3, v4, v5, v6, v7;
  170. // sample 16x16 cross (sparse-sample on X360, incremental kernel update on SPUs)
  171. 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 )
  172. 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 )
  173. float long_edge_mask_h = ( h0.a + h1.a + h2.a + h3.a + h4.a + h5.a + h6.a + h7.a ) / 8.0f;
  174. float long_edge_mask_v = ( v0.a + v1.a + v2.a + v3.a + v4.a + v5.a + v6.a + v7.a ) / 8.0f;
  175. long_edge_mask_h = saturate( long_edge_mask_h * 2.0f - 1.0f );
  176. long_edge_mask_v = saturate( long_edge_mask_v * 2.0f - 1.0f );
  177. //if ( long_edge_mask_h > 0 || long_edge_mask_v > 0 ) // faster but less resistant to noise (TFU2 X360)
  178. if ( abs( long_edge_mask_h - long_edge_mask_v ) > 0.2f ) // resistant to noise (TFU2 SPUs)
  179. {
  180. float4 long_blurred_h = ( h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7 ) / 8.0f;
  181. float4 long_blurred_v = ( v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 ) / 8.0f;
  182. float lb_h_lum = GetIntensity( long_blurred_h.xyz );
  183. float lb_v_lum = GetIntensity( long_blurred_v.xyz );
  184. float center_lum = GetIntensity( center.xyz );
  185. float left_lum = GetIntensity( left.xyz );
  186. float right_lum = GetIntensity( right.xyz );
  187. float top_lum = GetIntensity( top.xyz );
  188. float bottom_lum = GetIntensity( bottom.xyz );
  189. float4 clr_v = center;
  190. float4 clr_h = center;
  191. // we had to hack this because DIV by 0 gives some artefacts on different platforms
  192. float hx = center_lum == top_lum ? 0.0 : saturate( 0 + ( lb_h_lum - top_lum ) / ( center_lum - top_lum ) );
  193. float hy = center_lum == bottom_lum ? 0.0 : saturate( 1 + ( lb_h_lum - center_lum ) / ( center_lum - bottom_lum ) );
  194. float vx = center_lum == left_lum ? 0.0 : saturate( 0 + ( lb_v_lum - left_lum ) / ( center_lum - left_lum ) );
  195. float vy = center_lum == right_lum ? 0.0 : saturate( 1 + ( lb_v_lum - center_lum ) / ( center_lum - right_lum ) );
  196. float4 vhxy = float4( vx, vy, hx, hy );
  197. //vhxy = vhxy == float4( 0, 0, 0, 0 ) ? float4( 1, 1, 1, 1 ) : vhxy;
  198. clr_v = lerp( left , clr_v, vhxy.x );
  199. clr_v = lerp( right , clr_v, vhxy.y );
  200. clr_h = lerp( top , clr_h, vhxy.z );
  201. clr_h = lerp( bottom, clr_h, vhxy.w );
  202. clr = lerp( clr, clr_v, long_edge_mask_v );
  203. clr = lerp( clr, clr_h, long_edge_mask_h );
  204. }
  205. return clr;
  206. }
  207. v2f vert( appdata_img v ) {
  208. v2f o;
  209. o.pos = UnityObjectToClipPos (v.vertex);
  210. float2 uv = v.texcoord.xy;
  211. o.uv.xy = uv;
  212. return o;
  213. }
  214. half4 fragFirst (v2f i) : SV_Target {
  215. return highPassPre (i.uv);
  216. }
  217. half4 fragSecond (v2f i) : SV_Target {
  218. return edgeDetectAndBlur( i.uv );
  219. }
  220. half4 fragThird (v2f i) : SV_Target {
  221. return edgeDetectAndBlurSharper( i.uv );
  222. }
  223. ENDCG
  224. SubShader {
  225. Pass {
  226. ZTest Always Cull Off ZWrite Off
  227. CGPROGRAM
  228. #pragma vertex vert
  229. #pragma fragment fragFirst
  230. #pragma exclude_renderers d3d11_9x
  231. ENDCG
  232. }
  233. Pass {
  234. ZTest Always Cull Off ZWrite Off
  235. CGPROGRAM
  236. #pragma vertex vert
  237. #pragma fragment fragSecond
  238. #pragma target 3.0
  239. #pragma exclude_renderers d3d11_9x
  240. ENDCG
  241. }
  242. Pass {
  243. ZTest Always Cull Off ZWrite Off
  244. CGPROGRAM
  245. #pragma vertex vert
  246. #pragma fragment fragThird
  247. #pragma target 3.0
  248. ENDCG
  249. }
  250. }
  251. Fallback off
  252. }