Open eslavnov opened 4 years ago
Hey @eslavnov , could you provide an example with the styling used in code (jsfiddle or other) so we could reproduce this issue on our side?
Hi @karimnaaji!
Sorry that I did not provide an example from the very beginning, here it is: https://jsfiddle.net/gyrga/ku6wm3z8/
At the default zoom level, you can see these artefacts. If you zoom-in, at some point they go away and the line is displayed properly. While making this minimal example I've noticed that line-blur
seems to be the culprit: removing it results in a line with no such artefacts. Looks like line-blur
is struggling when there are small sharp corners and your view is zoomed-out...
Any pointers on how we could fix this issue will be highly appreciated!
Thanks, @eslavnov that's very useful. Yes it does seem to be related to line-blur
, it looks like there is overlapping geometry that is blending together at the line extremities, resulting in those overlays.
Hey, @eslavnov I was looking at your example on jsfiddle, I found that using an event with map.on
and setPaintProperty
you can dynamically change the map paint properties such as line-blur
. here is my example based on yours: https://jsfiddle.net/featmo/p0huvzj9/379/
Sorry if my explanation and code are a bit rough, this is my first issue.
hey, @karimnaaji this artifact shows when using line-opacity
Thanks for the example, looks great! I think that solution can provide a good workaround until we solve this type of issue within the library. @eslavnov have you considered and tried something like @featmo's solution?
Hi all,
Just wanted to share two possible mitigation strategies: 1) indeed, tweaking the line-blur depending on a zoom level helps quite a bit 2) for our particular use-case, tweaking the tolerance based on zoom helped a lot: most of these artifacts appear when the line makes a turn and only at specific zoom levels, so simplifying the lines for those zoom levels really helps.
This does not really solve the problem, but depending on your use case this might be an acceptable workaround.
Just one additional note is that this is not strictly a problem with the line-blur
property, though that's certainly one way to trigger it. It's more generally a problem with the combination of self-intersections caused by large line-widths and opacity < 1, as can be seen in the following image which uses no line-blur:
The only two methods I can think of for resolving this are adjusting the line geometry to prevent self-intersections (for example, we could limit vertex movement tangent to line segments to half of each line segment length so that nearby line vertices would not cause this overlap—at the cost of line offset correctness, and although computing these limits and passing them as attributes to the shader seems prohibitive), or to draw the lines to a separate framerbuffer and then composite them onto the map—which is currently not possible because compositing was removed early on due to serious performance problems.
I wrote up a somewhat lengthy description of exactly why this occurs and what can be done about it, which I'll copy below. The specific context was implementation of a glow or drop-shadow-like effect:
The line-blur property can be used to accomplish a glow or drop-shadow-like effect but results in jagged artifacts near sharp corners. These artifacts worsen as the line width (including blur) increases. A single sharp corner does not trigger the effect (edit: a single sharp corner can trigger this. See: #10925 for a partial resolution of this behavior, though it would not solve the case of nearby overlapping corners like those which would occur on a windy road). The image at the top of this issue illustrates this well. Note that most of these corners are isolated, though a small part of the artifacts in the lower left result from two overlapping corners:
It’s important to note that this is not strictly related to the line-blur property and more generally occurs on all lines with large width and opacity less than one. The image below shows two line layers. The transparent purple line layer exhibits the artifact even though there is no line-blur. See, for example:
This behavior occurs because of how Mapbox GL draws lines. For a detailed explanation of how lines are drawn, see the Mapbox blog post, Drawing Antialiased Lines in OpenGL.
Drawing lines first requires breaking up the line into triangles. The following diagram shows an example of a triangulation. (The exact triangulation Mapbox uses is very slightly different— it uses just two triangles—though the difference is not important with respect to line-blur artifacts.)
Lines of finite width must be joined with a miter or a round. The diagram below shows the geometry of a single corner.
The problem arises when triangulating two nearby corners. It is not straightforward, in general, to produce a triangulation of two nearby corners which does not self-intersect. Some self-intersection can be worked around easily (See in progress issue #10925 which I believe will significantly reduce these artifacts), but a more general solution would need to be performed on every frame as the map zooms and pitches, so that it’s not currently feasible to fully resolve the issue by performing this more complex geometric computation at each corner, on every frame.
There are workarounds, but not a general solution.
For a brief time, Mapbox GL supported layer blending modes by performing additional compositing steps during rendering. In this approach, fully opaque lines would be drawn to a separate image. The image would then be composited with transparency back onto the rendered map. However, this feature was removed in 2014 (see: https://github.com/mapbox/mapbox-gl-js/issues/523#issuecomment-51731405 )as a single blended layer could degrade performance of the entire map by 33%. Due to critical performance considerations, it is not currently planned to bring this feature back.
Note additionally that compositing alone would not fully solve the problem. A single self-intersecting, blurred line would still exhibit these artifacts, even if drawn on a separate layer. The key ingredient for perfect drop shadows would be to draw unblurred lines to a separate layer, then apply a blur filter to that layer, then composite the layer onto the main map. If the cost of compositing alone may be acceptable with graphics performance in 2021, I believe these additional blur filter passes would push the cost back into the infeasible range.
The artifacts worsen as line widths increase and mitered corner geometries intersect. The simplest way to reduce the artifacts is to adjust the style to minimize total line widths (including the width of line-blur).
Appearance of the artifacts depends most critically on line width and distance between line vertices. Both of these may change as the map is zoomed. Thus, it may be possible with careful use of expressions to reduce the line-blur shadowing effect in configuration ranges where the artifacts are most visible.
GeoJSON sources have a tolerance property. Increasing the tolerance increases line simplification, which in turn increases the distance between adjacent line vertices. This has the effect of reducing the artifacts. However, increasing simplification impacts overall rendering of the map and may be too indirect a solution to be advisable.
There is more than one way to accomplish the appearance of a shadow. In addition to just the line-blur property (which increasing causes the artifacts under consideration), it is possible to add a viewport-anchored translation to the lines. The line-translate and line-translate-anchor properties provide a mechanism for applying a similar depth cue without increasing the total line width.
One downside of this approach is that the intersecting lines as well as line-caps still combine additively during rendering, resulting in potentially undesirable behavior at line caps. The image below shows the effect of different line-cap choices. I believe rounded line caps may be the best option in this approach.
See: sample style
@asheemmamoowala pointed out that it might be possible to use multiple shadows in different viewport-anchored directions, e.g. [1, 0], [0, 1], [-1, 0], [0, -1]. I believe performance would be acceptable, but I suspect this would introduce angular dependence on the shadow strength, as well as unpleasant patterns at line ends or where lines meet.
Hi guys,
Thank you for this awesome library!
Not sure if it's a bug or just me doing something wrong (probably the latter...), but I am experiencing some weird rendering issues when using the line layer.
At the maximum zoom level the line looks as I would expect it:
However, when I zoom out I start to get these strange artefacts where my line makes sharp turns:
I've tried tweaking various settings and also searched the issues, but no luck. I would really appreciate if somebody could point me in the right direction: to be honest, I am a bit lost now on how to debug/fix this issue.
Thanks in advance!