SMAA.glsl.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. See https://js.arcgis.com/4.24/esri/copyright.txt for details.
  4. */
  5. import{Float4Uniform as e}from"../views/3d/webgl-engine/core/shaderModules/Float4Uniform.js";import{glsl as o}from"../views/3d/webgl-engine/core/shaderModules/interfaces.js";import{ShaderBuilder as t}from"../views/3d/webgl-engine/core/shaderModules/ShaderBuilder.js";import{Texture2DUniform as r}from"../views/3d/webgl-engine/core/shaderModules/Texture2DUniform.js";import{SMAAOutput as s}from"../views/3d/webgl-engine/lib/SMAATechniqueConfiguration.js";import{VertexAttribute as d}from"../views/3d/webgl-engine/lib/VertexAttribute.js";const a={threshold:.05,localConstrastAdaption:2,maxSearchSteps:8,maxDistanceAreaTex:16};function x(x){const c=new t;return x.output===s.EdgeDetector&&(c.attributes.add(d.POSITION,"vec2"),c.vertex.uniforms.add(new e("resolution")),c.varyings.add("fTexCoord","vec2"),c.varyings.add("fOffset[3]","vec4"),c.vertex.code.add(o`void SMAAEdgeDetectionVS( vec2 texcoord ) {
  6. fOffset[0] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 );
  7. fOffset[1] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 );
  8. fOffset[2] = texcoord.xyxy + resolution.xyxy * vec4( -2.0, 0.0, 0.0, 2.0 );
  9. }
  10. void main() {
  11. fTexCoord = (position + 1.0 ) * 0.5;
  12. gl_Position = vec4(position, 0, 1);
  13. SMAAEdgeDetectionVS( fTexCoord );
  14. }`),c.fragment.uniforms.add(new r("tColor")),c.fragment.code.add(o`
  15. vec4 SMAAColorEdgeDetectionPS( vec2 texcoord, vec4 offset[3], sampler2D colorTex ) {
  16. vec2 threshold = vec2( ${o.float(a.threshold)} );
  17. // Calculate color deltas:
  18. vec4 delta;
  19. vec3 C = texture2D( colorTex, texcoord ).rgb;
  20. vec3 Cleft = texture2D( colorTex, offset[0].xy ).rgb;
  21. vec3 t = abs( C - Cleft );
  22. delta.x = max( max( t.r, t.g ), t.b );
  23. vec3 Ctop = texture2D( colorTex, offset[0].zw ).rgb;
  24. t = abs( C - Ctop );
  25. delta.y = max( max( t.r, t.g ), t.b );
  26. // We do the usual threshold:
  27. vec2 edges = step( threshold, delta.xy );
  28. // Then discard if there is no edge:
  29. if ( dot( edges, vec2( 1.0, 1.0 ) ) == 0.0 )
  30. discard;
  31. // Calculate right and bottom deltas:
  32. vec3 Cright = texture2D( colorTex, offset[1].xy ).rgb;
  33. t = abs( C - Cright );
  34. delta.z = max( max( t.r, t.g ), t.b );
  35. vec3 Cbottom = texture2D( colorTex, offset[1].zw ).rgb;
  36. t = abs( C - Cbottom );
  37. delta.w = max( max( t.r, t.g ), t.b );
  38. // Calculate the maximum delta in the direct neighborhood:
  39. float maxDelta = max( max( max( delta.x, delta.y ), delta.z ), delta.w );
  40. // Calculate left-left and top-top deltas:
  41. vec3 Cleftleft = texture2D( colorTex, offset[2].xy ).rgb;
  42. t = abs( C - Cleftleft );
  43. delta.z = max( max( t.r, t.g ), t.b );
  44. vec3 Ctoptop = texture2D( colorTex, offset[2].zw ).rgb;
  45. t = abs( C - Ctoptop );
  46. delta.w = max( max( t.r, t.g ), t.b );
  47. // Calculate the final maximum delta:
  48. maxDelta = max( max( maxDelta, delta.z ), delta.w );
  49. // Local contrast adaptation in action:
  50. edges.xy *= step( maxDelta, float(${o.float(a.localConstrastAdaption)}) * delta.xy );
  51. return vec4( edges, 0.0, 0.0 );
  52. }
  53. void main() {
  54. gl_FragColor = SMAAColorEdgeDetectionPS( fTexCoord, fOffset, tColor );
  55. }
  56. `)),x.output===s.BlendWeight&&(c.attributes.add(d.POSITION,"vec2"),c.vertex.uniforms.add(new e("resolution")),c.varyings.add("fTexCoord","vec2"),c.varyings.add("fOffset[3]","vec4"),c.varyings.add("fPixCoord","vec2"),c.vertex.code.add(o`
  57. void SMAABlendingWeightCalculationVS( vec2 texcoord ) {
  58. fPixCoord = texcoord * resolution.zw;
  59. fOffset[0] = texcoord.xyxy + resolution.xyxy * vec4( -0.25, 0.125, 1.25, 0.125 );
  60. fOffset[1] = texcoord.xyxy + resolution.xyxy * vec4( -0.125, 0.25, -0.125, -1.25 );
  61. fOffset[2] = vec4( fOffset[0].xz, fOffset[1].yw ) + vec4( -2.0, 2.0, -2.0, 2.0 ) * resolution.xxyy * float( ${o.int(a.maxSearchSteps)} );
  62. }
  63. void main() {
  64. fTexCoord = (position + 1.0 ) * 0.5;
  65. gl_Position = vec4(position, 0, 1);
  66. SMAABlendingWeightCalculationVS( fTexCoord );
  67. }
  68. `),c.fragment.uniforms.add(new r("tEdges")),c.fragment.uniforms.add(new r("tArea")),c.fragment.uniforms.add(new r("tSearch")),c.fragment.uniforms.add(new r("tColor")),c.fragment.uniforms.add(new e("resolution")),c.fragment.code.add(o`
  69. #define SMAA_AREATEX_PIXEL_SIZE ( 1.0 / vec2( 160.0, 560.0 ) )
  70. #define SMAA_AREATEX_SUBTEX_SIZE ( 1.0 / 7.0 )
  71. vec4 SMAASampleLevelZeroOffset(sampler2D texture, vec2 coord, vec2 offset) {
  72. return texture2D(texture, coord + offset.x * resolution.xy, 0.0);
  73. }
  74. vec2 round( vec2 x ) {
  75. return sign( x ) * floor( abs( x ) + 0.5 );
  76. }
  77. float SMAASearchLength( sampler2D searchTex, vec2 e, float bias, float scale ) {
  78. e.r = bias + e.r * scale;
  79. return 255.0 * texture2D( searchTex, e, 0.0 ).r;
  80. }
  81. float SMAASearchXLeft( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
  82. vec2 e = vec2( 0.0, 1.0 );
  83. for ( int i = 0; i < ${o.int(a.maxSearchSteps)}; i ++ ) {
  84. e = texture2D( edgesTex, texcoord, 0.0 ).rg;
  85. texcoord -= vec2( 2.0, 0.0 ) * resolution.xy;
  86. if ( ! ( texcoord.x > end && e.g > 0.8281 && e.r == 0.0 ) ) break;
  87. }
  88. texcoord.x += 0.25 * resolution.x;
  89. texcoord.x += resolution.x;
  90. texcoord.x += 2.0 * resolution.x;
  91. texcoord.x -= resolution.x * SMAASearchLength(searchTex, e, 0.0, 0.5);
  92. return texcoord.x;
  93. }
  94. float SMAASearchXRight( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
  95. vec2 e = vec2( 0.0, 1.0 );
  96. for ( int i = 0; i < ${o.int(a.maxSearchSteps)}; i ++ ) {
  97. e = texture2D( edgesTex, texcoord, 0.0 ).rg;
  98. texcoord += vec2( 2.0, 0.0 ) * resolution.xy;
  99. if ( ! ( texcoord.x < end && e.g > 0.8281 && e.r == 0.0 ) ) break;
  100. }
  101. texcoord.x -= 0.25 * resolution.x;
  102. texcoord.x -= resolution.x;
  103. texcoord.x -= 2.0 * resolution.x;
  104. texcoord.x += resolution.x * SMAASearchLength( searchTex, e, 0.5, 0.5 );
  105. return texcoord.x;
  106. }
  107. float SMAASearchYUp( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
  108. vec2 e = vec2( 1.0, 0.0 );
  109. for ( int i = 0; i < ${o.int(a.maxSearchSteps)}; i ++ ) {
  110. e = texture2D( edgesTex, texcoord, 0.0 ).rg;
  111. texcoord += vec2( 0.0, 2.0 ) * resolution.xy;
  112. if ( ! ( texcoord.y > end && e.r > 0.8281 && e.g == 0.0 ) ) break;
  113. }
  114. texcoord.y -= 0.25 * resolution.y;
  115. texcoord.y -= resolution.y;
  116. texcoord.y -= 2.0 * resolution.y;
  117. texcoord.y += resolution.y * SMAASearchLength( searchTex, e.gr, 0.0, 0.5 );
  118. return texcoord.y;
  119. }
  120. float SMAASearchYDown( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {
  121. vec2 e = vec2( 1.0, 0.0 );
  122. for ( int i = 0; i < ${o.int(a.maxSearchSteps)}; i ++ ) {
  123. e = texture2D( edgesTex, texcoord, 0.0 ).rg;
  124. texcoord -= vec2( 0.0, 2.0 ) * resolution.xy;
  125. if ( ! ( texcoord.y < end && e.r > 0.8281 && e.g == 0.0 ) ) break;
  126. }
  127. texcoord.y += 0.25 * resolution.y;
  128. texcoord.y += resolution.y;
  129. texcoord.y += 2.0 * resolution.y;
  130. texcoord.y -= resolution.y * SMAASearchLength( searchTex, e.gr, 0.5, 0.5 );
  131. return texcoord.y;
  132. }
  133. vec2 SMAAArea( sampler2D areaTex, vec2 dist, float e1, float e2, float offset ) {
  134. vec2 texcoord = float( ${o.int(a.maxDistanceAreaTex)} ) * round( 4.0 * vec2( e1, e2 ) ) + dist;
  135. texcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + ( 0.5 * SMAA_AREATEX_PIXEL_SIZE );
  136. texcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;
  137. return texture2D( areaTex, texcoord, 0.0 ).rg;
  138. }
  139. vec4 SMAABlendingWeightCalculationPS( vec2 texcoord, vec2 pixcoord, vec4 offset[ 3 ], sampler2D edgesTex, sampler2D areaTex, sampler2D searchTex, ivec4 subsampleIndices ) {
  140. vec4 weights = vec4( 0.0, 0.0, 0.0, 0.0 );
  141. vec2 e = texture2D( edgesTex, texcoord ).rg;
  142. if ( e.g > 0.0 ) {
  143. vec2 d;
  144. vec2 coords;
  145. coords.x = SMAASearchXLeft( edgesTex, searchTex, offset[ 0 ].xy, offset[ 2 ].x );
  146. coords.y = offset[ 1 ].y;
  147. d.x = coords.x;
  148. float e1 = texture2D( edgesTex, coords, 0.0 ).r;
  149. coords.x = SMAASearchXRight( edgesTex, searchTex, offset[ 0 ].zw, offset[ 2 ].y );
  150. d.y = coords.x;
  151. d = d * resolution.z - pixcoord.x;
  152. vec2 sqrt_d = sqrt( abs( d ) );
  153. coords.y -= 1.0 * resolution.y;
  154. float e2 = SMAASampleLevelZeroOffset( edgesTex, coords, vec2( 1.0, 0.0 ) ).r;
  155. weights.rg = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.y ) );
  156. }
  157. if ( e.r > 0.0 ) {
  158. vec2 d;
  159. vec2 coords;
  160. coords.y = SMAASearchYUp( edgesTex, searchTex, offset[ 1 ].xy, offset[ 2 ].z );
  161. coords.x = offset[ 0 ].x;
  162. d.x = coords.y;
  163. float e1 = texture2D( edgesTex, coords, 0.0 ).g;
  164. coords.y = SMAASearchYDown( edgesTex, searchTex, offset[ 1 ].zw, offset[ 2 ].w );
  165. d.y = coords.y;
  166. d = d * resolution.w - pixcoord.y;
  167. vec2 sqrt_d = sqrt( abs( d ) );
  168. coords.y -= 1.0 * resolution.y;
  169. float e2 = SMAASampleLevelZeroOffset( edgesTex, coords, vec2( 0.0, 1.0 ) ).g;
  170. weights.ba = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.x ) );
  171. // for some reason the following lines are necessary to prevent
  172. // texture lookup precision issues on some Intel integrated graphics chips
  173. vec4 dbg = (offset[ 0 ]+offset[ 1 ]+offset[ 2 ] + coords.xyyx);
  174. weights.r += 0.00000001 * dot(vec4(0,1,0,1),dbg);
  175. }
  176. return weights;
  177. }
  178. void main() {
  179. gl_FragColor = SMAABlendingWeightCalculationPS( fTexCoord, fPixCoord, fOffset, tEdges, tArea, tSearch, ivec4( 0.0 ) );
  180. }
  181. `)),x.output===s.Blur&&(c.attributes.add(d.POSITION,"vec2"),c.vertex.uniforms.add(new e("resolution")),c.varyings.add("fTexCoord","vec2"),c.varyings.add("fOffset[2]","vec4"),c.vertex.code.add(o`void SMAANeighborhoodBlendingVS( vec2 texcoord ) {
  182. fOffset[0] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 );
  183. fOffset[1] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 );
  184. }
  185. void main() {
  186. fTexCoord = (position + 1.0 ) * 0.5;
  187. gl_Position = vec4(position, 0, 1);
  188. SMAANeighborhoodBlendingVS(fTexCoord);
  189. }`),c.fragment.uniforms.add(new r("tBlendWeights")),c.fragment.uniforms.add(new r("tColor")),c.fragment.uniforms.add(new e("resolution")),c.fragment.code.add(o`vec4 SMAANeighborhoodBlendingPS( vec2 texcoord, vec4 offset[ 2 ], sampler2D colorTex, sampler2D blendTex ) {
  190. vec4 a;
  191. a.xz = texture2D( blendTex, texcoord ).xz;
  192. a.y = texture2D( blendTex, offset[ 1 ].zw ).g;
  193. a.w = texture2D( blendTex, offset[ 1 ].xy ).a;
  194. if ( dot(a, vec4( 1.0, 1.0, 1.0, 1.0 )) < 1e-5 ) {
  195. return texture2D( colorTex, texcoord, 0.0 );
  196. } else {
  197. vec2 offset;
  198. offset.x = a.a > a.b ? a.a : -a.b;
  199. offset.y = a.g > a.r ? -a.g : a.r;
  200. if ( abs( offset.x ) > abs( offset.y )) {
  201. offset.y = 0.0;
  202. } else {
  203. offset.x = 0.0;
  204. }
  205. vec4 C = texture2D( colorTex, texcoord, 0.0 );
  206. texcoord += sign( offset ) * resolution.xy;
  207. vec4 Cop = texture2D( colorTex, texcoord, 0.0 );
  208. float s = abs( offset.x ) > abs( offset.y ) ? abs( offset.x ) : abs( offset.y );
  209. vec4 mixed = mix(C, Cop, s);
  210. return mixed;
  211. }
  212. }
  213. void main() {
  214. gl_FragColor = SMAANeighborhoodBlendingPS( fTexCoord, fOffset, tColor, tBlendWeights );
  215. }`)),c}const c=Object.freeze(Object.defineProperty({__proto__:null,build:x},Symbol.toStringTag,{value:"Module"}));export{c as S,x as b};