@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
162 lines (133 loc) • 10.9 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import{copy as e,set as o}from"../core/libs/gl-matrix-2/math/vec2.js";import{create as i}from"../core/libs/gl-matrix-2/factories/vec2f64.js";import{ZEROS as r}from"../core/libs/gl-matrix-2/factories/vec4f64.js";import{RejectBySlice as t}from"../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl.js";import{ObjectAndLayerIdColor as l}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/ObjectAndLayerIdColor.glsl.js";import{AlignPixel as a}from"../views/3d/webgl-engine/core/shaderLibrary/hud/AlignPixel.glsl.js";import{HUD as s}from"../views/3d/webgl-engine/core/shaderLibrary/hud/HUD.glsl.js";import{HUDOcclusionPass as n}from"../views/3d/webgl-engine/core/shaderLibrary/hud/HUDOcclusionPass.glsl.js";import{HUDVisibility as c}from"../views/3d/webgl-engine/core/shaderLibrary/hud/HUDVisibility.glsl.js";import{OutputHighlight as d}from"../views/3d/webgl-engine/core/shaderLibrary/output/OutputHighlight.glsl.js";import{ReadDepth as u}from"../views/3d/webgl-engine/core/shaderLibrary/output/ReadDepth.glsl.js";import{positionOutsideClipSpace as f}from"../views/3d/webgl-engine/core/shaderLibrary/shading/PositionOutsideClipSpace.js";import{VisualVariables as p}from"../views/3d/webgl-engine/core/shaderLibrary/shading/VisualVariables.glsl.js";import{ColorConversion as g}from"../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl.js";import{ScreenSizePerspective as m,addScreenSizePerspective as v,addScreenSizePerspectiveAlignment as x}from"../views/3d/webgl-engine/core/shaderLibrary/util/ScreenSizePerspective.glsl.js";import{addPixelRatio as b}from"../views/3d/webgl-engine/core/shaderLibrary/util/View.glsl.js";import{Float2PassUniform as h}from"../views/3d/webgl-engine/core/shaderModules/Float2PassUniform.js";import{Float4BindUniform as w}from"../views/3d/webgl-engine/core/shaderModules/Float4BindUniform.js";import{Float4PassUniform as C}from"../views/3d/webgl-engine/core/shaderModules/Float4PassUniform.js";import{FloatPassUniform as z}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{If as P,glsl as S}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{Texture2DBindUniform as j}from"../views/3d/webgl-engine/core/shaderModules/Texture2DBindUniform.js";import{Texture2DPassUniform as y}from"../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform.js";import{ShaderBuilder as A}from"../views/webgl/ShaderBuilder.js";import{alphaCutoff as $}from"../webscene/support/AlphaCutoff.js";function O(e){const i=new A;if(i.include(s,e),i.vertex.include(t,e),e.occlusionPass)return i.include(n,e),i;const{output:O,oitPass:L,hasOcclusionTexture:U,signedDistanceFieldEnabled:M,useVisibilityPixel:_,pixelSnappingEnabled:q,hasEmission:H,hasScreenSizePerspective:R,debugDrawLabelBorder:k,hasVVSize:E,hasVVColor:I,hasRotation:G,occludedFragmentFade:J,sampleSignedDistanceFieldTexelCenter:K}=e;i.include(m),i.include(p,e),i.include(l,e),_&&i.include(c);const{vertex:N,fragment:Q}=i;Q.include(g),i.varyings.add("vcolor","vec4"),i.varyings.add("vtc","vec2"),i.varyings.add("vsize","vec2");const W=8===O,X=W&&_;X&&i.varyings.add("voccluded","float"),N.uniforms.add(new w("viewport",e=>e.camera.fullViewport),new h("screenOffset",(e,i)=>o(B,2*e.screenOffset[0]*i.camera.pixelRatio,2*e.screenOffset[1]*i.camera.pixelRatio)),new h("anchorPosition",e=>F(e)),new C("materialColor",({color:e})=>e),new z("materialRotation",e=>e.rotation),new y("tex",e=>e.texture)),b(N),M&&(N.uniforms.add(new C("outlineColor",e=>e.outlineColor)),Q.uniforms.add(new C("outlineColor",e=>D(e)?e.outlineColor:r),new z("outlineSize",e=>D(e)?e.outlineSize:0))),q&&N.include(a),R&&(v(N),x(N)),k&&i.varyings.add("debugBorderCoords","vec4"),i.attributes.add("uv0","vec2"),i.attributes.add("uvi","vec4"),i.attributes.add("color","vec4"),i.attributes.add("size","vec2"),i.attributes.add("rotation","float"),(E||I)&&i.attributes.add("featureAttribute","vec4"),N.main.add(S`
ProjectHUDAux projectAux;
vec4 posProj = projectPositionHUD(projectAux);
forwardObjectAndLayerIdColor();
if (rejectBySlice(projectAux.posModel)) {
gl_Position = ${f};
return;
}
vec2 inputSize;
${P(R,S`
inputSize = screenSizePerspectiveScaleVec2(size, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspective);
vec2 screenOffsetScaled = screenSizePerspectiveScaleVec2(screenOffset, projectAux.absCosAngle, projectAux.distanceToCamera, screenSizePerspectiveAlignment);`,S`
inputSize = size;
vec2 screenOffsetScaled = screenOffset;`)}
${P(E,S`inputSize *= vvScale(featureAttribute).xx;`)}
vec2 combinedSize = inputSize * pixelRatio;
vec4 quadOffset = vec4(0.0);
${P(_,S`
bool visible = testHUDVisibility(posProj);
if (!visible) {
vtc = vec2(0.0);
${P(k,"debugBorderCoords = vec4(0.5, 0.5, 1.5 / combinedSize);")}
return;
}
`)}
${P(X,S`voccluded = visible ? 0.0 : 1.0;`)}
`);const Y=S`
vec2 uv = mix(uvi.xy, uvi.zw, bvec2(uv0));
vec2 texSize = vec2(textureSize(tex, 0));
uv = mix(vec2(1.0), uv / texSize, lessThan(uv, vec2(${T})));
quadOffset.xy = (uv0 - anchorPosition) * 2.0 * combinedSize;
${P(G,S`
float angle = radians(materialRotation + rotation);
float cosAngle = cos(angle);
float sinAngle = sin(angle);
mat2 rotate = mat2(cosAngle, -sinAngle, sinAngle, cosAngle);
quadOffset.xy = rotate * quadOffset.xy;
`)}
quadOffset.xy = (quadOffset.xy + screenOffsetScaled) / viewport.zw * posProj.w;
`,Z=q?M?S`posProj = alignToPixelOrigin(posProj, viewport.zw) + quadOffset;`:S`posProj += quadOffset;
if (inputSize.x == size.x) {
posProj = alignToPixelOrigin(posProj, viewport.zw);
}`:S`posProj += quadOffset;`;N.main.add(S`
${Y}
${I?"vcolor = interpolateVVColor(featureAttribute.y) * materialColor;":"vcolor = color * materialColor;"}
${P(9===O,S`vcolor.a = 1.0;`)}
bool alphaDiscard = vcolor.a < ${S.float($)};
${P(M,`alphaDiscard = alphaDiscard && outlineColor.a < ${S.float($)};`)}
if (alphaDiscard) {
// "early discard" if both symbol color (= fill) and outline color (if applicable) are transparent
gl_Position = vec4(1e38, 1e38, 1e38, 1.0);
return;
} else {
${Z}
gl_Position = posProj;
}
vtc = uv;
${P(k,S`debugBorderCoords = vec4(uv0, 1.5 / combinedSize);`)}
vsize = inputSize;
`),Q.uniforms.add(new y("tex",e=>e.texture)),J&&!W&&(Q.include(u),Q.uniforms.add(new j("depthMap",e=>e.mainDepth),new z("occludedOpacity",e=>e.occludedFragmentOpacity?.value??1))),U&&Q.uniforms.add(new j("texOcclusion",e=>e.hudOcclusion?.attachment));const ee=k?S`(isBorder > 0.0 ? 0.0 : ${S.float($)})`:S.float($),oe=S`
${P(k,S`float isBorder = float(any(lessThan(debugBorderCoords.xy, debugBorderCoords.zw)) || any(greaterThan(debugBorderCoords.xy, 1.0 - debugBorderCoords.zw)));`)}
vec2 samplePos = vtc;
${P(K,S`
float txSize = float(textureSize(tex, 0).x);
float texelSize = 1.0 / txSize;
// Calculate how much we have to add/subtract to/from each texel to reach the size of an onscreen pixel
vec2 scaleFactor = (vsize - txSize) * texelSize;
samplePos += (vec2(1.0, -1.0) * texelSize) * scaleFactor;`)}
${M?S`
vec4 fillPixelColor = vcolor;
// Get distance in output units (i.e. pixels)
float sdf = texture(tex, samplePos).r;
float pixelDistance = sdf * vsize.x;
// Create smooth transition from the icon into its outline
float fillAlphaFactor = clamp(0.5 - pixelDistance, 0.0, 1.0);
fillPixelColor.a *= fillAlphaFactor;
if (outlineSize > 0.25) {
vec4 outlinePixelColor = outlineColor;
float clampedOutlineSize = min(outlineSize, 0.5*vsize.x);
// Create smooth transition around outline
float outlineAlphaFactor = clamp(0.5 - (abs(pixelDistance) - 0.5*clampedOutlineSize), 0.0, 1.0);
outlinePixelColor.a *= outlineAlphaFactor;
if (
outlineAlphaFactor + fillAlphaFactor < ${ee} ||
fillPixelColor.a + outlinePixelColor.a < ${S.float($)}
) {
discard;
}
// perform un-premultiplied over operator (see https://en.wikipedia.org/wiki/Alpha_compositing#Description)
float compositeAlpha = outlinePixelColor.a + fillPixelColor.a * (1.0 - outlinePixelColor.a);
vec3 compositeColor = vec3(outlinePixelColor) * outlinePixelColor.a +
vec3(fillPixelColor) * fillPixelColor.a * (1.0 - outlinePixelColor.a);
${P(!W,S`fragColor = vec4(compositeColor, compositeAlpha);`)}
} else {
if (fillAlphaFactor < ${ee}) {
discard;
}
${P(!W,S`fragColor = premultiplyAlpha(fillPixelColor);`)}
}
// visualize SDF:
// fragColor = vec4(clamp(-pixelDistance/vsize.x*2.0, 0.0, 1.0), clamp(pixelDistance/vsize.x*2.0, 0.0, 1.0), 0.0, 1.0);
`:S`
vec4 texColor = texture(tex, samplePos, -0.5);
if (texColor.a < ${ee}) {
discard;
}
${P(!W,S`fragColor = texColor * premultiplyAlpha(vcolor);`)}
`}
${P(J&&!W,S`
float zSample = -linearizeDepth(texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x);
float zFragment = -linearizeDepth(gl_FragCoord.z);
if (zSample < ${S.float(1-V)} * zFragment) {
fragColor *= occludedOpacity;
}
`)}
${P(U,S`fragColor *= texelFetch(texOcclusion, ivec2(gl_FragCoord.xy), 0).r;`)}
${P(!W&&k,S`fragColor = mix(fragColor, vec4(1.0, 0.0, 1.0, 1.0), isBorder * 0.5);`)}
${P(2===L,S`
if (fragColor.a < ${S.float($)}) {
discard;
}`)}
`;switch(O){case 0:i.outputs.add("fragColor","vec4",0),H&&i.outputs.add("fragEmission","vec4",1),1===L&&i.outputs.add("fragAlpha","float",H?2:1),Q.main.add(S`
${oe}
// Unlike other materials, the fragment shader outputs premultiplied colors.
// Disable this for front face rendering for correct OIT compositing.
${P(2===L,S`fragColor.rgb /= fragColor.a;`)}
${P(H,S`fragEmission = vec4(0.0);`)}
${P(1===L,S`fragAlpha = fragColor.a;`)}`);break;case 9:Q.main.add(S`
${oe}
outputObjectAndLayerIdColor();`);break;case 8:i.include(d,e),Q.main.add(S`
${oe}
outputHighlight(${P(X,S`voccluded == 1.0`,S`false`)});`)}return i}function D(e){return e.outlineColor[3]>0&&e.outlineSize>0}function F(o){return o.textureIsSignedDistanceField?L(o.anchorPosition,o.distanceFieldBoundingBox,B):e(B,o.anchorPosition),B}const B=i();function L(e,i,r){o(r,e[0]*(i[2]-i[0])+i[0],e[1]*(i[3]-i[1])+i[1])}const V=.08,U=32e3,T=S.float(U),M=Object.freeze(Object.defineProperty({__proto__:null,build:O,calculateAnchorPosition:F,fullUV:U},Symbol.toStringTag,{value:"Module"}));export{M as H,O as b,F as c,U as f};