UNPKG

@arcgis/core

Version:

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

117 lines (93 loc) 6.68 kB
/* All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://js.arcgis.com/4.32/esri/copyright.txt for details. */ import{addVerticalOffset as e}from"../attributes/VerticalOffset.glsl.js";import{ScreenSizePerspective as t,addScreenSizePerspectiveAlignment as o}from"../util/ScreenSizePerspective.glsl.js";import{addProjViewLocalOrigin as a,addCameraPosition as s,addViewNormal as i,addPixelRatio as r}from"../util/View.glsl.js";import{Float4BindUniform as n}from"../../shaderModules/Float4BindUniform.js";import{FloatBindUniform as l}from"../../shaderModules/FloatBindUniform.js";import{FloatPassUniform as f}from"../../shaderModules/FloatPassUniform.js";import{glsl as c}from"../../shaderModules/glsl.js";import{VertexAttribute as p}from"../../../lib/VertexAttribute.js";const d=.5;function u(u,v){u.include(t),u.attributes.add(p.POSITION,"vec3"),u.attributes.add(p.NORMAL,"vec3"),u.attributes.add(p.CENTEROFFSETANDDISTANCE,"vec4");const m=u.vertex;a(m,v),s(m,v),m.uniforms.add(new n("viewport",(e=>e.camera.fullViewport)),new f("polygonOffset",(e=>e.shaderPolygonOffset)),new l("cameraGroundRelative",(e=>e.camera.aboveGround?1:-1))),v.hasVerticalOffset&&e(m),m.constants.add("smallOffsetAngle","float",.984807753012208),m.code.add(c`struct ProjectHUDAux { vec3 posModel; vec3 posView; vec3 vnormal; float distanceToCamera; float absCosAngle; };`),m.code.add(c` float applyHUDViewDependentPolygonOffset(float pointGroundDistance, float absCosAngle, inout vec3 posView) { float pointGroundSign = ${v.terrainDepthTest?c.float(0):c`sign(pointGroundDistance)`}; if (pointGroundSign == 0.0) { pointGroundSign = cameraGroundRelative; } // cameraGroundRelative is -1 if camera is below ground, 1 if above ground // groundRelative is 1 if both camera and symbol are on the same side of the ground, -1 otherwise float groundRelative = cameraGroundRelative * pointGroundSign; // view angle dependent part of polygon offset emulation: we take the absolute value because the sign that is // dropped is instead introduced using the ground-relative position of the symbol and the camera if (polygonOffset > .0) { float cosAlpha = clamp(absCosAngle, 0.01, 1.0); float tanAlpha = sqrt(1.0 - cosAlpha * cosAlpha) / cosAlpha; float factor = (1.0 - tanAlpha / viewport[2]); // same side of the terrain if (groundRelative > 0.0) { posView *= factor; } // opposite sides of the terrain else { posView /= factor; } } return groundRelative; } `),v.draped&&!v.hasVerticalOffset||i(m),v.draped||(m.uniforms.add(new l("perDistancePixelRatio",(e=>Math.tan(e.camera.fovY/2)/(e.camera.fullViewport[2]/2)))),m.code.add(c` void applyHUDVerticalGroundOffset(vec3 normalModel, inout vec3 posModel, inout vec3 posView) { float distanceToCamera = length(posView); // Compute offset in world units for a half pixel shift float pixelOffset = distanceToCamera * perDistancePixelRatio * ${c.float(d)}; // Apply offset along normal in the direction away from the ground surface vec3 modelOffset = normalModel * cameraGroundRelative * pixelOffset; // Apply the same offset also on the view space position vec3 viewOffset = (viewNormal * vec4(modelOffset, 1.0)).xyz; posModel += modelOffset; posView += viewOffset; } `)),v.screenCenterOffsetUnitsEnabled&&r(m),v.hasScreenSizePerspective&&o(m),m.code.add(c` vec4 projectPositionHUD(out ProjectHUDAux aux) { vec3 centerOffset = centerOffsetAndDistance.xyz; float pointGroundDistance = centerOffsetAndDistance.w; aux.posModel = position; aux.posView = (view * vec4(aux.posModel, 1.0)).xyz; aux.vnormal = normal; ${v.draped?"":"applyHUDVerticalGroundOffset(aux.vnormal, aux.posModel, aux.posView);"} // Screen sized offset in world space, used for example for line callouts // Note: keep this implementation in sync with the CPU implementation, see // - MaterialUtil.verticalOffsetAtDistance // - HUDMaterial.applyVerticalOffsetTransformation aux.distanceToCamera = length(aux.posView); vec3 viewDirObjSpace = normalize(cameraPosition - aux.posModel); float cosAngle = dot(aux.vnormal, viewDirObjSpace); aux.absCosAngle = abs(cosAngle); ${v.hasScreenSizePerspective&&(v.hasVerticalOffset||v.screenCenterOffsetUnitsEnabled)?"vec3 perspectiveFactor = screenSizePerspectiveScaleFactor(aux.absCosAngle, aux.distanceToCamera, screenSizePerspectiveAlignment);":""} ${v.hasVerticalOffset?v.hasScreenSizePerspective?"float verticalOffsetScreenHeight = applyScreenSizePerspectiveScaleFactorFloat(verticalOffset.x, perspectiveFactor);":"float verticalOffsetScreenHeight = verticalOffset.x;":""} ${v.hasVerticalOffset?c` float worldOffset = clamp(verticalOffsetScreenHeight * verticalOffset.y * aux.distanceToCamera, verticalOffset.z, verticalOffset.w); vec3 modelOffset = aux.vnormal * worldOffset; aux.posModel += modelOffset; vec3 viewOffset = (viewNormal * vec4(modelOffset, 1.0)).xyz; aux.posView += viewOffset; // Since we elevate the object, we need to take that into account // in the distance to ground pointGroundDistance += worldOffset;`:""} float groundRelative = applyHUDViewDependentPolygonOffset(pointGroundDistance, aux.absCosAngle, aux.posView); ${v.screenCenterOffsetUnitsEnabled?"":c` // Apply x/y in view space, but z in screen space (i.e. along posView direction) aux.posView += vec3(centerOffset.x, centerOffset.y, 0.0); // Same material all have same z != 0.0 condition so should not lead to // branch fragmentation and will save a normalization if it's not needed if (centerOffset.z != 0.0) { aux.posView -= normalize(aux.posView) * centerOffset.z; } `} vec4 posProj = proj * vec4(aux.posView, 1.0); ${v.screenCenterOffsetUnitsEnabled?v.hasScreenSizePerspective?"float centerOffsetY = applyScreenSizePerspectiveScaleFactorFloat(centerOffset.y, perspectiveFactor);":"float centerOffsetY = centerOffset.y;":""} ${v.screenCenterOffsetUnitsEnabled?"posProj.xy += vec2(centerOffset.x, centerOffsetY) * pixelRatio * 2.0 / viewport.zw * posProj.w;":""} // constant part of polygon offset emulation posProj.z -= groundRelative * polygonOffset * posProj.w; return posProj; } `)}export{u as HUD,d as HUDVerticalPixelOffset};