HUDMaterial.glsl.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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{isSome as e}from"../core/maybe.js";import{a as o,c as i}from"./vec2.js";import{O as r,a as l}from"./vec2f64.js";import{Z as t}from"./vec4f64.js";import{DEFAULT_TEX_SIZE as a}from"../views/3d/layers/graphics/sdfPrimitives.js";import{ShaderOutput as s}from"../views/3d/webgl-engine/core/shaderLibrary/ShaderOutputOptions.js";import{SliceDraw as n}from"../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl.js";import{AlignPixel as c}from"../views/3d/webgl-engine/core/shaderLibrary/hud/AlignPixel.glsl.js";import{HUD as d}from"../views/3d/webgl-engine/core/shaderLibrary/hud/HUD.glsl.js";import{HUDOcclusionPass as u}from"../views/3d/webgl-engine/core/shaderLibrary/hud/HUDOcclusionPass.glsl.js";import{OutputHighlight as p}from"../views/3d/webgl-engine/core/shaderLibrary/output/OutputHighlight.glsl.js";import{VisualVariables as v}from"../views/3d/webgl-engine/core/shaderLibrary/shading/VisualVariables.glsl.js";import{symbolAlphaCutoff as g,defaultMaskAlphaCutoff as f}from"../views/3d/webgl-engine/core/shaderLibrary/util/AlphaCutoff.js";import{ColorConversion as m}from"../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl.js";import{RgbaFloatEncoding as b}from"../views/3d/webgl-engine/core/shaderLibrary/util/RgbaFloatEncoding.glsl.js";import{ScreenSizePerspective as h,addScreenSizePerspective as w,addScreenSizePerspectiveAlignment as x}from"../views/3d/webgl-engine/core/shaderLibrary/util/ScreenSizePerspective.glsl.js";import{Float2PassUniform as C}from"../views/3d/webgl-engine/core/shaderModules/Float2PassUniform.js";import{Float4PassUniform as P}from"../views/3d/webgl-engine/core/shaderModules/Float4PassUniform.js";import{Float4sPassUniform as S}from"../views/3d/webgl-engine/core/shaderModules/Float4sPassUniform.js";import{FloatPassUniform as j}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{FloatsPassUniform as z}from"../views/3d/webgl-engine/core/shaderModules/FloatsPassUniform.js";import{glsl as y}from"../views/3d/webgl-engine/core/shaderModules/interfaces.js";import{ShaderBuilder as F}from"../views/3d/webgl-engine/core/shaderModules/ShaderBuilder.js";import{Texture2DPassUniform as O}from"../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform.js";import{TransparencyPassType as A}from"../views/3d/webgl-engine/lib/basicInterfaces.js";import{VertexAttribute as $}from"../views/3d/webgl-engine/lib/VertexAttribute.js";import{vvColorNumber as D}from"../views/3d/webgl-engine/materials/VisualVariablePassParameters.js";function B(i){const l=new F,B=i.signedDistanceFieldEnabled;if(l.include(c),l.include(d,i),l.include(n,i),i.output===s.Occlusion)return l.include(u,i),l;const{vertex:H,fragment:V}=l;l.include(h),V.include(b),V.include(m),l.include(v,i),l.varyings.add("vcolor","vec4"),l.varyings.add("vtc","vec2"),l.varyings.add("vsize","vec2"),i.binaryHighlightOcclusionEnabled&&l.varyings.add("voccluded","float"),H.uniforms.add([new P("viewport",((e,o)=>o.camera.fullViewport)),new C("screenOffset",((e,i)=>o(U,2*e.screenOffset[0]*i.camera.pixelRatio,2*e.screenOffset[1]*i.camera.pixelRatio))),new C("anchorPosition",(e=>L(e))),new P("materialColor",(e=>e.color)),new j("pixelRatio",((e,o)=>o.camera.pixelRatio))]),B&&(H.uniforms.add(new P("outlineColor",(e=>e.outlineColor))),V.uniforms.add([new P("outlineColor",(e=>_(e)?e.outlineColor:t)),new j("outlineSize",(e=>_(e)?e.outlineSize:0))])),i.hasScreenSizePerspective&&(w(H),x(H)),(i.debugDrawLabelBorder||i.binaryHighlightOcclusionEnabled)&&l.varyings.add("debugBorderCoords","vec4"),l.attributes.add($.UV0,"vec2"),l.attributes.add($.COLOR,"vec4"),l.attributes.add($.SIZE,"vec2"),l.attributes.add($.AUXPOS2,"vec4"),H.code.add(y`
  6. void main(void) {
  7. ProjectHUDAux projectAux;
  8. vec4 posProj = projectPositionHUD(projectAux);
  9. if (rejectBySlice(projectAux.posModel)) {
  10. // Project outside of clip plane
  11. gl_Position = vec4(1e038, 1e038, 1e038, 1.0);
  12. return;
  13. }
  14. vec2 inputSize;
  15. ${i.hasScreenSizePerspective?y`
  16. inputSize = screenSizePerspectiveScaleVec2(size, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspective);
  17. vec2 screenOffsetScaled = screenSizePerspectiveScaleVec2(screenOffset, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspectiveAlignment);
  18. `:y`
  19. inputSize = size;
  20. vec2 screenOffsetScaled = screenOffset;`}
  21. ${i.vvSize?"inputSize *= vvScale(auxpos2).xx;":""}
  22. vec2 combinedSize = inputSize * pixelRatio;
  23. vec4 quadOffset = vec4(0.0);
  24. ${i.occlusionTestEnabled||i.binaryHighlightOcclusionEnabled?"bool visible = testVisibilityHUD(posProj);":""}
  25. ${i.binaryHighlightOcclusionEnabled?"voccluded = visible ? 0.0 : 1.0;":""}
  26. `);const E=y`vec2 uv01 = floor(uv0);
  27. vec2 uv = uv0 - uv01;
  28. quadOffset.xy = ((uv01 - anchorPosition) * 2.0 * combinedSize + screenOffsetScaled) / viewport.zw * posProj.w;`,T=i.pixelSnappingEnabled?B?y`posProj = alignToPixelOrigin(posProj, viewport.zw) + quadOffset;`:y`posProj += quadOffset;
  29. if (inputSize.x == size.x) {
  30. posProj = alignToPixelOrigin(posProj, viewport.zw);
  31. }`:y`posProj += quadOffset;`;i.vvColor&&H.uniforms.add([new S("vvColorColors",(e=>e.vvColorColors),D),new z("vvColorValues",(e=>e.vvColorValues),D)]),H.uniforms.add(new C("textureCoordinateScaleFactor",(o=>e(o.texture)&&e(o.texture.descriptor.textureCoordinateScaleFactor)?o.texture.descriptor.textureCoordinateScaleFactor:r))),H.code.add(y`
  32. ${i.occlusionTestEnabled?"if (visible) {":""}
  33. ${E}
  34. ${i.vvColor?"vcolor = vvGetColor(auxpos2, vvColorValues, vvColorColors) * materialColor;":"vcolor = color / 255.0 * materialColor;"}
  35. bool alphaDiscard = vcolor.a < ${y.float(g)};
  36. ${B?`alphaDiscard = alphaDiscard && outlineColor.a < ${y.float(g)};`:""}
  37. if (alphaDiscard) {
  38. // "early discard" if both symbol color (= fill) and outline color (if applicable) are transparent
  39. gl_Position = vec4(1e38, 1e38, 1e38, 1.0);
  40. return;
  41. } else {
  42. ${T}
  43. gl_Position = posProj;
  44. }
  45. vtc = uv * textureCoordinateScaleFactor;
  46. ${i.debugDrawLabelBorder?"debugBorderCoords = vec4(uv01, 1.5 / combinedSize);":""}
  47. vsize = inputSize;
  48. ${i.occlusionTestEnabled?y`} else { vtc = vec2(0.0);
  49. ${i.debugDrawLabelBorder?"debugBorderCoords = vec4(0.5, 0.5, 1.5 / combinedSize);}":"}"}`:""}
  50. }
  51. `),V.uniforms.add(new O("tex",(e=>e.texture)));const M=i.debugDrawLabelBorder?y`(isBorder > 0.0 ? 0.0 : ${y.float(f)})`:y.float(f),R=y`
  52. ${i.debugDrawLabelBorder?y`
  53. float isBorder = float(any(lessThan(debugBorderCoords.xy, debugBorderCoords.zw)) || any(greaterThan(debugBorderCoords.xy, 1.0 - debugBorderCoords.zw)));`:""}
  54. ${B?y`
  55. vec4 fillPixelColor = vcolor;
  56. // Attempt to sample texel centers to avoid that thin cross outlines
  57. // disappear with large symbol sizes.
  58. // see: https://devtopia.esri.com/WebGIS/arcgis-js-api/issues/7058#issuecomment-603041
  59. const float txSize = ${y.float(a)};
  60. const float texelSize = 1.0 / txSize;
  61. // Calculate how much we have to add/subtract to/from each texel to reach the size of an onscreen pixel
  62. vec2 scaleFactor = (vsize - txSize) * texelSize;
  63. vec2 samplePos = vtc + (vec2(1.0, -1.0) * texelSize) * scaleFactor;
  64. // Get distance and map it into [-0.5, 0.5]
  65. float d = rgba2float(texture2D(tex, samplePos)) - 0.5;
  66. // Distance in output units (i.e. pixels)
  67. float dist = d * vsize.x;
  68. // Create smooth transition from the icon into its outline
  69. float fillAlphaFactor = clamp(0.5 - dist, 0.0, 1.0);
  70. fillPixelColor.a *= fillAlphaFactor;
  71. if (outlineSize > 0.25) {
  72. vec4 outlinePixelColor = outlineColor;
  73. float clampedOutlineSize = min(outlineSize, 0.5*vsize.x);
  74. // Create smooth transition around outline
  75. float outlineAlphaFactor = clamp(0.5 - (abs(dist) - 0.5*clampedOutlineSize), 0.0, 1.0);
  76. outlinePixelColor.a *= outlineAlphaFactor;
  77. if (
  78. outlineAlphaFactor + fillAlphaFactor < ${M} ||
  79. fillPixelColor.a + outlinePixelColor.a < ${y.float(g)}
  80. ) {
  81. discard;
  82. }
  83. // perform un-premultiplied over operator (see https://en.wikipedia.org/wiki/Alpha_compositing#Description)
  84. float compositeAlpha = outlinePixelColor.a + fillPixelColor.a * (1.0 - outlinePixelColor.a);
  85. vec3 compositeColor = vec3(outlinePixelColor) * outlinePixelColor.a +
  86. vec3(fillPixelColor) * fillPixelColor.a * (1.0 - outlinePixelColor.a);
  87. gl_FragColor = vec4(compositeColor, compositeAlpha);
  88. } else {
  89. if (fillAlphaFactor < ${M}) {
  90. discard;
  91. }
  92. gl_FragColor = premultiplyAlpha(fillPixelColor);
  93. }
  94. // visualize SDF:
  95. // gl_FragColor = vec4(clamp(-dist/vsize.x*2.0, 0.0, 1.0), clamp(dist/vsize.x*2.0, 0.0, 1.0), 0.0, 1.0);
  96. `:y`
  97. vec4 texColor = texture2D(tex, vtc, -0.5);
  98. if (texColor.a < ${M}) {
  99. discard;
  100. }
  101. gl_FragColor = texColor * premultiplyAlpha(vcolor);
  102. `}
  103. // Draw debug border with transparency, so that original texels along border are still partially visible
  104. ${i.debugDrawLabelBorder?y`gl_FragColor = mix(gl_FragColor, vec4(1.0, 0.0, 1.0, 1.0), isBorder * 0.5);`:""}
  105. `;return i.output===s.Alpha&&V.code.add(y`
  106. void main() {
  107. ${R}
  108. gl_FragColor = vec4(gl_FragColor.a);
  109. }
  110. `),i.output===s.Color&&V.code.add(y`
  111. void main() {
  112. ${R}
  113. ${i.transparencyPassType===A.FrontFace?"gl_FragColor.rgb /= gl_FragColor.a;":""}
  114. }
  115. `),i.output===s.Highlight&&(l.include(p),V.code.add(y`
  116. void main() {
  117. ${R}
  118. ${i.binaryHighlightOcclusionEnabled?y`
  119. if (voccluded == 1.0) {
  120. gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  121. } else {
  122. gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
  123. }`:"outputHighlight();"}
  124. }
  125. `)),l}function _(e){return e.outlineColor[3]>0&&e.outlineSize>0}function L(e,o=U){return e.textureIsSignedDistanceField?H(e.anchorPosition,e.distanceFieldBoundingBox,o):i(o,e.anchorPosition),o}function H(i,r,l){e(r)?o(l,i[0]*(r[2]-r[0])+r[0],i[1]*(r[3]-r[1])+r[1]):o(l,0,0)}const U=l(),V=Object.freeze(Object.defineProperty({__proto__:null,build:B,calculateAnchorPosForRendering:L},Symbol.toStringTag,{value:"Module"}));export{V as H,B as b,L as c};