mapbox / mapbox-gl-native

Interactive, thoroughly customizable maps in native Android, iOS, macOS, Node.js, and Qt applications, powered by vector tiles and OpenGL
https://mapbox.com/mobile
Other
4.36k stars 1.33k forks source link

Hillshading using Terrain RGB has pixelated issue at high zoom levels and a possible solution #16459

Open ystsoi opened 4 years ago

ystsoi commented 4 years ago

Platform: Android / iOS

I have prepared an Android test program to help showing the issue (need to set the access token first): https://github.com/ystsoi/mapbox-gl-native/tree/test-terrain-rgb-issues/TestTerrainRGBIssue

This is the pixelated hillshading at zoom level 14: Zoom 14

But if you clear the app data, zoom to level 10 or 11, then set the device to offline state, and zoom to level 14, the result seems better: Zoom 10 to 14 Zoom 11 to 14

The corresponding RGB image is: RGB

Therefore, for hillshading purpose, it may be better to limit the source max zoom level, which may improve the appearance, and decrease the download size. But I found that "maxzoom" for "raster-dem" source does not work with the Terrain RGB set via "url", "maxzoom" only works with custom tiles set via "tiles". See whether you can provide some ways to limit the maxzoom for the Terrain RGB source.

And when I work with custom raster-dem source, I have found a lightness issue, which can be shown by another test program: https://github.com/ystsoi/mapbox-gl-native/tree/test-terrain-rgb-issues/TestTerrainRGBIssue2

If I set the "maxzoom" of the source to 15, the output is: maxzoom 15

But if I set the "maxzoom" to 11, the output is darker: maxzoom 15

See whether this is a bug, or is by intention.

astojilj commented 4 years ago

This is known data issue: https://github.com/mapbox/mapbox-gl-js/issues/6027

maxzoom" to 11

In areas where full resolution of DEM data is not available, upscaled 11 is used as zoom level 14. We are working on fixing this.

ystsoi commented 4 years ago

Not sure whether this issue is related to that one, as that one talks about preserving vertical sub-meter resolution. For most area, I suppose that your source is SRTM, which has only 1 arc-sec horizontal resolution (around 30 meters), and meter-level vertical resolution. This corresponds to the pixel distance of zoom levels around 11 to 12 for 512x512-pixel tiles.

Therefore, tiles from higher zoom level should contain quite a lot of redundant values computed by interpolation. And I think that one of the possible causes of the pixelated issue may be due to the interpolation method use. If this is true, you may either prevent generating high zoom level tiles for area without high precision source, or use a better interpolation method which supports a smoother change of slope.

But solving the data issue may not solve hillshade issues completely. Suppose that one day we have very very detail source data, such that we can show hillshade for buildings, or even steps. But not all applications care about these details, and high detail tends to produce a lot of noises. So developers may want to lower the max zoom level to get a simpler hillshade.

And for the lightness/darkness issue, just to ensure that we are talking on the same thing. Actually, the custom terrain used by the second test program contains only one tile of zoom level 11: https://github.com/ystsoi/mapbox-gl-native/tree/test-terrain-rgb-issues/TestTerrainRGBIssue2/app/src/main/assets/terrain/11/1673 Therefore, no matter the maxzoom is 11 or 15, only the tile from zoom level 11 is used, but the result is of different lightness.

astojilj commented 4 years ago

Thanks for the analysis. Let's split the findings:

Pixelation issue at level 14 is related to mapbox/mapbox-gl-js#6027. Correct, using zoom 11 in areas where up to zoom 11 is supported is a workaround but it is not expected to produce the same value as I'll explain below.

But I found that "maxzoom" for "raster-dem" source does not work with the Terrain RGB set via "url", "maxzoom" only works with custom tiles set via "tiles".

This seems like a separate issue. Please submit another bug about it.

Different lightness is currently expected: in https://github.com/mapbox/mapbox-gl-js/blob/master/src/shaders/hillshade_prepare.fragment.glsl#L60 difference of zoom to max zoom is used.

    float exaggeration = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;

    vec2 deriv = vec2(
        (c + f + f + i) - (a + d + d + g),
        (g + h + h + i) - (a + b + b + c)
    ) /  pow(2.0, (u_zoom - u_maxzoom) * exaggeration + 19.2562 - u_zoom);

However, it is possible to adjust the results, using https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#paint-hillshade-hillshade-exaggeration layer styling option. Please check if that helps achieving the wanted results.

To complete the reference, hillshade-exaggeration is used in shader here (intensity).

The corresponding RGB image is:

A note about interpolation / upsampling: attached image (350x315) is not an original sent from server but scaled by browser's development tools: originals are 512x512 or 256x256. Using originals you should be able to see that four pixels in 2x2 pixel block have the same pixel value. We're working on this.

ystsoi commented 4 years ago

Opened a new issue for the "maxzoom" issue: https://github.com/mapbox/mapbox-gl-native/issues/16461

I see, need to take some time to digest the logic. It is OK, just a bit inconvenient that the intensity needs to be re-adjusted after changed the maxzoom.

Actually, the source data of the attached image is from your server. As the islet spans two tiles, I need to combine them, and then cut the related part. FYI, the source tiles are: https://api.mapbox.com/v4/mapbox.terrain-rgb/14/13391/7155@2x.webp?... https://api.mapbox.com/v4/mapbox.terrain-rgb/14/13391/7156@2x.webp?...

Cannot see any 2x2 pixel block.