Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

maplibre-gl-3dtiles-terrain

Use a Cesium-style 3D Tiles quantized-mesh terrain dataset (swisstopo, Cesium World Terrain, …) as ordinary terrain in MapLibre GL JS — with map.setTerrain(), queryTerrainElevation(), hillshade and 2D-layer draping, and no changes to MapLibre core.

MapLibre's terrain pipeline consumes a regular-grid heightmap (raster-dem); quantized-mesh tiles are irregular TINs. This plugin resamples each requested Web-Mercator tile from the TIN onto a regular grid, terrarium-packs it, and serves it through maplibregl.addProtocol, so from MapLibre's side it is just a raster-dem source.

Install

npm install maplibre-gl-3dtiles-terrain

Plain ESM, no build step. maplibre-gl is a peer dependency. You provide a quantized-mesh decoder (e.g. @here/quantized-mesh-decoder) — it is injected so this package stays small and you control its version.

Usage

import * as maplibregl from 'maplibre-gl';
import decode from '@here/quantized-mesh-decoder';
import {loadQuantizedMeshDataset, registerQuantizedMeshTerrain}
    from 'maplibre-gl-3dtiles-terrain';

// 1. describe the dataset from its layer.json
const dataset = await loadQuantizedMeshDataset(
    'https://3d.geo.admin.ch/ch.swisstopo.terrain.3d/v1/layer.json',
    {
        attribution: 'Terrain: © swisstopo',
        // swisstopo's layer.json omits `available`; synthesize it over these
        // bounds up to maxZoom (tiles the server actually lacks degrade to a
        // fallback apron).
        boundsOverride: {west: 5.6, south: 45.5, east: 11.0, north: 48.2},
        maxZoom: 14
    }
);

// 2. register the protocol and get a ready-made raster-dem source spec
const {sourceSpec} = registerQuantizedMeshTerrain(maplibregl, {dataset, decode});

// 3. use it like any terrain
map.on('load', () => {
    map.addSource('qm-terrain', sourceSpec);
    map.setTerrain({source: 'qm-terrain', exaggeration: 1.2});
    map.addLayer({id: 'hillshade', type: 'hillshade', source: 'qm-terrain'});
});

API

loadQuantizedMeshDataset(layerJsonUrl, options?) => Promise<dataset>

Fetches the dataset's layer.json and returns {available, bounds, minZoom, maxZoom, fadeDistanceDeg, attribution, tileUrl(z,x,y)}.

Options:

  • boundsOverride {west,south,east,north} — synthesize availability for endpoints that omit the available array.
  • maxZoom — cap synthesized availability.
  • attribution — fallback if layer.json omits it.

registerQuantizedMeshTerrain(maplibregl, options) => {protocol, sourceSpec, unregister}

Registers the addProtocol handler and returns a raster-dem sourceSpec (encoding: 'terrarium', tiles: ['<protocol>://{z}/{x}/{y}'], plus minzoom/maxzoom/bounds/attribution). Call unregister() to remove it.

Options:

  • dataset — from loadQuantizedMeshDataset.
  • decode(buffer) => {header:{minHeight,maxHeight}, vertexData, triangleIndices} — the quantized-mesh decoder.
  • protocol — default 'quantized-mesh'.
  • tileSize — default 256.
  • fallbackHeight — default 1500; apron height outside coverage.

Notes

  • Quantized-mesh uses the EPSG:4326 TMS grid (2 tiles wide at zoom 0); the plugin handles the reprojection to Web Mercator internally.
  • Datasets requiring an access token (e.g. Cesium World Terrain via Cesium ion) work by building the tileUrl with the token; the keyless swisstopo endpoint needs none.
  • Resampling runs on the main thread. A worker transferring raw ArrayBuffers is a possible future optimization.

License

BSD-3-Clause.

About

Use Cesium-style 3D Tiles quantized-mesh terrain as a raster-dem source in MapLibre GL JS

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages