PostFX_MSAA.fx 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /************************************************* *****************************
  2. *
  3. * PostFX_MSAA.fx
  4. *
  5. *
  6. * Copyright (c)2008 ELectronic Arts, Inc.
  7. *
  8. ******************************************************************************/
  9. #include "Common.fxh"
  10. #include "CommonPostFX.fxh"
  11. // Screen info.
  12. float2 ScreenInfo
  13. <
  14. string SasBindAddress = "WW3D.FrameBufferSize";
  15. >;
  16. // Taken from BFME2, can be made dynamic if needed.
  17. #define NClip 30.0f
  18. #define FClip 3800.0f
  19. float4 CameraInfo // camera info ( -f*n/(f-n), f/(f-n), n, 1/(f-n) )
  20. <
  21. string SasBindAddress = "WW3D.AA.CameraInfo";
  22. > = float4( -FClip*NClip/(FClip-NClip), FClip/(FClip-NClip), NClip, 1.0f/(FClip-NClip) );
  23. static const float KernelSize = 0.35f; // anti-alias kernel size
  24. static const float EdgeBarrier = 50.0f; // world space edge detection barrier
  25. #define DEBUG_PSAA 0
  26. // Red = 30% of the luminosity.
  27. // Green = 59% of the luminosity.
  28. // Blue = 11% of the luminosity.
  29. //
  30. // e.g.
  31. //
  32. // RGB color of (100, 150, 200) would compute luminance as:
  33. //
  34. // (100 x 0.3) + (150 x 0.59) + (200 x 0.11) = 140
  35. static const float3 LumVec = float3(0.3f, 0.59f, 0.11f);
  36. static const float MinThreshold = 0.02f;
  37. static const float MaxThreshold = 0.03f;
  38. /*-----------------------------------------------------------------------------
  39. Poisson Distribution Tap Filter
  40. -----------------------------------------------------------------------------*/
  41. #define NumTaps 8
  42. static const float2 PoissonTable[NumTaps] =
  43. {
  44. float2( 0.000000f, 0.000000f ),
  45. float2( 0.527837f,-0.085868f ),
  46. float2(-0.040088f, 0.536087f ),
  47. float2(-0.670445f,-0.179949f ),
  48. float2(-0.419418f,-0.616039f ),
  49. float2( 0.440453f,-0.639399f ),
  50. float2(-0.757088f, 0.349334f ),
  51. float2( 0.574619f, 0.685879f ),
  52. };
  53. static const float BlurThreshold = 0.05f;
  54. // Samplers
  55. SAMPLER_2D_BEGIN(FrameBufferSampler,
  56. string SasBindAddress = "PostEffect.FrameBufferTexture";
  57. int WW3DDynamicSet = DS_CUSTOM_FIRST;
  58. )
  59. AddressU = Clamp;
  60. AddressV = Clamp;
  61. MipFilter = None;
  62. MinFilter = Linear;
  63. MagFilter = Linear;
  64. SAMPLER_2D_END
  65. SAMPLER_2D_BEGIN(DepthBufferSampler,
  66. string SasBindAddress = "PostEffect.DepthBufferTexture";
  67. int WW3DDynamicSet = DS_CUSTOM_FIRST;
  68. )
  69. AddressU = Clamp;
  70. AddressV = Clamp;
  71. MipFilter = None;
  72. MinFilter = Point;
  73. MagFilter = Point;
  74. SAMPLER_2D_END
  75. // ----------------------------------------------------------------------------
  76. struct VSOutputAA
  77. {
  78. float4 Position : POSITION;
  79. float2 TexCoord : TEXCOORD0;
  80. };
  81. struct VSOutputPSAA
  82. {
  83. float4 Position : POSITION;
  84. float2 TexCoord : TEXCOORD0;
  85. float4 TexCoordOffLR : TEXCOORD1;
  86. float4 TexCoordOffUD : TEXCOORD2;
  87. #if DEBUG_PSAA
  88. float4 DebugColor : TEXCOORD3;
  89. float2 DebugThreshold : TEXCOORD4;
  90. #endif
  91. };
  92. /*-----------------------------------------------------------------------------
  93. SampleZDepth
  94. -----------------------------------------------------------------------------*/
  95. float PointSampleZDepth(const float2 texCoord)
  96. {
  97. return 1.0f - tex2D(SAMPLER(DepthBufferSampler), texCoord).r;
  98. }
  99. /*-----------------------------------------------------------------------------
  100. ConvertZToWorldDist
  101. To acuratly control Z blur fall off we should really be working in normalized world space (i.e. a wbuffer).
  102. Convert z value to world distance
  103. W = (-(F*N)/(F-N))/(Z- (F/(F-N))
  104. CameraInfo.x = - f*n/(f-n);
  105. CameraInfo.y = f/(f-n);
  106. CameraInfo.z = n;
  107. CameraInfo.w = 1.0f/(f-n);
  108. input: 0.0->1.0
  109. output: near->far
  110. -----------------------------------------------------------------------------*/
  111. float ConvertZToWorldDist(float zDepth)
  112. {
  113. return CameraInfo.x / (zDepth - CameraInfo.y);
  114. }
  115. // ----------------------------------------------------------------------------
  116. // As above, but does 4 distance conversions at once
  117. float4 ConvertZToWorldDist4(float4 zDepths)
  118. {
  119. return CameraInfo.x / (zDepths - CameraInfo.y);
  120. }
  121. // ----------------------------------------------------------------------------
  122. float4 BlurSample(const float2 texCoord, const float blurAmount, float2 blurOffset)
  123. {
  124. float tapContribution = 1.0f / NumTaps;
  125. // Grab the first sample, at the center of the disc
  126. float4 color = tex2D(SAMPLER(FrameBufferSampler), texCoord);
  127. // If the blur amount is greater than a threshold, then apply the full 8 tap filter.
  128. if( blurAmount >= BlurThreshold )
  129. {
  130. // set up color for accumulation
  131. color *= tapContribution;
  132. // scale the blur offset by the blur amount
  133. blurOffset *= blurAmount;
  134. // Accumulate the rest
  135. for( int i = 1; i < NumTaps; i++ )
  136. {
  137. float4 tapColor = tex2D(SAMPLER(FrameBufferSampler), texCoord + PoissonTable[i] * blurOffset);
  138. color += tapColor * tapContribution;
  139. }
  140. #if 0
  141. // Displays the edges in 'white'.
  142. color = float4( 0.1, 0.0, 0.0, 0.0 );
  143. #endif
  144. }
  145. // Compensate for darkening in Xenon fixed16 HDR render targets
  146. color.xyz = UncompressRenderTargetColor(color.xyz);
  147. // Done!
  148. return color;
  149. }
  150. // ----------------------------------------------------------------------------
  151. float EdgeDetect(const float2 texCoord)
  152. {
  153. float du = 1.0f / ScreenInfo.x;
  154. float dv = 1.0f / ScreenInfo.y;
  155. float4 zsamplesA;
  156. float4 zsamplesB;
  157. // Sample Z-buffer
  158. zsamplesA.x = PointSampleZDepth(texCoord + float2(-du,-dv));
  159. zsamplesA.y = PointSampleZDepth(texCoord + float2( 0,-dv));
  160. zsamplesA.z = PointSampleZDepth(texCoord + float2(+du,-dv));
  161. zsamplesA.w = PointSampleZDepth(texCoord + float2(-du, 0));
  162. zsamplesB.x = PointSampleZDepth(texCoord + float2(+du, 0));
  163. zsamplesB.y = PointSampleZDepth(texCoord + float2(-du,+dv));
  164. zsamplesB.z = PointSampleZDepth(texCoord + float2( 0,+dv));
  165. zsamplesB.w = PointSampleZDepth(texCoord + float2(+du,+dv));
  166. // Convert to world distances
  167. float4 wdepthA = ConvertZToWorldDist4(zsamplesA);
  168. float4 wdepthB = ConvertZToWorldDist4(zsamplesB);
  169. // Sobel edge detection filters
  170. // vertical filter horizontal filter
  171. // [ -1 0 1 ] [ -1 -2 -1 ]
  172. // [ -2 0 2 ] [ 0 0 0 ]
  173. // [ -1 0 1 ] [ 1 2 1 ]
  174. float sobelV = dot(wdepthA, float4(-1, 0, 1, -2)) + dot(wdepthB, float4(2, -1, 0, 1));
  175. float sobelH = dot(wdepthA, float4(-1, -2, -1, 0)) + dot(wdepthB, float4(0, 1, 2, 1));
  176. float2 edge = float2(abs(sobelH), abs(sobelV)) - EdgeBarrier;
  177. edge = step(0, edge);
  178. // blurAmount (0.0 off, 1.0 on)
  179. return max(edge.x, edge.y);
  180. }
  181. // ----------------------------------------------------------------------------
  182. VSOutputAA AntiAliasVS(float2 Position : POSITION, float2 Texcoord : TEXCOORD0)
  183. {
  184. VSOutputAA Out;
  185. Out.Position = float4(Position, 0, 1);
  186. Out.TexCoord = Texcoord;
  187. return Out;
  188. }
  189. // ----------------------------------------------------------------------------
  190. float4 AntiAliasPS(const VSOutputAA In) : COLOR
  191. {
  192. float2 blurOffset = (1.0f / ScreenInfo) * KernelSize;
  193. return BlurSample(In.TexCoord, EdgeDetect(In.TexCoord), blurOffset);
  194. }
  195. // ----------------------------------------------------------------------------
  196. float PerceptualDifferenceLum( float3 a, float3 b )
  197. {
  198. float3 diff = abs( a - b );
  199. return dot( diff, LumVec );
  200. }
  201. // ----------------------------------------------------------------------------
  202. VSOutputPSAA AntiAliasLumVS(float2 Position : POSITION, float2 TexCoord : TEXCOORD0)
  203. {
  204. float4 PSAAOffsets;
  205. #if DEBUG_PSAA
  206. PSAAOffsets.z = 1.0f;
  207. PSAAOffsets.w = MinThreshold * 0.01f + MaxThreshold;
  208. #endif
  209. PSAAOffsets.x = 1.0f / ScreenInfo.x;
  210. PSAAOffsets.y = 1.0f / ScreenInfo.y;
  211. VSOutputPSAA Out;
  212. Out.Position = float4(Position, 0, 1);
  213. Out.TexCoord = TexCoord;
  214. Out.TexCoordOffLR.xy = Out.TexCoord;
  215. Out.TexCoordOffLR.x -= PSAAOffsets.x;
  216. Out.TexCoordOffLR.zw = Out.TexCoord;
  217. Out.TexCoordOffLR.z += PSAAOffsets.x;
  218. Out.TexCoordOffUD.xy = Out.TexCoord;
  219. Out.TexCoordOffUD.y -= PSAAOffsets.y;
  220. Out.TexCoordOffUD.zw = Out.TexCoord;
  221. Out.TexCoordOffUD.w += PSAAOffsets.y;
  222. #if DEBUG_PSAA
  223. Out.DebugColor = PSAAOffsets.z ? float4( 1.0f, 0.0f, 0.0f, -1.0f ) : 0.0f;
  224. Out.DebugThreshold = PSAAOffsets.w;
  225. #endif
  226. return Out;
  227. }
  228. // ----------------------------------------------------------------------------
  229. float4 AntiAliasLumPS(const VSOutputPSAA In) : COLOR
  230. {
  231. float4 col0 = tex2D( SAMPLER(FrameBufferSampler), In.TexCoordOffLR.xy );
  232. float4 col2 = tex2D( SAMPLER(FrameBufferSampler), In.TexCoordOffLR.zw );
  233. float4 col1 = tex2D( SAMPLER(FrameBufferSampler), In.TexCoordOffUD.xy );
  234. float4 col3 = tex2D( SAMPLER(FrameBufferSampler), In.TexCoordOffUD.zw );
  235. float4 col = tex2D( SAMPLER(FrameBufferSampler), In.TexCoord );
  236. float4 colRet = col;
  237. #if DEBUG_PSAA
  238. float MinThreshold = 0.02f;//In.DebugThreshold.x;
  239. float MaxThreshold = 0.03f;//In.DebugThreshold.y;
  240. #endif
  241. float hDiff = PerceptualDifferenceLum( col0.rgb, col2.rgb );
  242. float vDiff = PerceptualDifferenceLum( col1.rgb, col3.rgb );
  243. float maxDiff = max( hDiff, vDiff );
  244. if( maxDiff > MinThreshold )
  245. {
  246. colRet += col0 + col1 + col2 + col3;
  247. colRet *= 0.2;
  248. float filterBlend = saturate( ( maxDiff - MinThreshold ) / ( MaxThreshold - MinThreshold ) );
  249. colRet = lerp( col, colRet, filterBlend );
  250. #if DEBUG_PSAA
  251. if( In.DebugColor.a > 0.0f )
  252. {
  253. colRet = lerp( colRet, In.DebugColor, In.DebugColor.a * filterBlend );
  254. }
  255. #endif
  256. }
  257. #if DEBUG_PSAA
  258. if( In.DebugColor.a < 0.0f )
  259. {
  260. float c0 = dot( col.rgb, LumVec );
  261. float c1 = dot( colRet.rgb, LumVec );
  262. if( c0 < c1 )
  263. colRet = float4( 0.0f, c1 - c0, 0.0f, 1.0f );
  264. else
  265. colRet = float4( c0 - c1, 0.0f, 0.0f, 1.0f );
  266. }
  267. #endif
  268. // Compensate for darkening in Xenon fixed16 HDR render targets
  269. colRet.xyz = UncompressRenderTargetColor( colRet.xyz );
  270. return colRet;
  271. }
  272. // ----------------------------------------------------------------------------
  273. technique AntiAlias
  274. {
  275. pass p0
  276. {
  277. VertexShader = compile VS_3_0 AntiAliasLumVS();
  278. PixelShader = compile PS_3_0 AntiAliasLumPS();
  279. AlphaTestEnable = false;
  280. AlphaBlendEnable = false;
  281. CullMode = none;
  282. ZEnable = false;
  283. ZWriteEnable = false;
  284. ZFunc = Always;
  285. ColorWriteEnable = RED|GREEN|BLUE|ALPHA;
  286. }
  287. }