UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

277 lines (245 loc) • 16.6 kB
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */ import{SliceDraw as e}from"../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl.js";import{ObjectAndLayerIdColor as i}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/ObjectAndLayerIdColor.glsl.js";import{RibbonVertexPosition as t}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/RibbonVertexPosition.glsl.js";import{LineStipple as n,computePixelSize as r}from"../views/3d/webgl-engine/core/shaderLibrary/shading/LineStipple.glsl.js";import{MarkerSizing as o}from"../views/3d/webgl-engine/core/shaderLibrary/shading/MarkerSizing.glsl.js";import{PiUtils as a}from"../views/3d/webgl-engine/core/shaderLibrary/shading/PiUtils.glsl.js";import{positionOutsideClipSpace as s}from"../views/3d/webgl-engine/core/shaderLibrary/shading/PositionOutsideClipSpace.js";import{terrainDepthTest as l}from"../views/3d/webgl-engine/core/shaderLibrary/shading/TerrainDepthTest.glsl.js";import{ColorConversion as p}from"../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl.js";import{NoPerspectiveWrite as d,NoPerspectiveRead as c}from"../views/3d/webgl-engine/core/shaderLibrary/util/NoPerspective.glsl.js";import{addProjViewLocalOrigin as m,addPixelRatio as v}from"../views/3d/webgl-engine/core/shaderLibrary/util/View.glsl.js";import{Float2BindUniform as f}from"../views/3d/webgl-engine/core/shaderModules/Float2BindUniform.js";import{Float4BindUniform as g}from"../views/3d/webgl-engine/core/shaderModules/Float4BindUniform.js";import{Float4PassUniform as h}from"../views/3d/webgl-engine/core/shaderModules/Float4PassUniform.js";import{FloatBindUniform as S}from"../views/3d/webgl-engine/core/shaderModules/FloatBindUniform.js";import{FloatPassUniform as u}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{glsl as D,If as x}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{Matrix4BindUniform as L}from"../views/3d/webgl-engine/core/shaderModules/Matrix4BindUniform.js";import{AnimatedLine as w}from"../views/3d/webgl-engine/shaders/AnimatedLine.glsl.js";import{outputColorHighlightOLID as b}from"../views/3d/webgl-engine/shaders/OutputColorHighlightOLID.glsl.js";import{ShaderBuilder as y}from"../views/webgl/ShaderBuilder.js";import{alphaCutoff as P}from"../webscene/support/AlphaCutoff.js";const j=1;function z(z){const C=new y,{attributes:W,varyings:R,vertex:F,fragment:A}=C,{applyMarkerOffset:V,draped:T,output:E,capType:O,stippleEnabled:$,falloffEnabled:N,roundJoins:M,wireframe:_,innerColorEnabled:k,hasAnimation:I,hasScreenSizePerspective:B,worldSizedImagePattern:H}=z;A.include(a),C.include(t,z),C.include(n,z),C.include(i,z),C.include(l,z),C.include(w,z);const J=V&&!T;J&&(F.uniforms.add(new u("markerScale",e=>e.markerScale)),C.include(o,{space:2,hasScreenSizePerspective:B})),m(F,z),F.uniforms.add(new L("inverseProjectionMatrix",e=>e.camera.inverseProjectionMatrix),new f("nearFar",e=>e.camera.nearFar),new u("miterLimit",e=>"miter"!==e.join?0:e.miterLimit),new g("viewport",e=>e.camera.fullViewport)),F.constants.add("LARGE_HALF_FLOAT","float",65500),W.add("position","vec3"),W.add("previousDelta","vec4"),W.add("nextDelta","vec4"),W.add("lineParameters","vec2"),W.add("u0","float"),R.add("vColor","vec4"),R.add("vpos","vec3",{invariant:!0}),R.add("vLineDistance","float"),R.add("vLineWidth","float");const U=$;U&&R.add("vLineSizeInv","float");const G=2===O,q=$&&G,K=N||q;K&&R.add("vLineDistanceNorm","float"),G&&(R.add("vSegmentSDF","float"),R.add("vReverseSegmentSDF","float")),F.code.add(D`vec2 perpendicular(vec2 v) { return vec2(v.y, -v.x); } float interp(float ncp, vec4 a, vec4 b) { return (-ncp - a.z) / (b.z - a.z); } vec2 rotate(vec2 v, float a) { float s = sin(a); float c = cos(a); mat2 m = mat2(c, -s, s, c); return m * v; }`),F.code.add(D`vec4 projectAndScale(vec4 pos) { vec4 posNdc = proj * pos; posNdc.xy *= viewport.zw / posNdc.w; return posNdc; }`),F.code.add(D`void clip( inout vec4 pos, inout vec4 prev, inout vec4 next, bool isStartVertex ) { float vnp = nearFar[0] * 0.99; if (pos.z > -nearFar[0]) { if (!isStartVertex) { if (prev.z < -nearFar[0]) { pos = mix(prev, pos, interp(vnp, prev, pos)); next = pos; } else { pos = vec4(0.0, 0.0, 0.0, 1.0); } } else { if (next.z < -nearFar[0]) { pos = mix(pos, next, interp(vnp, pos, next)); prev = pos; } else { pos = vec4(0.0, 0.0, 0.0, 1.0); } } } else { if (prev.z > -nearFar[0]) { prev = mix(pos, prev, interp(vnp, pos, prev)); } if (next.z > -nearFar[0]) { next = mix(next, pos, interp(vnp, next, pos)); } } }`),v(F),F.constants.add("aaWidth","float",$?0:1).main.add(D` // unpack values from vertex type bool isStartVertex = abs(abs(lineParameters.y) - 3.0) == 1.0; vec3 prevPosition = position + previousDelta.xyz * previousDelta.w; vec3 nextPosition = position + nextDelta.xyz * nextDelta.w; float coverage = 1.0; // Check for special value of lineParameters.y which is used by the Renderer when graphics are removed before the // VBO is recompacted. If this is the case, then we just project outside of clip space. if (lineParameters.y == 0.0) { gl_Position = ${s}; } else { vec4 pos = view * vec4(position, 1.0); vec4 prev = view * vec4(prevPosition, 1.0); vec4 next = view * vec4(nextPosition, 1.0); bool isJoin = abs(lineParameters.y) < 3.0; `),J&&F.main.add(D`vec4 other = isStartVertex ? next : prev; bool markersHidden = areWorldMarkersHidden(pos.xyz, other.xyz); if (!isJoin && !markersHidden) { pos.xyz += normalize(other.xyz - pos.xyz) * getWorldMarkerSize(pos.xyz) * 0.5; }`),C.include(d),F.main.add(D` clip(pos, prev, next, isStartVertex); vec3 clippedPos = pos.xyz; vec3 clippedCenter = mix(pos.xyz, isStartVertex ? next.xyz : prev.xyz, 0.5); forwardViewPosDepth(pos.xyz); pos = projectAndScale(pos); next = projectAndScale(next); prev = projectAndScale(prev); vec2 left = (pos.xy - prev.xy); vec2 right = (next.xy - pos.xy); float leftLen = length(left); float rightLen = length(right); float lineSize = getSize(${x(B,"clippedPos")}); ${x($&&B,"float patternLineSize = getSize(clippedCenter);")} ${x($&&!B,"float patternLineSize = lineSize;")} ${x(H,D` lineSize += aaWidth; float lineWidth = lineSize * pixelRatio * worldToScreenRatio; if (lineWidth < 1.0) { coverage = lineWidth; lineWidth = 1.0; } `,D` if (lineSize < 1.0) { coverage = lineSize; // convert sub-pixel coverage to alpha lineSize = 1.0; } lineSize += aaWidth; float lineWidth = lineSize * pixelRatio; `)} vLineWidth = noPerspectiveWrite(lineWidth, pos.w); ${U?D`vLineSizeInv = noPerspectiveWrite(1.0 / lineSize, pos.w);`:""} `);($||G)&&F.main.add(D` float isEndVertex = float(!isStartVertex); vec2 segmentOrigin = mix(pos.xy, prev.xy, isEndVertex); vec2 segment = mix(right, left, isEndVertex); ${G?D`vec2 segmentEnd = mix(next.xy, pos.xy, isEndVertex);`:""} `),F.main.add(D`left = (leftLen > 0.001) ? left/leftLen : vec2(0.0, 0.0); right = (rightLen > 0.001) ? right/rightLen : vec2(0.0, 0.0); vec2 capDisplacementDir = vec2(0, 0); vec2 joinDisplacementDir = vec2(0, 0); float displacementLen = lineWidth; if (isJoin) { bool isOutside = (left.x * right.y - left.y * right.x) * lineParameters.y > 0.0; joinDisplacementDir = normalize(left + right); joinDisplacementDir = perpendicular(joinDisplacementDir); if (leftLen > 0.001 && rightLen > 0.001) { float nDotSeg = dot(joinDisplacementDir, left); displacementLen /= length(nDotSeg * left - joinDisplacementDir); if (!isOutside) { displacementLen = min(displacementLen, min(leftLen, rightLen)/abs(nDotSeg)); } } float subdivisionFactor = lineParameters.x; if (isOutside && (displacementLen > miterLimit * lineWidth)) {`),M?F.main.add(D` vec2 startDir = leftLen < 0.001 ? right : left; startDir = perpendicular(startDir); vec2 endDir = rightLen < 0.001 ? left : right; endDir = perpendicular(endDir); float factor = ${$?D`min(1.0, subdivisionFactor * ${D.float((j+2)/(j+1))})`:D`subdivisionFactor`}; float rotationAngle = acos(clamp(dot(startDir, endDir), -1.0, 1.0)); joinDisplacementDir = rotate(startDir, -sign(lineParameters.y) * factor * rotationAngle); `):F.main.add(D`if (leftLen < 0.001) { joinDisplacementDir = right; } else if (rightLen < 0.001) { joinDisplacementDir = left; } else { joinDisplacementDir = (isStartVertex || subdivisionFactor > 0.0) ? right : left; } joinDisplacementDir = perpendicular(joinDisplacementDir);`);const Q=0!==O;return F.main.add(D` displacementLen = lineWidth; } } else { // CAP handling --------------------------------------------------- joinDisplacementDir = isStartVertex ? right : left; joinDisplacementDir = perpendicular(joinDisplacementDir); ${Q?D`capDisplacementDir = isStartVertex ? -right : left;`:""} } `),F.main.add(D` // Displacement (in pixels) caused by join/or cap vec2 dpos = joinDisplacementDir * sign(lineParameters.y) * displacementLen + capDisplacementDir * displacementLen; float lineDistNorm = noPerspectiveWrite(sign(lineParameters.y), pos.w); vLineDistance = lineWidth * lineDistNorm; ${K?D`vLineDistanceNorm = lineDistNorm;`:""} pos.xy += dpos; `),G&&F.main.add(D`vec2 segmentDir = normalize(segment); vSegmentSDF = noPerspectiveWrite((isJoin && isStartVertex) ? LARGE_HALF_FLOAT : (dot(pos.xy - segmentOrigin, segmentDir)), pos.w); vReverseSegmentSDF = noPerspectiveWrite((isJoin && !isStartVertex) ? LARGE_HALF_FLOAT : (dot(pos.xy - segmentEnd, -segmentDir)), pos.w);`),$&&(T?F.uniforms.add(new S("worldToScreenRatio",e=>1/e.screenToPCSRatio)):F.main.add(D`vec3 segmentCenter = mix((nextPosition + position) * 0.5, (position + prevPosition) * 0.5, isEndVertex); float worldToScreenRatio = computeWorldToScreenRatio(segmentCenter);`),F.main.add(D`float segmentLengthScreenDouble = length(segment); float segmentLengthScreen = segmentLengthScreenDouble * 0.5; float discreteWorldToScreenRatio = discretizeWorldToScreenRatio(worldToScreenRatio); float segmentLengthRender = length(mix(nextPosition - position, position - prevPosition, isEndVertex)); vStipplePatternStretch = worldToScreenRatio / discreteWorldToScreenRatio;`),T?F.main.add(D`float segmentLengthPseudoScreen = segmentLengthScreen / pixelRatio * discreteWorldToScreenRatio / worldToScreenRatio; float startPseudoScreen = u0 * discreteWorldToScreenRatio - mix(0.0, segmentLengthPseudoScreen, isEndVertex);`):F.main.add(D`float startPseudoScreen = mix(u0, u0 - segmentLengthRender, isEndVertex) * discreteWorldToScreenRatio; float segmentLengthPseudoScreen = segmentLengthRender * discreteWorldToScreenRatio;`),F.uniforms.add(new u("stipplePatternPixelSize",e=>r(e))),F.main.add(D` float patternLength = patternLineSize * stipplePatternPixelSize; ${x(H,D` float uu = mix(u0, u0 - segmentLengthRender, isEndVertex); vStippleDistanceLimits = vec2(uu, uu + segmentLengthRender); vStipplePatternStretch = 1.0; // The v-coordinate used in case of an image pattern. bool isLeft = sign(lineParameters.y) < 0.0; vStippleV = isLeft ? 0.0 : 1.0; `,D` // Compute the coordinates at both start and end of the line segment, because we need both to clamp to in the // fragment shader vStippleDistanceLimits = computeStippleDistanceLimits(startPseudoScreen, segmentLengthPseudoScreen, segmentLengthScreen, patternLength); `)} vStippleDistance = mix(vStippleDistanceLimits.x, vStippleDistanceLimits.y, isEndVertex); // Adjust the coordinate to the displaced position (the pattern is shortened/overextended on the in/outside of // joins) if (segmentLengthScreenDouble >= 0.001) { // Project the actual vertex position onto the line segment. Note that the resulting factor is within [0..1] // at the original vertex positions, and slightly outside of that range at the displaced positions vec2 stippleDisplacement = pos.xy - segmentOrigin; float stippleDisplacementFactor = dot(segment, stippleDisplacement) / (segmentLengthScreenDouble * segmentLengthScreenDouble); // Apply this offset to the actual vertex coordinate (can be screen or pseudo-screen space) vStippleDistance += (stippleDisplacementFactor - isEndVertex) * (vStippleDistanceLimits.y - vStippleDistanceLimits.x); } // Cancel out perspective correct interpolation because we want this length the really represent the screen // distance vStippleDistanceLimits = noPerspectiveWrite(vStippleDistanceLimits, pos.w); vStippleDistance = noPerspectiveWrite(vStippleDistance, pos.w); // Disable stipple distance limits on caps vStippleDistanceLimits = isJoin ? vStippleDistanceLimits : isStartVertex ? vec2(-1e34, vStippleDistanceLimits.y) : vec2(vStippleDistanceLimits.x, 1e34); `)),F.main.add(D` // Convert back into NDC pos.xy = (pos.xy / viewport.zw) * pos.w; vColor = getColor(); vColor.a = noPerspectiveWrite(vColor.a * coverage, pos.w); ${_&&!T?"pos.z -= 0.001 * pos.w;":""} // transform final position to camera space for slicing vpos = (inverseProjectionMatrix * pos).xyz; gl_Position = pos; forwardObjectAndLayerIdColor(); }`),C.fragment.include(e,z),C.include(b,z),A.include(p),A.main.add(D`discardBySlice(vpos); discardByTerrainDepth();`),C.include(c),A.main.add(D` float lineWidth = noPerspectiveRead(vLineWidth); float lineDistance = noPerspectiveRead(vLineDistance); ${x(K,D`float lineDistanceNorm = noPerspectiveRead(vLineDistanceNorm);`)} `),_?A.main.add(D`vec4 finalColor = vec4(1.0, 0.0, 1.0, 1.0);`):(G&&A.main.add(D` float sdf = noPerspectiveRead(min(vSegmentSDF, vReverseSegmentSDF)); vec2 fragmentPosition = vec2(min(sdf, 0.0), lineDistance); float fragmentRadius = length(fragmentPosition); float fragmentCapSDF = (fragmentRadius - lineWidth) * 0.5; // Divide by 2 to transform from double pixel scale float capCoverage = clamp(0.5 - fragmentCapSDF, 0.0, 1.0); if (capCoverage < ${D.float(P)}) { discard; } `),q?A.main.add(D` vec2 stipplePosition = vec2( min(getStippleSDF() * 2.0 - 1.0, 0.0), lineDistanceNorm ); float stippleRadius = length(stipplePosition * lineWidth); float stippleCapSDF = (stippleRadius - lineWidth) * 0.5; // Divide by 2 to transform from double pixel scale float stippleCoverage = clamp(0.5 - stippleCapSDF, 0.0, 1.0); float stippleAlpha = step(${D.float(P)}, stippleCoverage); `):A.main.add(D`float stippleAlpha = getStippleAlpha(lineWidth);`),9!==E&&A.main.add(D`discardByStippleAlpha(stippleAlpha, ${D.float(P)});`),C.include(c),A.uniforms.add(new h("intrinsicColor",e=>e.color)).main.add(D`vec4 color = intrinsicColor * vColor; color.a = noPerspectiveRead(color.a);`),k&&A.uniforms.add(new h("innerColor",e=>e.innerColor??e.color),new u("innerWidth",(e,i)=>e.innerWidth*i.camera.pixelRatio)).main.add(D`float distToInner = abs(lineDistance) - innerWidth; float innerAA = clamp(0.5 - distToInner, 0.0, 1.0); float innerAlpha = innerColor.a + color.a * (1.0 - innerColor.a); color = mix(color, vec4(innerColor.rgb, innerAlpha), innerAA);`),A.main.add(D`vec4 finalColor = blendStipple(color, stippleAlpha);`),N&&(A.uniforms.add(new u("falloff",e=>e.falloff)),A.main.add(D`finalColor.a *= pow(max(0.0, 1.0 - abs(lineDistanceNorm)), falloff);`)),$||A.main.add(D`float featherStartDistance = max(lineWidth - 2.0, 0.0); float value = abs(lineDistance); float feather = (value - featherStartDistance) / (lineWidth - featherStartDistance); finalColor.a *= 1.0 - clamp(feather, 0.0, 1.0);`),I&&A.main.add(D` finalColor = animate(finalColor); ${x(9!==E,D` if (finalColor.a <= ${D.float(P)}) { discard; }`)} `)),A.main.add(D`outputColorHighlightOLID(applySlice(finalColor, vpos), finalColor.rgb);`),C}const C=Object.freeze(Object.defineProperty({__proto__:null,build:z,ribbonlineNumRoundJoinSubdivisions:j},Symbol.toStringTag,{value:"Module"}));export{C as R,z as b,j as r};