FXAAShader.js 6.6 KB

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