Skip to content

Commit 9121fc7

Browse files
ImageOverlayPlugins: Add MVT Support (#1575)
* Add PMTiles plugin with MVT support * Add support for redraw, rearchitecture * Simplify * Update * Consolidate * Remove export * Read PMTiles header * Update demo, simplify * Remove unnecessary class * Add export * Fix artifacts * Move functions * Cleanup * Simplification * Updates * Shift to entirely user-defined styles * Updats * Remove tile styler * Simplification * Update * Remove style * Add support for png, etc pmtiles * Switch to dynamic imports * Share canvas drawing logic * Updates * Clean up * Add getStyle * Cleanup * Clean up * Cleanup * Cleanup * Fix naming * Add Path2D support * Comment * Remove outdates docs * Switch to generated surface plugin * lint fixes * Small fix ups * Simplification * Simplification * Share "setFrame" functions * Updates * Updates * Cleanup * Cleanup * Fix lack of queueing * simplify pmtiles image source * Adjust * Variable updates * Cleanup * Update docs * Always split when zooming in * Update PMTiles * Code style updates * Update JSDoc * Docs update * Updates to docs * Tab fix * update docs * Updates --------- Co-authored-by: AlaricBaraou <alaric.baraou@gmail.com>
1 parent 8a5978f commit 9121fc7

14 files changed

Lines changed: 1417 additions & 160 deletions

example/three/pmtiles.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6+
7+
<title>PMTiles Globe Example</title>
8+
<link rel="stylesheet" href="../styles.css">
9+
</head>
10+
<body>
11+
<script type="module" src="pmtiles.js"></script>
12+
</body>
13+
</html>

example/three/pmtiles.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { Scene, WebGLRenderer, PerspectiveCamera } from 'three';
2+
import {
3+
TilesRenderer,
4+
GlobeControls,
5+
} from '3d-tiles-renderer';
6+
import {
7+
UpdateOnChangePlugin,
8+
TilesFadePlugin,
9+
ImageOverlayPlugin,
10+
PMTilesOverlay,
11+
GeneratedSurfacePlugin,
12+
} from '3d-tiles-renderer/plugins';
13+
import GUI from 'three/addons/libs/lil-gui.module.min.js';
14+
15+
// Layer config for Protomaps v4 basemap — colors from the Protomaps "Light" theme
16+
const LAYERS = {
17+
earth: { enabled: true, fill: '#e2dfda', order: 0 },
18+
water: { enabled: true, fill: '#80deea', order: 1 },
19+
landcover: { enabled: true, fill: '#c4e7d2', order: 2 },
20+
landuse: { enabled: true, fill: '#cfddd5', order: 3 },
21+
natural: { enabled: true, fill: '#e2e0d7', order: 4 },
22+
buildings: { enabled: true, fill: '#cccccc', order: 5 },
23+
roads: { enabled: true, stroke: '#ebebeb', order: 6 },
24+
transit: { enabled: true, stroke: '#a7b1b3', order: 7 },
25+
boundaries: { enabled: true, stroke: '#adadad', order: 8 },
26+
places: { enabled: true, fill: '#5c5c5c', order: 9 },
27+
pois: { enabled: true, fill: '#1a8cbd', radius: 3, order: 10 },
28+
};
29+
30+
let scene, renderer, camera, controls, tiles, overlay;
31+
32+
init();
33+
render();
34+
35+
function init() {
36+
37+
renderer = new WebGLRenderer( { antialias: true } );
38+
renderer.setPixelRatio( window.devicePixelRatio );
39+
renderer.setSize( window.innerWidth, window.innerHeight );
40+
renderer.setClearColor( 0x111111 );
41+
renderer.setAnimationLoop( render );
42+
document.body.appendChild( renderer.domElement );
43+
44+
scene = new Scene();
45+
camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.001, 10000 );
46+
47+
// PMTiles overlay: vector tile data composited on top of the base geometry
48+
overlay = new PMTilesOverlay( {
49+
url: 'https://demo-bucket.protomaps.com/v4.pmtiles',
50+
getStyle,
51+
} );
52+
53+
// Base tile layer: XYZ raster tiles provide the globe geometry
54+
tiles = new TilesRenderer();
55+
tiles.registerPlugin( new UpdateOnChangePlugin() );
56+
tiles.registerPlugin( new TilesFadePlugin() );
57+
tiles.registerPlugin( new GeneratedSurfacePlugin( {
58+
center: true,
59+
shape: 'ellipsoid',
60+
} ) );
61+
tiles.registerPlugin( new ImageOverlayPlugin( {
62+
overlays: [ overlay ],
63+
renderer,
64+
} ) );
65+
66+
tiles.setCamera( camera );
67+
tiles.group.rotation.x = - Math.PI / 2;
68+
tiles.group.updateMatrixWorld();
69+
scene.add( tiles.group );
70+
71+
// Controls
72+
controls = new GlobeControls( scene, camera, renderer.domElement );
73+
controls.setEllipsoid( tiles.ellipsoid, tiles.group );
74+
controls.enableDamping = true;
75+
controls.camera.position.set( 0, 0, 1.5e7 );
76+
77+
window.addEventListener( 'resize', onWindowResize );
78+
79+
setupGUI();
80+
81+
}
82+
83+
function getStyle( layerName, properties ) {
84+
85+
if ( ! ( layerName in LAYERS ) ) return null;
86+
87+
const layer = LAYERS[ layerName ];
88+
return layer.enabled ? layer : null;
89+
90+
}
91+
92+
function updateOverlay() {
93+
94+
overlay.redraw();
95+
96+
}
97+
98+
function setupGUI() {
99+
100+
const gui = new GUI();
101+
102+
for ( const key in LAYERS ) {
103+
104+
const folder = gui.addFolder( key.charAt( 0 ).toUpperCase() + key.slice( 1 ) );
105+
folder.add( LAYERS[ key ], 'enabled' ).onChange( updateOverlay );
106+
folder.addColor( LAYERS[ key ], LAYERS[ key ].fill !== undefined ? 'fill' : 'stroke' ).onChange( updateOverlay );
107+
folder.close();
108+
109+
}
110+
111+
}
112+
113+
function onWindowResize() {
114+
115+
camera.aspect = window.innerWidth / window.innerHeight;
116+
camera.updateProjectionMatrix();
117+
renderer.setSize( window.innerWidth, window.innerHeight );
118+
119+
}
120+
121+
function render() {
122+
123+
controls.update();
124+
125+
camera.updateMatrixWorld();
126+
tiles.setCamera( camera );
127+
tiles.setResolutionFromRenderer( camera, renderer );
128+
tiles.update();
129+
130+
renderer.render( scene, camera );
131+
132+
}

package-lock.json

Lines changed: 81 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"license": "Apache-2.0",
8484
"devDependencies": {
8585
"@babel/preset-modules": "^0.1.6",
86+
"@mapbox/vector-tile": "^2.0.3",
8687
"@babel/preset-react": "^7.26.3",
8788
"@babel/preset-typescript": "^7.26.0",
8889
"@babylonjs/core": "^8.47.2",
@@ -107,6 +108,8 @@
107108
"jsdoc": "^4.0.5",
108109
"leva": "^0.10.0",
109110
"lil-gui": "^0.21.0",
111+
"pbf": "^4.0.1",
112+
"pmtiles": "^4.3.2",
110113
"postprocessing": "^6.36.4",
111114
"three": "^0.170.0",
112115
"typescript": "^5.6.0",
@@ -117,12 +120,18 @@
117120
"peerDependencies": {
118121
"@babylonjs/core": ">=8.0.0",
119122
"@babylonjs/loaders": ">=8.0.0",
123+
"@mapbox/vector-tile": "^2.0.3",
120124
"@react-three/fiber": "^8.17.9 || ^9.0.0",
125+
"pbf": "^4.0.1",
126+
"pmtiles": "^4.3.2",
121127
"react": "^18.3.1 || ^19.0.0",
122128
"react-dom": "^18.3.1 || ^19.0.0",
123129
"three": ">=0.167.0"
124130
},
125131
"peerDependenciesMeta": {
132+
"@mapbox/vector-tile": {
133+
"optional": true
134+
},
126135
"@react-three/fiber": {
127136
"optional": true
128137
},
@@ -132,6 +141,12 @@
132141
"@babylonjs/loaders": {
133142
"optional": true
134143
},
144+
"pbf": {
145+
"optional": true
146+
},
147+
"pmtiles": {
148+
"optional": true
149+
},
135150
"react": {
136151
"optional": true
137152
},

0 commit comments

Comments
 (0)