@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
119 lines (103 loc) • 7.74 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.32/esri/copyright.txt for details.
*/
import{ShaderOutput as e}from"../views/3d/webgl-engine/core/shaderLibrary/ShaderOutput.js";import{SliceDraw as o}from"../views/3d/webgl-engine/core/shaderLibrary/Slice.glsl.js";import{Transform as r}from"../views/3d/webgl-engine/core/shaderLibrary/Transform.glsl.js";import{ObjectAndLayerIdColor as t}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/ObjectAndLayerIdColor.glsl.js";import{VertexColor as a}from"../views/3d/webgl-engine/core/shaderLibrary/attributes/VertexColor.glsl.js";import{terrainDepthTest as i}from"../views/3d/webgl-engine/core/shaderLibrary/shading/TerrainDepthTest.glsl.js";import{VisualVariables as l}from"../views/3d/webgl-engine/core/shaderLibrary/shading/VisualVariables.glsl.js";import{ColorConversion as n}from"../views/3d/webgl-engine/core/shaderLibrary/util/ColorConversion.glsl.js";import{addProjViewLocalOrigin as c,addCameraPosition as d}from"../views/3d/webgl-engine/core/shaderLibrary/util/View.glsl.js";import{Float4PassUniform as s}from"../views/3d/webgl-engine/core/shaderModules/Float4PassUniform.js";import{FloatBindUniform as v}from"../views/3d/webgl-engine/core/shaderModules/FloatBindUniform.js";import{glsl as g}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{VertexAttribute as p}from"../views/3d/webgl-engine/lib/VertexAttribute.js";import{Style as m}from"../views/3d/webgl-engine/materials/PatternStyle.js";import{outputColorHighlightOID as f}from"../views/3d/webgl-engine/shaders/OutputColorHighlightOID.glsl.js";import{ShaderBuilder as u}from"../views/webgl/ShaderBuilder.js";const w=.70710678118,b=w,h=.08715574274,y=10,S=1;function j(j){const C=new u,{vertex:T,fragment:P,attributes:R,varyings:V}=C,D=j.output===e.Highlight;c(T,j),C.include(r,j),C.include(a,j),C.include(l,j),C.include(t,j),C.fragment.include(o,j),C.include(f,j),C.include(i,j),j.draped?T.uniforms.add(new v("worldToScreenRatio",(e=>1/e.screenToPCSRatio))):R.add(p.BOUNDINGRECT,"mat3"),R.add(p.POSITION,"vec3"),R.add(p.UVMAPSPACE,"vec4"),j.vvColor&&R.add(p.COLORFEATUREATTRIBUTE,"float"),j.hasVertexColors||V.add("vColor","vec4"),V.add("vpos","vec3"),V.add("vuv","vec2"),T.uniforms.add(new s("uColor",(e=>e.color)));const O=j.style===m.ForwardDiagonal||j.style===m.BackwardDiagonal||j.style===m.DiagonalCross;return O&&T.code.add(g`
const mat2 rotate45 = mat2(${g.float(w)}, ${g.float(-.70710678118)},
${g.float(b)}, ${g.float(w)});
`),j.draped||(d(T,j),T.uniforms.add(new v("worldToScreenPerDistanceRatio",(e=>1/e.camera.perScreenPixelRatio))),T.code.add(g`vec3 projectPointToLineSegment(vec3 center, vec3 halfVector, vec3 point) {
float projectedLength = dot(halfVector, point - center) / dot(halfVector, halfVector);
return center + halfVector * clamp(projectedLength, -1.0, 1.0);
}`),T.code.add(g`vec3 intersectRayPlane(vec3 rayDir, vec3 rayOrigin, vec3 planeNormal, vec3 planePoint) {
float d = dot(planeNormal, planePoint);
float t = (d - dot(planeNormal, rayOrigin)) / dot(planeNormal, rayDir);
return rayOrigin + t * rayDir;
}`),T.code.add(g`
float boundingRectDistanceToCamera() {
vec3 center = vec3(boundingRect[0][0], boundingRect[0][1], boundingRect[0][2]);
vec3 halfU = vec3(boundingRect[1][0], boundingRect[1][1], boundingRect[1][2]);
vec3 halfV = vec3(boundingRect[2][0], boundingRect[2][1], boundingRect[2][2]);
vec3 n = normalize(cross(halfU, halfV));
vec3 viewDir = - vec3(view[0][2], view[1][2], view[2][2]);
float viewAngle = dot(viewDir, n);
float minViewAngle = ${g.float(h)};
if (abs(viewAngle) < minViewAngle) {
// view direction is (almost) parallel to plane -> clamp it to min angle
float normalComponent = sign(viewAngle) * minViewAngle - viewAngle;
viewDir = normalize(viewDir + normalComponent * n);
}
// intersect view direction with infinite plane that contains bounding rect
vec3 planeProjected = intersectRayPlane(viewDir, cameraPosition, n, center);
// clip to bounds by projecting to u and v line segments individually
vec3 uProjected = projectPointToLineSegment(center, halfU, planeProjected);
vec3 vProjected = projectPointToLineSegment(center, halfV, planeProjected);
// use to calculate the closest point to camera on bounding rect
vec3 closestPoint = uProjected + vProjected - center;
return length(closestPoint - cameraPosition);
}
`)),T.code.add(g`
vec2 scaledUV() {
vec2 uv = uvMapSpace.xy ${O?" * rotate45":""};
vec2 uvCellOrigin = uvMapSpace.zw ${O?" * rotate45":""};
${j.draped?"":g`
float distanceToCamera = boundingRectDistanceToCamera();
float worldToScreenRatio = worldToScreenPerDistanceRatio / distanceToCamera;
`}
// Logarithmically discretize ratio to avoid jittering
float step = 0.1;
float discreteWorldToScreenRatio = log(worldToScreenRatio);
discreteWorldToScreenRatio = ceil(discreteWorldToScreenRatio / step) * step;
discreteWorldToScreenRatio = exp(discreteWorldToScreenRatio);
vec2 uvOffset = mod(uvCellOrigin * discreteWorldToScreenRatio, ${g.float(y)});
return uvOffset + (uv * discreteWorldToScreenRatio);
}
`),T.main.add(g`
vuv = scaledUV();
vpos = position;
forwardViewPosDepth((view * vec4(vpos, 1.0)).xyz);
forwardNormalizedVertexColor();
forwardObjectAndLayerIdColor();
${j.hasVertexColors?"vColor *= uColor;":j.vvColor?"vColor = uColor * interpolateVVColor(colorFeatureAttribute);":"vColor = uColor;"}
gl_Position = transformPosition(proj, view, vpos);
`),P.include(n),j.draped&&P.uniforms.add(new v("texelSize",(e=>1/e.camera.pixelRatio))),D||(P.code.add(g`
const float lineWidth = ${g.float(S)};
const float spacing = ${g.float(y)};
const float spacingINV = ${g.float(1/y)};
float coverage(float p, float txlSize) {
p = mod(p, spacing);
float halfTxlSize = txlSize / 2.0;
float start = p - halfTxlSize;
float end = p + halfTxlSize;
float coverage = (ceil(end * spacingINV) - floor(start * spacingINV)) * lineWidth;
coverage -= min(lineWidth, mod(start, spacing));
coverage -= max(lineWidth - mod(end, spacing), 0.0);
return coverage / txlSize;
}
`),j.draped||P.code.add(g`const int maxSamples = 5;
float sampleAA(float p) {
vec2 dxdy = abs(vec2(dFdx(p), dFdy(p)));
float fwidth = dxdy.x + dxdy.y;
ivec2 samples = 1 + ivec2(clamp(dxdy, 0.0, float(maxSamples - 1)));
vec2 invSamples = 1.0 / vec2(samples);
float accumulator = 0.0;
for (int j = 0; j < maxSamples; j++) {
if(j >= samples.y) {
break;
}
for (int i = 0; i < maxSamples; i++) {
if(i >= samples.x) {
break;
}
vec2 step = vec2(i,j) * invSamples - 0.5;
accumulator += coverage(p + step.x * dxdy.x + step.y * dxdy.y, fwidth);
}
}
accumulator /= float(samples.x * samples.y);
return accumulator;
}`)),P.main.add(g`
discardBySlice(vpos);
discardByTerrainDepth();
vec4 color = vColor;
${D?"":g`color.a *= ${x(j)};`}
outputColorHighlightOID(color, vpos);
`),C}function x(e){function o(o){return e.draped?g`coverage(vuv.${o}, texelSize)`:g`sampleAA(vuv.${o})`}switch(e.style){case m.ForwardDiagonal:case m.Horizontal:return o("y");case m.BackwardDiagonal:case m.Vertical:return o("x");case m.DiagonalCross:case m.Cross:return g`1.0 - (1.0 - ${o("x")}) * (1.0 - ${o("y")})`;default:return"0.0"}}const C=Object.freeze(Object.defineProperty({__proto__:null,build:j},Symbol.toStringTag,{value:"Module"}));export{C as P,j as b};