Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closest tiles disappearing when 3D terrain is used #1241

Closed
openSourcerer9000 opened this issue May 20, 2022 · 31 comments
Closed

Closest tiles disappearing when 3D terrain is used #1241

openSourcerer9000 opened this issue May 20, 2022 · 31 comments
Labels
bug Something isn't working terrain

Comments

@openSourcerer9000
Copy link

openSourcerer9000 commented May 20, 2022

When 3D terrain is on, maplibre is removing the closer raster tiles from view. Something to do with the camera being distorted from the viewport? It's like it thinks the closest tiles are out of view.

The issue is present with exaggeration of 1, but gets dramatically worse by increasing the exaggeration z-factor (TerrainLayer.jsx). Vector basemaps seem immune, but geojson vector layers also disappear in unison with raster basemaps and custom raster tiles.

The problem has been identified to occur in flat areas which are also down at sea level. All the terrain examples use the Swiss Alps, etc (because it looks awesome), so the camera may just be calibrated to elevations of 5km. Given an elevation of 0-5m, something may not be set up correctly.

You can fork this demo repo to test the issue, or just zoom to center: [-93.32780,29.8834], pitch:85 using this terrain and a raster imagery basemap.

        type: "raster-dem",
        tiles: ["https://vtc-cdn.maptoolkit.net/terrainrgb/{z}/{x}/{y}.webp"],

https://github.com/openSourcerer9000/MapLibreGL-3D-terrain-tiles-disappearing-issue-demo

May be related to this algorithm #1080?

image

maplibre-gl-js version: 2.2.0-pre.2

browser:Chrome

@wipfli wipfli added the terrain label May 20, 2022
@wipfli
Copy link
Contributor

wipfli commented May 20, 2022

Thanks for reporting! Do you think you can reproduce this problem by tuning the debug example below?

<!DOCTYPE html>
<html>

<head>
    <title>MapLibre GL JS Terrain3D Example</title>
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
    <link href="https://unpkg.com/[email protected]/dist/maplibre-gl.css" rel="stylesheet" />
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        html,
        body,
        #map {
            height: 100%;
        }
    </style>
</head>

<body>
    <div id='map'></div>

    <script>
        var map = window.map = new maplibregl.Map({
            container: 'map',
            zoom: 12,
            center: [11.39085, 47.27574],
            pitch: 52,
            hash: true,
            style: {
                version: 8,
                sources: {
                    osm: {
                        type: 'raster',
                        tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
                        tileSize: 256,
                        attribution: '&copy; OpenStreetMap Contributors',
                        maxzoom: 19
                    },
                    terrainSource: {
                        type: 'raster-dem',
                        url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
                        tileSize: 256
                    },
                    hillshadeSource: {
                        type: 'raster-dem',
                        url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json',
                        tileSize: 256
                    },
                },
                layers: [
                    {
                        id: 'osm',
                        type: 'raster',
                        source: 'osm'
                    },
                    {
                        id: 'hills',
                        type: 'hillshade',
                        source: 'hillshadeSource',
                        layout: {'visibility': 'visible'},
                        paint: {'hillshade-shadow-color': '#473B24'}
                    }
                ],
                terrain: {
                    source: 'terrainSource',
                    exaggeration: 1
                }
            },
            maxZoom: 18,
            maxPitch: 85
        });
        map.addControl(new maplibregl.NavigationControl({
            visualizePitch: true,
            showZoom: true,
            showCompass: true
        }));
        map.addControl(
            new maplibregl.TerrainControl({
                source: 'terrainSource',
                exaggeration: 1
            })
        );
    </script>
</body>

</html>

@christian-nils
Copy link

christian-nils commented May 23, 2022

Hi,

I experience the same issue. I used your demo code, and modified a bit to recreate the issue:

        var map = window.map =  new maplibregl.Map({
        container: 'map',
        zoom: 12,
        center: [14.9799, 56.5254],
        pitch: 52,
        hash: true,
        style: {
          version: 8,
          sources: {
            osm: {
              type: 'raster',
              tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
              tileSize: 256,
              attribution: '&copy; OpenStreetMap Contributors',
              maxzoom: 19
            },
            terrainSource: {
              type: 'raster-dem',
              url: 'https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=MY_MAPTILER_API_KEY',
              tileSize: 256
            },
            hillshadeSource: {
              type: 'raster-dem',
              url: 'https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=MY_MAPTILER_API_KEY',
              tileSize: 256
            }
          },
          layers: [
            {
              id: 'osm',
              type: 'raster',
              source: 'osm'
            },
            {
              id: 'hills',
              type: 'hillshade',
              source: 'hillshadeSource',
              layout: { visibility: 'visible' },
              paint: { 'hillshade-shadow-color': '#473B24' }
            }
          ],
          terrain: {
            source: 'terrainSource',
            exaggeration: 1
          }
        },
        maxZoom: 18,
        maxPitch: 85
      })
      map.addControl(
        new maplibregl.NavigationControl({
          visualizePitch: true,
          showZoom: true,
          showCompass: true
        })
      )
      map.addControl(
        new maplibregl.TerrainControl({
          source: 'terrainSource',
          exaggeration: 1
        })
      )

I changed the terrain-rgb to the tiles.json provided by MapTiler's API. Then I inspected a region of the world where the terrain is not that high. Here is the result:

screencast.mp4

Anyway, I take the opportunity to thank you for your work on this fantastic feature!

EDIT: BTW, the issue can be seen on https://maptoolkit.net as well. Go to a area that is quite flat (let's say Malmö), activate the 3D and zoom quite much on the map, tiles will start disappearing (https://maptoolkit.net/#/@12.99916,55.6034,18.4,59.9,60,terrain,3d).

@wiesehahn
Copy link

I experience the same issue with e.g.

 const map= new maplibregl.Map({
        container: "map",
        style: 'https://api.maptiler.com/maps/hybrid/style.json?key=XXX ',
        center: [10.61,51.78],
        pitch: 65,
        zoom: 13
      });

      map.on('load', () => {
        map.addSource("terrain", {
              "type": "raster-dem",
              "url": "https://api.maptiler.com/tiles/terrain-rgb/tiles.json?key=XXX ",
            });
            map.setTerrain({
                source: "terrain",
                exaggeration: 3 });
        });

grafik

I guess before exaggerating the tiles cover the window and then when exaggerated they are "lifted" to reveal the gap.

Also I recognized artifacts along horizontal tile borders in the distance. Are tiles of different zoom level used by distance?

@HarelM
Copy link
Collaborator

HarelM commented May 24, 2022

Are tiles of different zoom level used by distance?

As far as I know, yes.

@openSourcerer9000
Copy link
Author

openSourcerer9000 commented May 24, 2022

This comment may help put some perspective on the issue

@dechristopher
Copy link

I think this issue is due to the tileSize property in the terrain source. You need to set tileSize: 512 since most of the DEM sources from MapTiler aren't 256 pixels in size. When I added this, the issue was resolved. Hope this helps.

@openSourcerer9000
Copy link
Author

Hm OK in the map I'm working on I'm using custom terrain tiles. I can try gen'ing them at 512px instead and see if it works. If so, the common factors exposing the bug would be low elevation, flat slopes, and tiles at 256px.

@dechristopher
Copy link

dechristopher commented May 24, 2022

As for the flat slopes and low elevation, make sure you're generating the tiles to support the equation given here:

height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)

This is how MapLibre decodes raster-dem RGB sources to retrieve elevation data in meters.

I can't imagine there's a specification that demands 512px tiles for 3D terrain though.

@comlib1
Copy link

comlib1 commented May 24, 2022

Having the same issue... and switching to 512 tiles didn't solve the issue.

@openSourcerer9000
Copy link
Author

openSourcerer9000 commented May 24, 2022

@dechristopher

I split the single band terrain into Terrarium RGB using this rasterio script that seems to be floating around, and then set encoding='terrarium'

with rasterio.open('dem_plus_body.tif') as src:
    dem = src.read(1)
    r = np.zeros(dem.shape)
    g = np.zeros(dem.shape)
    b = np.zeros(dem.shape)

    v = dem + 32768
    r += np.floor(v / 256.0)
    g += np.floor(v % 256.0)
    b += np.floor((v - np.floor(v)) * 256.0)

    meta = src.profile
    meta["dtype"] = rasterio.uint8
    meta["nodata"] = None
    meta["count"] = 3

    with rasterio.open('encoded_elevation.tif', 'w', **meta) as dst:
        dst.write_band(1, r.astype(rasterio.uint8))
        dst.write_band(2, g.astype(rasterio.uint8))
        dst.write_band(3, b.astype(rasterio.uint8))

The encoding tag didn't throw an error, so I assume this format is supported? Also my elevation units were feet, so I guess if terrarium is m it would make it 3x flatter.

@christian-nils
Copy link

I think this issue is due to the tileSize property in the terrain source. You need to set tileSize: 512 since most of the DEM sources from MapTiler aren't 256 pixels in size. When I added this, the issue was resolved. Hope this helps.

Not sure if this is the right way to fix the issue. I am using the winter style provided by MapTiler (https://api.maptiler.com/maps/winter/style.json?key=MY_MAPTILER_API_KEY) and the source "terrain-rgb" does not have a tileSize property set to 256 so it should use the default of 512px. I do have the problem with this source as well.

@bertt
Copy link

bertt commented Jun 1, 2022

Sample of white tiles issues with vector tiles basemap: https://bertt.github.io/terrain_tiles/amerongen/

@acalcutt
Copy link
Contributor

acalcutt commented Jun 1, 2022

@bertt

I was looking at your example and was able to replicate your issue with my terrain tiles here https://wifidb.net/demo/terrain_raster/test4_notworking.html

The only two things I notice was
1.) Right now, Terrain and Hillshade are supposed to have separate sources due to the way source caching works at the moment. ( #1186 (comment) )
2.) Exaggeration was very high, Set to 10. It looks like you used my process for JAXA based terrain tiles, so the exaggeration should be the default of 1 with those tiles.

I tried fixing both those things. When I added the second source for hillshade, the issue persisted. When I set the exageration to 1, the issue with white tiles seems much better
https://wifidb.net/demo/terrain_raster/test4.html

So maybe this is an issue when a high exaggeration is set?

@acalcutt
Copy link
Contributor

acalcutt commented Jun 1, 2022

Actually I think I'm wrong. I still see the issue on the second example, I jut have to be zoomed in a lot further

@bertt
Copy link

bertt commented Jun 1, 2022

@acalcutt in this case I've used Dutch AHN3/PDOK height data see https://github.com/bertt/terrain_tiles/blob/main/amerongen/README.md

@acalcutt
Copy link
Contributor

acalcutt commented Jun 2, 2022

Could this be something with going over the maxzoom of the tile sources?

I notice if I take the first example in this thread and limit MaxZoom to 14, the issue doesn't occur
https://stackblitz.com/edit/web-platform-fsf4vk?file=index.html

However if I go a little higher, to MaxZoom 16, that issue appears
https://stackblitz.com/edit/web-platform-fembpm?file=index.html

For the other example @bertt , I also wonder about it being a bounds issue, since most of the sources I have used were full planet.

@bertt
Copy link

bertt commented Jun 2, 2022

@acalcutt don't think it's a bounds issue, don't see whitespace with 1 Jaxa DTM
https://bertt.github.io/terrain_tiles/spain/

Screenshot 2022-06-02 at 08 39 54

@timokorkalainen
Copy link
Contributor

Are the tiles available for all zoom levels? I believe I had an issue with a source providing only certain tile levels that meant the Terrain3D algorithm using a specific level to make initial height calculations couldn't perform and in turn seemed to produce similar errors.

@wiesehahn
Copy link

To me it looks more like tile coverage is calculated before exaggeration, and then if lifted too heavy it does not fit the viewport anymore. In my basic understanding additional tiles pointing towards the viewer should be requested. Based on exaggeration and pitch.

@flother
Copy link
Contributor

flother commented Jun 21, 2022

I have a 3D terrain map in development that I've used to test @prozessor13's proposed solution (352bc03) and as far as I can see it fixes the problem. With a TerrainRGB layer, a satellite raster layer, and an exaggeration of 1.5 the closest tiles to the camera are now visible.

Would it possible to publish a v2.2.0-pre.3 release for this? Once it's available via npmjs.com I would be happy to publish my map as a test for the fix.

@HarelM
Copy link
Collaborator

HarelM commented Jun 21, 2022

@flother as far as I can see in the PR a unit test is missing for this case.
If you could create a unit test to cover this case (and maybe a render test too) and send a PR against the branch of the linked PR (#1300) I think we could push this forward faster.
Thanks!!

@flother
Copy link
Contributor

flother commented Jun 21, 2022

@HarelM Done! (The unit test, at least).

HarelM pushed a commit that referenced this issue Jun 24, 2022
* Add terrain style spec integration test

Tests that the root level terrain object must be in the following form:

    "terrain": {
      "source": string,
      "exaggeration": number,
      "elevationOffset": number
    }

* Add work-in-progress render test for 3D terrain

* Fix terrain render test so it passes

The original test was failing because there were no terrain tiles
available at the zoom being requested. Now it's testing at zoom 13,
which means requesting terrain tiles at zoom 12, which are available to
the tests.

* Update terrain render test to test fix for #1241

The fix for #1241, commit 352bc03, ensures that elevationOffset is
taken into account when gauging which tiles are required to render 3D
terrain. If we add an extreme offset then we have a test that fails on
the current main branch but passes after the fix.
acalcutt pushed a commit to acalcutt/maplibre-gl-js that referenced this issue Jun 25, 2022
* Fixes maplibre#1241 - correct coveringTiles when terrain is enabled

* fix lint

* Add unit test for calculating min/max elevation (maplibre#1316)

* Add unit test for calculating min/max elevation

* Use correct method name

* Move min/max elevation value calc to Terrain class

* Alter Terrain.getMinMaxElevation to take tileID arg

* Fix unit tests after merge from main

* Fix lint

* Add render test for 3D terrain (maplibre#1320)

* Add terrain style spec integration test

Tests that the root level terrain object must be in the following form:

    "terrain": {
      "source": string,
      "exaggeration": number,
      "elevationOffset": number
    }

* Add work-in-progress render test for 3D terrain

* Fix terrain render test so it passes

The original test was failing because there were no terrain tiles
available at the zoom being requested. Now it's testing at zoom 13,
which means requesting terrain tiles at zoom 12, which are available to
the tests.

* Update terrain render test to test fix for maplibre#1241

The fix for maplibre#1241, commit 352bc03, ensures that elevationOffset is
taken into account when gauging which tiles are required to render 3D
terrain. If we add an extreme offset then we have a test that fails on
the current main branch but passes after the fix.

* Add changelog comment

Co-authored-by: Matt Riggott <[email protected]>
Co-authored-by: HarelM <[email protected]>
@flother
Copy link
Contributor

flother commented Jun 26, 2022

I think that this is fixed now that v2.2.0-pre.3 has been released. The terrain map I mentioned earlier in the thread is running on that version and I no longer have the problem of missing tiles.

https://www.flother.is/blog/geldingadalsgos/map/

@zdila
Copy link
Contributor

zdila commented Aug 18, 2022

May be a different issue, but in my case not only closest tiles but all. Open https://labs.maptiler.com/samples/maplibre/terrain/#style=satellite&lat=48.57344071&lng=20.46078220&zoom=17.16&bearing=-127.95&pitch=76.00&3d=true then zoom a little bit and tiles starts to disappear. If you refresh the page, nothing is shown until you zoom out. MapLibre 2.3.0.

@flother
Copy link
Contributor

flother commented Aug 19, 2022

It looks like that's a link to localhost — it doesn't resolve for me. Is there a public link you can share?

@zdila
Copy link
Contributor

zdila commented Aug 19, 2022

Oh, sorry. I've fixed the link.

@zdila
Copy link
Contributor

zdila commented Aug 19, 2022

What I noticed with https://labs.maptiler.com/samples/maplibre/terrain/ is that I can't zoom inside the hill, but with my demo I can do it, which probably causes all the tiles to (gradually) disappear.

@bertt
Copy link

bertt commented Aug 19, 2022

I can confirm this issue is fixed after upgrade from v2.2.0-pre.2 to 2.3.0. Demo: https://bertt.github.io/terrain_tiles/amerongen/

image

@prozessor13
Copy link
Collaborator

Walking with the camera into terrain is still an open issue :/

@HarelM
Copy link
Collaborator

HarelM commented Aug 21, 2022

I'm closing this as this is fixed I believe.
If there's another issue let's open a different one.

@HarelM HarelM closed this as completed Aug 21, 2022
@HarelM HarelM added the bug Something isn't working label Aug 21, 2022
@mattgrid
Copy link

I couldn't see an existing ticket for the camera bug mentioned by @zdila, so I've created #1542.

@HarelM HarelM added PR is more than welcomed Extra attention is needed and removed PR is more than welcomed Extra attention is needed labels Aug 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working terrain
Projects
None yet
Development

No branches or pull requests