-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathshader-frag.ts
106 lines (95 loc) · 2.77 KB
/
shader-frag.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { CreateEdgeCurveProgramOptions } from "./utils";
export default function getFragmentShader({ arrowHead }: CreateEdgeCurveProgramOptions) {
const hasTargetArrowHead = arrowHead?.extremity === "target" || arrowHead?.extremity === "both";
const hasSourceArrowHead = arrowHead?.extremity === "source" || arrowHead?.extremity === "both";
// language=GLSL
const SHADER = /*glsl*/ `
precision highp float;
varying vec4 v_color;
varying float v_thickness;
varying float v_feather;
varying vec2 v_cpA;
varying vec2 v_cpB;
varying vec2 v_cpC;
${
hasTargetArrowHead
? `
varying float v_targetSize;
varying vec2 v_targetPoint;`
: ""
}
${
hasSourceArrowHead
? `
varying float v_sourceSize;
varying vec2 v_sourcePoint;`
: ""
}
${
arrowHead
? `
uniform float u_lengthToThicknessRatio;
uniform float u_widenessToThicknessRatio;`
: ""
}
float det(vec2 a, vec2 b) {
return a.x * b.y - b.x * a.y;
}
vec2 getDistanceVector(vec2 b0, vec2 b1, vec2 b2) {
float a = det(b0, b2), b = 2.0 * det(b1, b0), d = 2.0 * det(b2, b1);
float f = b * d - a * a;
vec2 d21 = b2 - b1, d10 = b1 - b0, d20 = b2 - b0;
vec2 gf = 2.0 * (b * d21 + d * d10 + a * d20);
gf = vec2(gf.y, -gf.x);
vec2 pp = -f * gf / dot(gf, gf);
vec2 d0p = b0 - pp;
float ap = det(d0p, d20), bp = 2.0 * det(d10, d0p);
float t = clamp((ap + bp) / (2.0 * a + b + d), 0.0, 1.0);
return mix(mix(b0, b1, t), mix(b1, b2, t), t);
}
float distToQuadraticBezierCurve(vec2 p, vec2 b0, vec2 b1, vec2 b2) {
return length(getDistanceVector(b0 - p, b1 - p, b2 - p));
}
const vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);
void main(void) {
float dist = distToQuadraticBezierCurve(gl_FragCoord.xy, v_cpA, v_cpB, v_cpC);
float thickness = v_thickness;
${
hasTargetArrowHead
? `
float distToTarget = length(gl_FragCoord.xy - v_targetPoint);
float targetArrowLength = v_targetSize + thickness * u_lengthToThicknessRatio;
if (distToTarget < targetArrowLength) {
thickness = (distToTarget - v_targetSize) / (targetArrowLength - v_targetSize) * u_widenessToThicknessRatio * thickness;
}`
: ""
}
${
hasSourceArrowHead
? `
float distToSource = length(gl_FragCoord.xy - v_sourcePoint);
float sourceArrowLength = v_sourceSize + thickness * u_lengthToThicknessRatio;
if (distToSource < sourceArrowLength) {
thickness = (distToSource - v_sourceSize) / (sourceArrowLength - v_sourceSize) * u_widenessToThicknessRatio * thickness;
}`
: ""
}
float halfThickness = thickness / 2.0;
if (dist < halfThickness) {
#ifdef PICKING_MODE
gl_FragColor = v_color;
#else
float t = smoothstep(
halfThickness - v_feather,
halfThickness,
dist
);
gl_FragColor = mix(v_color, transparent, t);
#endif
} else {
gl_FragColor = transparent;
}
}
`;
return SHADER;
}