MapLibre GL JS custom layer that procedurally decorates buildings (windows, interiors, night lights, reflections, rooftops, weathering) from PLATEAU 3D Tiles
翻訳待ち
プラグインTypeScript · JavaScriptGitHub @hshntmkオンライン所有者未確認
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗建物のフットプリントと属性から外観を手続き的に作る、MapLibre GL JS のカスタムレイヤーです。PLATEAU の 3D Tiles(LOD1)を直接読み込めます。
PLATEAU の LOD1 の建物は押し出した箱なので、そのまま地図に載せると同じような箱が並びます。このライブラリは、建物の用途・階数と形、隣の建物との距離から、窓や屋根などの外観を決めて描きます。見た目は建物の種類ごとのスタイルで変えられます。
デモ: https://hshntmk.github.io/maplibre-facades/ (東京 23 区と札幌・仙台・新潟・大阪・広島・福岡の PLATEAU の 3D Tiles を直接読みます)
試作(0.x)の段階で、API は変わることがあります。動作は maplibre-gl 6.12 で確かめています。
npm にはまだ公開していないので、リポジトリからビルドします。
git clone https://github.com/hshntmk/maplibre-facades.git
cd maplibre-facades
npm install
npm run build # dist/ に本体・Worker・型定義を出力
利用側のプロジェクトでは、ローカルのパスを指定してインストールします。
npm install ../maplibre-facades maplibre-gl
maplibre-gl(5.x / 6.x)は peerDependency です。WebGL2 が必要です。
import { Map } from 'maplibre-gl';
import { BuildingFacadeLayer } from 'maplibre-facades';
const map = new Map({ container: 'map', style: '...', center: [139.7652, 35.6812], zoom: 16, pitch: 60 });
const layer = new BuildingFacadeLayer({
id: 'facades',
// PLATEAU の 3D Tiles(LOD1)の tileset.json。表示範囲のタイルだけ読む。複数の区は配列で渡す
source: { type: '3dtiles', url: 'https://assets.cms.plateau.reearth.io/.../13101_chiyoda-ku_lod1/tileset.json' },
timeOfDay: 20,
});
layer.on('load', ({ stats }) => console.log(`${stats.total} buildings`));
layer.on('error', ({ error }) => console.error(error.code, error.message));
map.on('load', () => map.addLayer(layer));
設定の誤りは、コンストラクタと set* メソッドが BuildingFacadeLayerError(code: 'options')を投げます。読み込み後のエラーは error イベントで届き、リスナーがなければ console.error に出ます。
時刻や効果は、作ったあとでも変えられます。変えてもデータは読み直しません。
layer.setTimeOfDay(6.5);
layer.setRoof({ equipment: { density: 0.3 } }); // 指定した項目だけ変わる
layer.setWeathering(false);
すべてのオプション・メソッド・イベント・スタイルの項目は リファレンスマニュアル にあります。
主なオプションです。
| オプション | 既定値 | 内容 |
|---|---|---|
source | (必須) | { type: '3dtiles', url } または { type: 'geojson', url } |
adapter | { name: 'plateau' } | 属性を共通モデルに変換する方法。PLATEAU 以外は { name: 'declarative', spec } で JSON のまま書く |
styles / styleRules | PRESET_STYLES / DEFAULT_STYLE_RULES | 建物の見た目(最大 16 種類)と、どの建物にどれを使うか(MapLibre の式) |
timeOfDay | 20 | 時刻(0–24)。太陽・空の色・点灯率が変わる |
effects | true | false で窓などを描かず、単色の箱にする |
interior | true | 窓の奥の部屋(インテリアマッピング) |
reflection | 1 | ガラスの反射の強さ(0–3) |
roof | すべて ON | パラペット・屋上の仕上げ・屋上設備・航空障害灯 |
weathering | ON | 外壁の雨だれ・くすみ・しみ |
surfaceDetail | ON | 外壁の素材(タイル・コンクリート・石・金属)の凹凸とつや、ガラスの歪み |
balconies | true | 共同住宅のバルコニーを立体で描く |
solidFixtures | false | 1 階の庇・テント・突き出し看板を立体で描く |
vegetation / season | true / 'summer' | 植生の木を描く / 木の季節(春は桜、秋は紅葉、冬は落葉) |
trafficSignals / streetLights / roadSigns / roadMarkings | すべて true | 都市設備の信号機・街灯・道路標識・路面標示を描く。信号の灯色は時間とともに変わり、街灯は夜に路面を照らす |
terrain / fog | true / true | MapLibre の地形に建物を載せる / sky の霞を建物にもかける |
workers | CPU のコア数の半分(1〜4) | 3D Tiles の処理に使う Worker の数 |
3D Tiles のソースには次のオプションがあります。
| オプション | 既定値 | 内容 |
|---|---|---|
maximumScreenSpaceError | 16 | 詳細なタイルに切り替える画面上の誤差(px)。広い範囲を見渡すなら 32〜64 にすると読み込み量が減る |
maxCachedTiles | 48 | 表示していないタイルを保持しておく数 |
cache | { maxSizeMB: 200, maxAgeDays: 2 } | 展開したタイルをブラウザ(IndexedDB)に保存し、次からはダウンロードを省く。false で保存しない |
dracoWasmUrl | jsDelivr の [email protected]/draco_decoder.wasm | Draco の展開に使う wasm。外部の CDN を使えない環境では自分で置いて指定する |
vegetation | なし | PLATEAU の植生モデル(LOD1)の tileset.json。単独木と植被を木として描く |
cityFurniture | なし | PLATEAU の都市設備モデル(LOD1)の tileset.json。信号機・街灯・道路標識・路面標示を描く |
建物の種類ごとの見た目(窓の間隔、外壁の色の候補、1 階の構成、勾配屋根の割合など)は、スタイルを上書きして変えます。
import { BuildingFacadeLayer, PRESET_STYLES, DEFAULT_STYLE_RULES } from 'maplibre-facades';
new BuildingFacadeLayer({
id: 'facades',
source,
styles: {
...PRESET_STYLES,
office: { ...PRESET_STYLES.office, wallMaterials: { stone: 0.5, metal: 0.3 }, warmRatio: 0.3 },
},
styleRules: [{ when: ['>=', ['get', 'height'], 100], style: 'curtainWall' }, ...DEFAULT_STYLE_RULES],
});
Worker は既定でバンドルに埋め込まれていて(Blob URL)、バンドラの設定は要りません。CSP で blob: の Worker が許可されていない場合は、同梱の maplibre-facades/worker を置いて URL を指定します。
import { setWorkerUrl } from 'maplibre-facades';
import workerUrl from 'maplibre-facades/worker?url'; // Vite の場合
setWorkerUrl(workerUrl); // レイヤーごとに指定するなら options.workerUrl
maplibre-gl v6 を Vite で本番ビルドすると、MapLibre 自身の Worker が出力されず、地図が起動しないことがあります。これは本ライブラリとは別の問題で、MapLibre の Worker の URL を次のように指定すると直ります。
import { setWorkerUrl } from 'maplibre-gl';
import mapLibreWorkerUrl from 'maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url';
setWorkerUrl(mapLibreWorkerUrl);
schemaUri)と、暗黙的タイリングの S2 の範囲は読めません。3D Tiles を直接読む場合は不要です。オフラインで使う場合や、全体を一度に読みたい場合は、PLATEAU の建築物モデル(LOD1 の 3D Tiles)から、フットプリントと属性を持つ GeoJSON を作れます。
npm run prepare-data -- 13101_bldg_lod1 --out ./public/data
データセット ID は PLATEAU データカタログ API の id です(13101_bldg_lod1 は千代田区)。取得した元データは data/raw/ に保存されます。
npm install
npm run dev # デモ(examples/chiyoda)を http://localhost:5180 で起動
npm test
npm run typecheck
npm run build # dist/index.js, dist/worker.js, dist/types/
npm run demo:build # デモを examples/chiyoda/dist に出力
処理は、取得(Source)→ 属性の変換(Adapter)→ 欠損の補完(Enricher)→ 見た目の選択(StyleResolver)→ メッシュの生成の順で Worker の中で進み、メインスレッドはタイルの選択と WebGL2 での描画だけをします。窓・室内・点灯は、壁 1 辺を 1 枚の四角形にして、フラグメントシェーダで描いています。
| パス | 内容 |
|---|---|
src/layer/ | BuildingFacadeLayer、イベント、設定の検証 |
src/sources/ | GeoJSON と 3D Tiles(タイルの選択、b3dm / glb の解析、フットプリントの復元) |
src/adapters/ | PLATEAU と宣言的アダプタ |
src/style/ | スタイルの定義、プリセット、選択ルール |
src/mesh/ | 壁面の解析、壁・屋根・バルコニー・1 階の部材・勾配屋根のメッシュ、植生の木と都市設備 |
src/render/ | シェーダ |
src/worker/ | Worker 本体、パイプライン、タイルの保存(IndexedDB) |
examples/chiyoda/ | デモ |