Variable: LINE_FRAGMENT_SHADER
ts
const LINE_FRAGMENT_SHADER: '\nprecision highp float;\n\nuniform vec2 uResolution;\nuniform float uPixelRatio;\nuniform vec4 uViewport; // GL viewport in device px (xy origin, zw size)\n\nvec2 hcClipToScreen(vec4 clip) {\n return (clip.xy / clip.w * 0.5 + 0.5) * uResolution;\n}\n\nvec4 hcScreenToClip(vec2 screen, float ndcZ) {\n return vec4(screen / uResolution * 2.0 - 1.0, ndcZ, 1.0);\n}\n\nvec4 hcOffsetClip(vec4 clip, vec2 offsetPx) {\n clip.xy += offsetPx / uResolution * 2.0 * clip.w;\n return clip;\n}\n\n/** Snap CSS px to the device-pixel grid; phase 0 = pixel edges, 0.5 = pixel centers. */\nfloat hcSnap(float px, float phase) {\n return (floor(px * uPixelRatio - phase + 0.5) + phase) / uPixelRatio;\n}\n\n/** Width of one device pixel in CSS px: the anti-aliasing ramp used by SDF fragment shaders. */\nfloat hcAAWidth() {\n return 1.0 / uPixelRatio;\n}\n\n\nuniform float uCap;\nuniform float uOpacity;\nuniform float uDash[16];\nuniform float uDashCount;\nuniform float uDashPeriod;\n\nflat in vec4 vAB;\nflat in vec4 vFrame;\nflat in vec4 vTangents;\nflat in vec4 vEndA;\nflat in vec4 vEndB;\nflat in vec3 vDash;\n#ifdef LINE_UNIFORM_COLOR\nuniform vec4 uColor;\n#else\nflat in vec4 vColorA;\nflat in vec4 vColorB;\n#endif\n\nout highp vec4 fragColor;\n\nconst float END_BUTT = 1.0;\nconst float END_SQUARE = 2.0;\nconst float END_ROUND = 3.0;\nconst float END_BEVEL = 4.0;\nconst float OWN_EPS = 1.0 / 512.0; // px; see the ownership partition in main()\n\nfloat endDistance(vec4 info, vec2 rel, float beyond, float hw) {\n if (info.w == END_BUTT || info.w == END_ROUND) return beyond;\n if (info.w == END_SQUARE) return beyond - hw;\n if (info.w == END_BEVEL) return dot(rel, info.xy) - info.z;\n return -1e20; // miter: bounded by the ownership clip only\n}\n\n// The nearest of best and the distances to the "on" interval [a, b] and its two neighbours.\nfloat hcDashInterval(float best, float m, float a, float b) {\n best = min(best, max(a - m, m - b));\n best = min(best, max(a - (m - uDashPeriod), (m - uDashPeriod) - b));\n best = min(best, max(a - (m + uDashPeriod), (m + uDashPeriod) - b));\n return best;\n}\n\n// Signed distance to the nearest "on" interval of the repeating dash pattern (mirrors\n// dashDistance() in line-dash.ts).\nfloat hcDashDistance(float along) {\n float m = along - floor(along / uDashPeriod) * uDashPeriod;\n if (uDashCount < 2.5) return hcDashInterval(1e20, m, 0.0, 0.0 + uDash[0]);\n float best = 1e20;\n float start = 0.0;\n int count = min(int(uDashCount), 16);\n for (int i = 0; i < count; i += 2) {\n float a = start;\n float b = start + uDash[i];\n best = hcDashInterval(best, m, a, b);\n start = b + uDash[i + 1];\n }\n return best;\n}\n\nvoid main() {\n // Screen px, from gl_FragCoord: bit-identical for both segments at a join.\n vec2 vPos = (gl_FragCoord.xy - uViewport.xy) / uViewport.zw * uResolution;\n vec2 a = vAB.xy;\n vec2 b = vAB.zw;\n vec2 dir = vFrame.xy;\n float len = vFrame.z;\n float hw = vFrame.w;\n vec2 rel = vPos - a;\n vec2 relB = vPos - b;\n\n // Exact ownership partition at joins, offset by OWN_EPS off the pixel centers.\n if (vTangents.xy != vec2(0.0) && dot(rel, vTangents.xy) < OWN_EPS) discard;\n if (vTangents.zw != vec2(0.0) && dot(relB, vTangents.zw) >= OWN_EPS) discard;\n\n float t = dot(rel, dir);\n float perp = dot(rel, vec2(-dir.y, dir.x));\n float d = abs(perp) - hw;\n d = max(d, endDistance(vEndA, rel, -t, hw));\n d = max(d, endDistance(vEndB, relB, t - len, hw));\n if (vEndA.w == END_ROUND) d = min(d, length(rel) - hw);\n if (vEndB.w == END_ROUND) d = min(d, length(relB) - hw);\n\n if (uDashCount > 0.5 && uDashPeriod > 0.0) {\n // Joins and caps take the dash state of their vertex (t clamped), so both segments agree.\n float scale = max(vDash.y, 1e-6);\n float along = vDash.x + clamp(t, 0.0, len) * scale;\n float dd = hcDashDistance(along) / scale;\n float dashD = dd;\n if (uCap > 1.5) dashD = dd - hw;\n else if (uCap > 0.5) dashD = length(vec2(max(dd, 0.0), perp)) - hw;\n d = max(d, dashD);\n }\n\n float coverage = clamp(0.5 - d / hcAAWidth(), 0.0, 1.0) * vDash.z;\n#ifdef LINE_UNIFORM_COLOR\n vec4 color = uColor;\n#else\n vec4 color = mix(vColorA, vColorB, len > 0.0 ? clamp(t / len, 0.0, 1.0) : 0.0);\n#endif\n float alpha = color.a * coverage * uOpacity;\n if (alpha <= 0.0) discard;\n fragColor = vec4(color.rgb, alpha);\n}\n';Experimental