すべてを球の上に描く、ブラウザだけで動く地図エンジン(自前の地図サーバーを持たない)
@ortho-earth/core · @ortho-earth/globe · WebGPU と WebGL2 · 実スケールの地形 · worker の流れ作業
ortho-map(v1:d3 の正射投影・層ごとに worker 1 本・WebGL2 のみ)の説明を置き換えたものです。
v1 は 2026 年 9 月に撤去しました。正射の地球・OffscreenCanvas・GeoPBF/AltPBF/Gint という考え方は引き継ぎ、実装は引き継いでいません。
部品は下にあるものほど硬く作っています(検定の関門・型定義・版で守る)。上のアプリは殻で、自由に変えてかまいません。 新しい仕事は、まず「どの層か」を言ってから書きます。
createGlobe() — 起動・世界帯・地域に依らないガジェット・SDK の型・関門
全体をつなぎとめる決まりは一つ:core と globe は国の名前を書かない。
機械の関門(verify:regionless)が globe のコードの地域の語を数え、増えたら落とします。
import の向きは一方通行で、japan → globe → core → ephem と japan → jp → core。globe と jp は互いを import しません。
両者が出会うのは、アプリが渡す申告の中だけです。
メインスレッドが持つのはカメラ・入力・DOM だけです。解読・組み立て・描画はすべて worker で動きます。
worker はすべて一つの入口(worker.js)から起動し、Worker の name で役割を指名します。
そのためバンドラが作る worker のビルドは一つで、共有する部品(GeoPBF の核・loaders.gl・シェーダ)は worker の数だけ複製されません。
draw {cam} を送る| 役割 | すること |
|---|---|
render | canvas の持ち主。地球・地形・基図のシーン・画像タイル・gint・注記・オーバーレイを、一つのフレーム・一つのカメラで描く |
ortho:tile / ortho:scene | タイルの取得と組み立て/シーンの結合(基図の流れ作業) |
mesh / meshdecoder | 大量の 3D メッシュ(建物)を流す — 解読・重複除去・接地・LOD・OPFS/IndexedDB への保存 |
model | glTF/GLB・押し出し・3D Tiles と I3S の中身。日影と可視域の計算も |
gintbake | gint の層を焼く(LOD の順位・辺)— 描画スレッドの外で |
ortho:height | 標高タイルの解読 |
rastertiles / imagequad | 手元の GeoPackage/MBTiles、または四隅で貼った画像から、画像タイルを配る |
decoder:* / encoder:* | GeoPBF の形式変換(落としたファイル・書き出し) |
地域パックは、ビルド時の空き枠を通して役割を足せます(日本は統計の worker を足す)。ホストはそれを知りません。
crossOriginIsolated は必須ではありません。あれば GeoPBF のバッファがコピー無しで worker へ渡り(SharedArrayBuffer)、
無ければ一度だけコピーされます。どちらでも全機能が動くことを関門(verify:nocoi)で確かめています。
core には同じ顔(set・draw・dispose)を持つ描画器が二つあります。WebGPU 版と WebGL2 版です。
render worker が起動時にどちらかを選びます。
| 条件 | 土台 |
|---|---|
?gl2=1 | WebGL2(手動の逃げ道) |
navigator.gpu が無い | WebGL2 に直行 |
| Android | WebGL2(一部のモバイル GPU ドライバで、黙って画面が黒くなる不具合があるため) |
| このタブで前回 WebGPU の起動に失敗した | WebGL2 |
| それ以外 | WebGPU |
WebGPU には三枚の落ち網があります。初期化に失敗したら worker の中で WebGL2 へ切り替える。 黙った失敗(初期化は通ったのに画面に何も出ない)は最初のフレームを読み戻して見つける。20 秒たってもフレームが来なければ WebGL2 で起動し直す。
画質のための仕組みが二つ、両方の土台で動きます。遷移時の AA:カメラが動いている間は MSAA 1× で描き、 約 0.5 秒止まったら 4× で一枚だけ描く。動的解像度:フレームが重くなると canvas の解像度を段階的に下げ、線の太さは画面上で変えない。
カメラは小さな素のオブジェクト(center・zoom・pitch・bearing)で、投影は 4×4 の行列一つです。
正射と透視は一続き:正射は、目を無限に遠ざけた透視です。投影は壁ではなくスライダーです。
?ell=1)。距離や面積の計測は常に楕円体で行います。flyTo・easeTo・fitBounds)は時間で評価する計画です。台本の再生は 1 歩 35 ms を上限とする仮想時計で進むので、遅い機械で録画してもずれません。
視点は URL にあります — #zoom/lat/lon[/45t][/-30r][/l=…][/c=テーマ][/t=UTC][/s=速さ]。アドレス欄はいつでも「いま見ているもの」へのリンクです。
標高は誇張せずに描きます。高さは AltPBF から:三つの解像度の 1° セルを worker で解読し、 二つの標高アトラスに詰めます — カメラの周りの細かいセルの近景アトラスと、地平線までの粗いセルの遠景アトラス。 シェーダは両方から一続きの高さの場を読みます。
raster-dem(Terrarium・Mapbox・地理院の形式)で、組み込みの標高を置き換えられます:map.setTerrain(…)。おおよそ z8 より下では、地球儀が自分で世界を描きます — Natural Earth 10 m の国・湖・川・海洋境界と、 全球の標高と気候の場から毎フレーム計算する段彩(画像タイルは一枚もダウンロードしない)。世界のデータが担えるのは正直ここまでです。
そこから上は地域が引き継ぎます。入場するズームは地域の申告が決めます(日本は z6.5 から地理院のベクタ基図)。 ベクタタイルは tile と scene の worker を通ります。傾けた 3D の視点では、ズームアウトしても細かいタイルが地面を覆えている間は、粗いタイルに差し替えません。
画像タイル(XYZ・WMS・WMTS・PMTiles・手元の GeoPackage/MBTiles・四隅で貼る一枚の画像)は、まず地面のアトラスに合成し、
地形のシェーダがそのアトラスを画素ごとに引きます。だから画像は山の上に平らに乗るのではなく、斜面に沿います。
MapLibre の style.json も同じ流れに変換して読みます(map.setStyle)。
タイルは描くため、Gint は知るためにあります。Gint の層は GeoPBF の幾何を丸ごと GPU に持つので、 どの地物も選び・強調し・表と突き合わせられます。
一つのメッシュの核が、あらゆる 3D データを流します。核は建物がどの国のものかを知りません。地域が申告するのはデータの在り処だけです。
| データ | 入り方 |
|---|---|
| 都市の建物(日本の PLATEAU・オランダの 3DBAG) | 地域パックが申告する区ごとの読み込み |
| 任意の 3D Tiles | map.add3DTiles(url) — 画面上の誤差で辿る・b3dm/i3dm/pnts/cmpt/glb |
| I3S のシーンレイヤ | map.addI3S(url) — loaders.gl で解読 |
| glTF/GLB の模型 | ファイルを落とす・?g= のリンク |
道はどれも同じです:解読(Draco を含む)→ 地心座標 → 正射の球 → 重複面の除去 → 地形への接地 → LOD → 原点相対の頂点 → 基図の平らな建物の輪郭を下で隠す被覆マスク。 解読した区は GPU がそのまま食える形で OPFS と IndexedDB に置くので、二度目はディスクから GPU へ直行します。
おおよそ z5 より下では空が見えます:実在の星・惑星と月・星座・黄道と天の赤道・夜の側。さらに引くと、実スケールの太陽系へ入っていきます。
これらはすべて一つの時計に従います(map.clock・@ortho-earth/ephem — 太陽系アプリと同じ時計)。
既定は実時間で、止める・早送り・巻き戻し・1800〜2049 年の任意の時刻に合わせることができます。
太陽直下点と恒星時は両アプリで同じ式から出すので、夜の側・星・人工衛星はいつも一致します。
時計は render worker に一つの基準 {sim, wall, rate} として渡り、状態が変わった時にだけ送られます。
import { createGlobe } from "@ortho-earth/globe";
const map = await createGlobe({ target: "#map", view: "#3/20/140" });
map.flyTo({ center: [139.767, 35.681], zoom: 14, pitch: 60 });
| 分野 | 例 |
|---|---|
| カメラ | jumpTo · easeTo · flyTo · fitBounds · cameraForBounds · setMaxBounds |
| スタイルと層 | setStyle · addSource / addLayer · setPaintProperty · setFilter · queryRenderedFeatures |
| 3D と地形 | add3DTiles · addI3S · setTerrain · 押し出し · 模型 |
| 解析 | sunShadow · viewshed · lineOfSight · 断面 · 計測 |
| 時間 | map.clock · map.on("time") |
| 拡張 | map.overlay(module) — 自前の canvas を render worker の中で同じフレーム・同じカメラ・api.time 付きで描く · addProtocol · transformRequest · Marker / Popup |
API の形は、できる所は MapLibre に合わせています。既存のスタイルや手癖がそのまま使えます。 上のすべては、公開パッケージそのものから頁を起動する関門で検めています — 検めたものが、インストールするものです。