FXAAShader.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import {
  2. Vector2
  3. } from 'three';
  4. const FXAAShader = {
  5. name: 'FXAAShader',
  6. uniforms: {
  7. 'tDiffuse': { value: null },
  8. 'resolution': { value: new Vector2( 1 / 1024, 1 / 512 ) }
  9. },
  10. vertexShader: /* glsl */`
  11. varying vec2 vUv;
  12. void main() {
  13. vUv = uv;
  14. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  15. }`,
  16. fragmentShader: /* glsl */`
  17. // FXAA algorithm from NVIDIA, C# implementation by Jasper Flick, GLSL port by Dave Hoskins
  18. // http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
  19. // https://catlikecoding.com/unity/tutorials/advanced-rendering/fxaa/
  20. uniform sampler2D tDiffuse;
  21. uniform vec2 resolution;
  22. varying vec2 vUv;
  23. #define EDGE_STEP_COUNT 6
  24. #define EDGE_GUESS 8.0
  25. #define EDGE_STEPS 1.0, 1.5, 2.0, 2.0, 2.0, 4.0
  26. const float edgeSteps[EDGE_STEP_COUNT] = float[EDGE_STEP_COUNT]( EDGE_STEPS );
  27. float _ContrastThreshold = 0.0312;
  28. float _RelativeThreshold = 0.063;
  29. float _SubpixelBlending = 1.0;
  30. vec4 Sample( sampler2D tex2D, vec2 uv ) {
  31. return texture( tex2D, uv );
  32. }
  33. float SampleLuminance( sampler2D tex2D, vec2 uv ) {
  34. return dot( Sample( tex2D, uv ).rgb, vec3( 0.3, 0.59, 0.11 ) );
  35. }
  36. float SampleLuminance( sampler2D tex2D, vec2 texSize, vec2 uv, float uOffset, float vOffset ) {
  37. uv += texSize * vec2(uOffset, vOffset);
  38. return SampleLuminance(tex2D, uv);
  39. }
  40. struct LuminanceData {
  41. float m, n, e, s, w;
  42. float ne, nw, se, sw;
  43. float highest, lowest, contrast;
  44. };
  45. LuminanceData SampleLuminanceNeighborhood( sampler2D tex2D, vec2 texSize, vec2 uv ) {
  46. LuminanceData l;
  47. l.m = SampleLuminance( tex2D, uv );
  48. l.n = SampleLuminance( tex2D, texSize, uv, 0.0, 1.0 );
  49. l.e = SampleLuminance( tex2D, texSize, uv, 1.0, 0.0 );
  50. l.s = SampleLuminance( tex2D, texSize, uv, 0.0, -1.0 );
  51. l.w = SampleLuminance( tex2D, texSize, uv, -1.0, 0.0 );
  52. l.ne = SampleLuminance( tex2D, texSize, uv, 1.0, 1.0 );
  53. l.nw = SampleLuminance( tex2D, texSize, uv, -1.0, 1.0 );
  54. l.se = SampleLuminance( tex2D, texSize, uv, 1.0, -1.0 );
  55. l.sw = SampleLuminance( tex2D, texSize, uv, -1.0, -1.0 );
  56. l.highest = max( max( max( max( l.n, l.e ), l.s ), l.w ), l.m );
  57. l.lowest = min( min( min( min( l.n, l.e ), l.s ), l.w ), l.m );
  58. l.contrast = l.highest - l.lowest;
  59. return l;
  60. }
  61. bool ShouldSkipPixel( LuminanceData l ) {
  62. float threshold = max( _ContrastThreshold, _RelativeThreshold * l.highest );
  63. return l.contrast < threshold;
  64. }
  65. float DeterminePixelBlendFactor( LuminanceData l ) {
  66. float f = 2.0 * ( l.n + l.e + l.s + l.w );
  67. f += l.ne + l.nw + l.se + l.sw;
  68. f *= 1.0 / 12.0;
  69. f = abs( f - l.m );
  70. f = clamp( f / l.contrast, 0.0, 1.0 );
  71. float blendFactor = smoothstep( 0.0, 1.0, f );
  72. return blendFactor * blendFactor * _SubpixelBlending;
  73. }
  74. struct EdgeData {
  75. bool isHorizontal;
  76. float pixelStep;
  77. float oppositeLuminance, gradient;
  78. };
  79. EdgeData DetermineEdge( vec2 texSize, LuminanceData l ) {
  80. EdgeData e;
  81. float horizontal =
  82. abs( l.n + l.s - 2.0 * l.m ) * 2.0 +
  83. abs( l.ne + l.se - 2.0 * l.e ) +
  84. abs( l.nw + l.sw - 2.0 * l.w );
  85. float vertical =
  86. abs( l.e + l.w - 2.0 * l.m ) * 2.0 +
  87. abs( l.ne + l.nw - 2.0 * l.n ) +
  88. abs( l.se + l.sw - 2.0 * l.s );
  89. e.isHorizontal = horizontal >= vertical;
  90. float pLuminance = e.isHorizontal ? l.n : l.e;
  91. float nLuminance = e.isHorizontal ? l.s : l.w;
  92. float pGradient = abs( pLuminance - l.m );
  93. float nGradient = abs( nLuminance - l.m );
  94. e.pixelStep = e.isHorizontal ? texSize.y : texSize.x;
  95. if (pGradient < nGradient) {
  96. e.pixelStep = -e.pixelStep;
  97. e.oppositeLuminance = nLuminance;
  98. e.gradient = nGradient;
  99. } else {
  100. e.oppositeLuminance = pLuminance;
  101. e.gradient = pGradient;
  102. }
  103. return e;
  104. }
  105. float DetermineEdgeBlendFactor( sampler2D tex2D, vec2 texSize, LuminanceData l, EdgeData e, vec2 uv ) {
  106. vec2 uvEdge = uv;
  107. vec2 edgeStep;
  108. if (e.isHorizontal) {
  109. uvEdge.y += e.pixelStep * 0.5;
  110. edgeStep = vec2( texSize.x, 0.0 );
  111. } else {
  112. uvEdge.x += e.pixelStep * 0.5;
  113. edgeStep = vec2( 0.0, texSize.y );
  114. }
  115. float edgeLuminance = ( l.m + e.oppositeLuminance ) * 0.5;
  116. float gradientThreshold = e.gradient * 0.25;
  117. vec2 puv = uvEdge + edgeStep * edgeSteps[0];
  118. float pLuminanceDelta = SampleLuminance( tex2D, puv ) - edgeLuminance;
  119. bool pAtEnd = abs( pLuminanceDelta ) >= gradientThreshold;
  120. for ( int i = 1; i < EDGE_STEP_COUNT && !pAtEnd; i++ ) {
  121. puv += edgeStep * edgeSteps[i];
  122. pLuminanceDelta = SampleLuminance( tex2D, puv ) - edgeLuminance;
  123. pAtEnd = abs( pLuminanceDelta ) >= gradientThreshold;
  124. }
  125. if ( !pAtEnd ) {
  126. puv += edgeStep * EDGE_GUESS;
  127. }
  128. vec2 nuv = uvEdge - edgeStep * edgeSteps[0];
  129. float nLuminanceDelta = SampleLuminance( tex2D, nuv ) - edgeLuminance;
  130. bool nAtEnd = abs( nLuminanceDelta ) >= gradientThreshold;
  131. for ( int i = 1; i < EDGE_STEP_COUNT && !nAtEnd; i++ ) {
  132. nuv -= edgeStep * edgeSteps[i];
  133. nLuminanceDelta = SampleLuminance( tex2D, nuv ) - edgeLuminance;
  134. nAtEnd = abs( nLuminanceDelta ) >= gradientThreshold;
  135. }
  136. if ( !nAtEnd ) {
  137. nuv -= edgeStep * EDGE_GUESS;
  138. }
  139. float pDistance, nDistance;
  140. if ( e.isHorizontal ) {
  141. pDistance = puv.x - uv.x;
  142. nDistance = uv.x - nuv.x;
  143. } else {
  144. pDistance = puv.y - uv.y;
  145. nDistance = uv.y - nuv.y;
  146. }
  147. float shortestDistance;
  148. bool deltaSign;
  149. if ( pDistance <= nDistance ) {
  150. shortestDistance = pDistance;
  151. deltaSign = pLuminanceDelta >= 0.0;
  152. } else {
  153. shortestDistance = nDistance;
  154. deltaSign = nLuminanceDelta >= 0.0;
  155. }
  156. if ( deltaSign == ( l.m - edgeLuminance >= 0.0 ) ) {
  157. return 0.0;
  158. }
  159. return 0.5 - shortestDistance / ( pDistance + nDistance );
  160. }
  161. vec4 ApplyFXAA( sampler2D tex2D, vec2 texSize, vec2 uv ) {
  162. LuminanceData luminance = SampleLuminanceNeighborhood( tex2D, texSize, uv );
  163. if ( ShouldSkipPixel( luminance ) ) {
  164. return Sample( tex2D, uv );
  165. }
  166. float pixelBlend = DeterminePixelBlendFactor( luminance );
  167. EdgeData edge = DetermineEdge( texSize, luminance );
  168. float edgeBlend = DetermineEdgeBlendFactor( tex2D, texSize, luminance, edge, uv );
  169. float finalBlend = max( pixelBlend, edgeBlend );
  170. if (edge.isHorizontal) {
  171. uv.y += edge.pixelStep * finalBlend;
  172. } else {
  173. uv.x += edge.pixelStep * finalBlend;
  174. }
  175. return Sample( tex2D, uv );
  176. }
  177. void main() {
  178. gl_FragColor = ApplyFXAA( tDiffuse, resolution.xy, vUv );
  179. }`
  180. };
  181. export { FXAAShader };
粤ICP备19079148号