mapbox / mapbox-gl-js

Interactive, thoroughly customizable maps in the browser, powered by vector tiles and WebGL
https://docs.mapbox.com/mapbox-gl-js/
Other
11.16k stars 2.21k forks source link

Always use GL_LINEAR interpolation for icon rendering #8730

Open kkaefer opened 5 years ago

kkaefer commented 5 years ago

Our goal is to render icons as crisp and sharp as possible. Since our icons are raster based, the best case is doing a 1:1 blit where we transfer the pixels directly, without any kind of interpolation, from the icon atlas texture. To that extent, we are disabling texture interpolation (by using GL_NEAREST) in situations where the map is not in the process of being rotated or zoomed, it's not tilted, and only for icons that are not rotated, transformed, or resized in any way. If all of those conditions are met, our map looks like this:

interpolation-nearest

However, when one of these isn't met, we resort to linear interpolation, which makes them look like this:

interpolation-linear

Note how some icons, like the Metro signs, are a bit blurry. To make this easier to see, here's a GIF that swaps both back and forth:

interpolation

However, there are a lot of caveats with our current approach:

I think we should remove our use of GL_NEAREST and always use linear interpolation. To keep icons crips, we could ensure that icons that can be rendered crisply use texture coordinates that are aligned to the texture's pixel grid. This would allow us to mix pixel-grid aligned and scaled icons within the same draw call, as well as "fade" between pixel-grid alignment and linearly interpolated icons when rotating or zooming.

I've done a few experiments in a local playground, and I believe the way to go is to adjust the texture coordinate in the vertex shader and shift it by the fractional value that the vertex is offset from an integer screen coordinate. This requires a border of 1 pixel around all of our icons to account for the linear interpolation. We already have a 1 pixel padding in our rendering code.

/cc @ansis

asheemmamoowala commented 5 years ago

@kkaefer Would this also address the issue raised in https://github.com/mapbox/mapbox-gl-js/issues/8476 ?

mourner commented 5 years ago

Related: #8118

kkaefer commented 5 years ago

@asheemmamoowala to some extent; since the icons are stretched, they're antialiased, and slightly blurry in the stretch direction, but it certainly looks better than before.

Old (GL_NEAREST)

Screenshot_2019-09-05 Mapbox GL JS debug page(1)

New (GL_LINEAR with my local version)

Screenshot_2019-09-05 Mapbox GL JS debug page

The problem in https://github.com/mapbox/mapbox-gl-js/issues/8476 is exacerbated by the fact that icon-text-fit treats the 1 pixel padding as part of the image that it stretches when it shouldn't do that.