はじめに
この記事は MapLibre Advent Calendar 2023 20日目の記事です。
MapLibre GL JSは2.5次元のインタラクティブな地図を描画するライブラリですが、一方で、3Dのデータ表現が弱いというところがあります。そこで、便利な方法として、3Dのデータ表現に長けているdeck.glのレイヤーをMapLibre GL JSに組み込む方法を紹介したいと思います。具体には、3D都市モデルPLATEAU 3D Tilesや3次元点群データをdeck.glのTile3DLayerを用いて、MapLibre GL JSにレイヤーとして組み込む方法について紹介します。
MapLibre GL JSにdeck.glレイヤーを組み込む方法
MapLibre GL JSにdeck.glレイヤーを組み込む方法には主に3つの方法があるようです。詳細については、下記の記事に詳しく書かれています。
1. MapboxOverlayを使ったオーバーレイ
2. MapboxOverlayを使ったインターリーブ
3. MapboxLayerを使ったインターリーブ
上記の記事の中で紹介されている、3つの方法におけるオーバーレイ、インターリーブの違いはこちらのページの図がわかりやすいです。
オーバーレイは、2つのライブラリが相互に独立してレンダリングする仕様のようで、2Dマップに適しているようです。一方で、インターリーブは、deck.glのレイヤーとMapLibre GL JSのレイヤーのオクルージョン(手前にある物体が後ろにある物体を隠す状態)が可能になるようで、3Dマップに適しているようです。
今回は、上記の記事で紹介されている方法のうち、deck.glのMapboxLayerを使ったインターリーブを使用して、MapLibre GL JSで3D都市モデルPLATEAU 3D Tilesや3次元点群データを表示します。
なお、3つの方法については、下記の記事でもGoogle Photorealistic 3D Tilesを用いて、MapLibre GL JSにdeck.glレイヤーを組み込む方法を試しているのであわせてご覧ください。
3D都市モデルPLATEAU 3D TilesをMapLibre GL JSで表示する
3D都市モデルPLATEAU 3D Tilesをdeck.glのTile3DLayerを用いて、MapLibre GL JSにレイヤーとして組み込みます。
デモサイト
東京駅周辺
ソースコードと解説
- 全体のソースコードは、下記のGitHubから入手してください。
- 解説は下記のとおりになります。
- 3D Tilesのローダーには、loaders.glのTiles3DLoaderを使用します。
<html>
<head>
<title>3D都市モデルPLATEAU(3D Tiles)</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css" rel="stylesheet">
<script src="https://unpkg.com/pmtiles@2.10.0/dist/index.js"></script>
<script src="https://unpkg.com/deck.gl@8.9.0/dist.min.js"></script>
<script src="https://unpkg.com/@loaders.gl/3d-tiles@^2.3.0/dist/dist.min.js"></script>
-
MapboxLayer
で3D都市モデルPLATEAU 3D Tilesを定義します。 -
loader
にTiles3DLoader
を指定します。 -
data
に3D都市モデルPLATEAU 3D TilesのURL(tileset.jsonのURL)を指定します。 - 3D Tilesの配信URLは下記より確認できます。
今回、3D都市モデルPLATEAU 3D Tilesは2021年度末時点で公開されている3D Tilesデータを使用しています。今回の方法で最新の3D Tilesデータ(2022年度末時点)を使用すると3Dモデルが表示されませんでした。ちなみに、QGIS3.34で3D Tilesを読み込めるようになりましたが、最新の3D Tilesデータは表示できませんでした。現時点の最新の3D Tilesデータは下記になります。
https://github.com/Project-PLATEAU/plateau-streaming-tutorial/blob/main/3d-tiles/plateau-3dtiles-streaming.md
-
onTileLoad
以下は、3Dモデルの高さをマップ平面に合うようにするための調整です。 - 詳細については、下記の記事が詳しいです。
- 最終的に、
content.cartographicOrigin.z
で建築物の基礎の標高に加えて東京駅付近のジオイド高 36.6641m を引いて、3Dモデルの高さをマップ平面に合うように調整しています。 -
map.addLayer(tile3dLayer)
で3D都市モデルPLATEAU 3D Tilesレイヤを追加します。
map.on('load', () => {
// MapboxLayerを使ったインターリーブ
const tile3dLayer = new deck.MapboxLayer({
id: '13101_chiyoda-ku',
type: deck.Tile3DLayer,
// 3D都市モデルPLATEAU 3DTilesソース
data: 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13101_chiyoda-ku/low_resolution/tileset.json', // 千代田区
loader: Tiles3DLoader,
opacity: 1,
// 【参考】https://nagix.hatenablog.com/entry/2022/12/27/203825
onTileLoad: d => {
const { content } = d;
const buffer = content.batchTableBinary.buffer;
const key = content.batchTableJson;
const len = key._gml_id.length;
const zMinView = new DataView(buffer, key._zmin.byteOffset, len * 8);
const zMins = [];
for (let i = 0; i < len; i++) {
zMins.push(zMinView.getFloat64(i * 8, true));
}
zMins.sort((a, b) => a - b);
content.cartographicOrigin.z -= 36.6641 + zMins[Math.floor(len / 2)];
}
});
// 3D都市モデルPLATEAU 3DTilesレイヤ
map.addLayer(tile3dLayer);
})
3次元点群データ(3D Tiles)をMapLibre GL JSで表示する
3次元点群データをdeck.glのTile3DLayerを用いて、MapLibre GL JSにレイヤーとして組み込みます。
長崎県がオープンデータとして公開している3次元点群データ(LAS形式)から3D Tilesを生成して、MapLibre GL JS+deck.glで表示しています。3次元点群データから3D Tilesを生成する方法については、Zennで記事を書いていますので、あわせてご覧ください。
デモサイト
長崎駅周辺
ソースコードと解説
- 全体のソースコードは、下記のGitHubから入手してください。
- 解説は下記のとおりになります。
- 3D Tilesのローダーには、loaders.glのTiles3DLoaderを使用します。
<html>
<head>
<title>長崎県 3次元点群データ(3DTiles)</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src='https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css' rel='stylesheet' />
<script src="https://unpkg.com/pmtiles@2.10.0/dist/index.js"></script>
<script src="https://unpkg.com/deck.gl@8.9.0/dist.min.js"></script>
<script src="https://unpkg.com/@loaders.gl/3d-tiles@^2.3.0/dist/dist.min.js"></script>
-
MapboxLayer
で3次元点群データ(3D Tiles)を定義します。 -
data
に3次元点群データ(3D Tiles)のURL(tileset.jsonのURL)を指定します。 -
loader
にTiles3DLoader
を指定します。 -
map.addLayer(tile3dLayer)
でレイヤを追加します。
map.on('load', () => {
// MapboxLayerを使ったインターリーブ
const tile3dLayer = new deck.MapboxLayer({
id: "nagasaki-station",
type: deck.Tile3DLayer,
pointSize: 2,
// 3次元点群データ(3DTiles)ソース
data: 'https://xs489works.xsrv.jp/3dtiles/open_nagasaki/nagasaki_station/tileset.json',
loader: Tiles3DLoader
});
// 3次元点群データ(3DTiles)レイヤ
map.addLayer(tile3dLayer);
})
参考文献
おわりに
MapLibre GL JSにdeck.glのレイヤーを組み込む方法についてご紹介しました。deck.glのTile3DLayerをMapLibre GL JSにレイヤとして組み込むことで、MapLibre GL JSで3D都市モデルPLATEAU 3D Tilesや3次元点群データ(3D Tiles)を表示することができます。deck.glには、Tile3DLayer以外にも可視化のための様々なレイヤーが用意されています。例えば、地点間の繋がりを3Dの弧で表現できるArcLayerやデータをヘキサゴン(六角形)で集約してヒートマップとして表現できるHexagonLayerなど表現力の高いレイヤーを利用することもできます。