Skip to content

Commit d34e13c

Browse files
committed
fix: When lines reverse on themselves, mitering could be wrong
If a line reversed direction exactly, mitering logic could render only half the pixels that should have been rendered. In general, when lines nearly reverse on themselves, mitering is tricky. This add some thresholds, below which the lines aren't mitered but are just rendered. For opaque lines, this is a strict improvement, though some joints may no longer show rounded or truncated miters. For semi-transparent lines, this is in general an improvement, but there can be cases where they appear double rendered instead of joined. The behavior is still deemed an improvement, as they should never have only have half the pixels rendered.
1 parent 90ae5d5 commit d34e13c

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

src/webgl/lineFeature.vert

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ void main(void)
6262
gl_Position = vec4(2.0, 2.0, 0.0, 1.0);
6363
return;
6464
}
65+
float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;
66+
// if lines reverse upon themselves and are not nearly the same length, skip
67+
// joins. This is a heuristic; the correct method would to be to pass some
68+
// sort of length of the adjacent line to the fragment renderer and adjust
69+
// which fragments are rendered, but this is much more complex.
70+
float abLimit = length(vec2(A.x - B.x, (A.y - B.y) / aspect)) / pixelWidth;
71+
float dcLimit = length(vec2(D.x - C.x, (D.y - C.y) / aspect)) / pixelWidth;
72+
if (abLimit >= lineLength - antialiasing - strokeWidth * 0.5 && abLimit <= lineLength + antialiasing + strokeWidth * 0.5) {
73+
abLimit = 0.0001;
74+
} else {
75+
if (abLimit < lineLength) abLimit = lineLength;
76+
abLimit = (strokeWidth - antialiasing) / (abLimit + antialiasing);
77+
if (abLimit < 0.0001) abLimit = 0.0001;
78+
if (abLimit > 0.1) abLimit = 0.1;
79+
}
80+
if (dcLimit >= lineLength - antialiasing - strokeWidth * 0.5 && dcLimit <= lineLength + antialiasing + strokeWidth * 0.5) {
81+
dcLimit = 0.0001;
82+
} else {
83+
if (dcLimit < lineLength) dcLimit = lineLength;
84+
dcLimit = (strokeWidth - antialiasing) / (dcLimit + antialiasing);
85+
if (dcLimit < 0.0001) dcLimit = 0.0001;
86+
if (dcLimit > 0.1) dcLimit = 0.1;
87+
}
6588
float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);
6689
// values we need to pass along
6790
strokeColorVar = vec4(strokeColor, strokeOpacity);
@@ -78,7 +101,7 @@ void main(void)
78101
// by default, offset by the width and don't extend lines. Later,
79102
// calculate line extensions based on end cap and end join modes
80103
float yOffset = strokeWidth + antialiasing;
81-
if (vertex == 0 || vertex == 2) yOffset *= -1.0;
104+
if (vertex == 0) yOffset *= -1.0;
82105
yOffset += strokeWidth * offset;
83106
float xOffset = 0.0;
84107
// end caps
@@ -105,7 +128,7 @@ void main(void)
105128
angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;
106129
cosABC = cos(angleABC); sinABC = sin(angleABC);
107130
// if this angle is close to flat, pass-through the join
108-
if (nearMode >= 4 && cosABC > 0.999999) {
131+
if (nearMode >= 4 && (cosABC > 0.999999 || cosABC < abLimit)) {
109132
nearMode = 3;
110133
}
111134
// miter, miter-clip
@@ -138,7 +161,7 @@ void main(void)
138161
angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;
139162
cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);
140163
// if this angle is close to flat, pass-through the join
141-
if (farMode >= 4 && cosBCD > 0.999999) {
164+
if (farMode >= 4 && (cosBCD > 0.999999 || cosBCD < dcLimit)) {
142165
farMode = 3;
143166
}
144167
// miter, miter-clip
@@ -159,8 +182,6 @@ void main(void)
159182
B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,
160183
B.z, 1.0);
161184
// store other values needed to determine which pixels to plot.
162-
float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;
163-
164185
if (vertex == 0 || vertex == 1) {
165186
subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);
166187
info = vec4(float(nearMode), float(farMode), offset, 0.0);

0 commit comments

Comments
 (0)