/ @ortho-earth/core

ortho-earth エンジン — 技術概要

すべてを球の上に描く、ブラウザだけで動く地図エンジン(自前の地図サーバーを持たない)
@ortho-earth/core · @ortho-earth/globe · WebGPU と WebGL2 · 実スケールの地形 · worker の流れ作業

目次
  1. 四つの層 — コアは硬く、アプリは柔らかく
  2. スレッドと worker
  3. 描画の土台 — WebGPU を先に、WebGL2 はいつでも
  4. カメラ・投影・ズーム
  5. 実スケールの地形
  6. 基図・画像タイル・世界帯
  7. Gint — 問いに答えるベクタ
  8. 3D メッシュ — 建物・3D Tiles・I3S・模型
  9. 空と共通の時計
  10. 公開面
経緯
このページは、最初のエンジン ortho-map(v1:d3 の正射投影・層ごとに worker 1 本・WebGL2 のみ)の説明を置き換えたものです。 v1 は 2026 年 9 月に撤去しました。正射の地球・OffscreenCanvas・GeoPBF/AltPBF/Gint という考え方は引き継ぎ、実装は引き継いでいません。

1. 四つの層 — コアは硬く、アプリは柔らかく

部品は下にあるものほど硬く作っています(検定の関門・型定義・版で守る)。上のアプリは殻で、自由に変えてかまいません。 新しい仕事は、まず「どの層か」を言ってから書きます。

apps apps/* 殻 — japan・world・equal・census2020・solar・globe の頁 … それぞれがエンジンを自分のビルドに束ねる
↓ opts.region(コードではなく申告)
region pack @ortho-earth/jp 一つの国が知っていること:基図・標高・建物・検索・POI・出典・初期視点
↓
host @ortho-earth/globe createGlobe() — 起動・世界帯・地域に依らないガジェット・SDK の型・関門
↓
core @ortho-earth/core 描画・カメラ・投影・地形・画像タイル・注記・gint・オーバーレイの契約 — 地域を知らない
↓
foundation geopbf · altpbf · ephem ベクタの形式(MIT)・標高タイル(MIT)・時計と空

全体をつなぎとめる決まりは一つ:core と globe は国の名前を書かない。 機械の関門(verify:regionless)が globe のコードの地域の語を数え、増えたら落とします。 import の向きは一方通行で、japan → globe → core → ephem と japan → jp → core。globe と jp は互いを import しません。 両者が出会うのは、アプリが渡す申告の中だけです。

2. スレッドと worker

メインスレッドが持つのはカメラ・入力・DOM だけです。解読・組み立て・描画はすべて worker で動きます。 worker はすべて一つの入口(worker.js)から起動し、Worker の name で役割を指名します。 そのためバンドラが作る worker のビルドは一つで、共有する部品(GeoPBF の核・loaders.gl・シェーダ)は worker の数だけ複製されません。

1main
カメラ・入力・飛行・ガジェット(DOM)・時計 · draw {cam} を送る
↓
2tile workers
取得・MVT の解読・三角形化・描画リスト(コピーでなく受け渡し)
↓
3scene worker
見えているタイルを一つのシーンに結合
↓
4render worker
OffscreenCanvas・地形・画像タイル・gint・注記・同一フレームのオーバーレイ — 一つの rAF で
役割すること
rendercanvas の持ち主。地球・地形・基図のシーン・画像タイル・gint・注記・オーバーレイを、一つのフレーム・一つのカメラで描く
ortho:tile / ortho:sceneタイルの取得と組み立て/シーンの結合(基図の流れ作業)
mesh / meshdecoder大量の 3D メッシュ(建物)を流す — 解読・重複除去・接地・LOD・OPFS/IndexedDB への保存
modelglTF/GLB・押し出し・3D Tiles と I3S の中身。日影と可視域の計算も
gintbakegint の層を焼く(LOD の順位・辺)— 描画スレッドの外で
ortho:height標高タイルの解読
rastertiles / imagequad手元の GeoPackage/MBTiles、または四隅で貼った画像から、画像タイルを配る
decoder:* / encoder:*GeoPBF の形式変換(落としたファイル・書き出し)

地域パックは、ビルド時の空き枠を通して役割を足せます(日本は統計の worker を足す)。ホストはそれを知りません。 crossOriginIsolated は必須ではありません。あれば GeoPBF のバッファがコピー無しで worker へ渡り(SharedArrayBuffer)、 無ければ一度だけコピーされます。どちらでも全機能が動くことを関門(verify:nocoi)で確かめています。

3. 描画の土台 — WebGPU を先に、WebGL2 はいつでも

core には同じ顔(set・draw・dispose)を持つ描画器が二つあります。WebGPU 版と WebGL2 版です。 render worker が起動時にどちらかを選びます。

条件土台
?gl2=1WebGL2(手動の逃げ道)
navigator.gpu が無いWebGL2 に直行
AndroidWebGL2(一部のモバイル GPU ドライバで、黙って画面が黒くなる不具合があるため)
このタブで前回 WebGPU の起動に失敗したWebGL2
それ以外WebGPU

WebGPU には三枚の落ち網があります。初期化に失敗したら worker の中で WebGL2 へ切り替える。 黙った失敗(初期化は通ったのに画面に何も出ない)は最初のフレームを読み戻して見つける。20 秒たってもフレームが来なければ WebGL2 で起動し直す。

画質のための仕組みが二つ、両方の土台で動きます。遷移時の AA:カメラが動いている間は MSAA 1× で描き、 約 0.5 秒止まったら 4× で一枚だけ描く。動的解像度:フレームが重くなると canvas の解像度を段階的に下げ、線の太さは画面上で変えない。

4. カメラ・投影・ズーム

カメラは小さな素のオブジェクト(center・zoom・pitch・bearing)で、投影は 4×4 の行列一つです。 正射と透視は一続き:正射は、目を無限に遠ざけた透視です。投影は壁ではなくスライダーです。

視点は URL にあります — #zoom/lat/lon[/45t][/-30r][/l=…][/c=テーマ][/t=UTC][/s=速さ]。アドレス欄はいつでも「いま見ているもの」へのリンクです。

5. 実スケールの地形

標高は誇張せずに描きます。高さは AltPBF から:三つの解像度の 1° セルを worker で解読し、 二つの標高アトラスに詰めます — カメラの周りの細かいセルの近景アトラスと、地平線までの粗いセルの遠景アトラス。 シェーダは両方から一続きの高さの場を読みます。

6. 基図・画像タイル・世界帯

おおよそ z8 より下では、地球儀が自分で世界を描きます — Natural Earth 10 m の国・湖・川・海洋境界と、 全球の標高と気候の場から毎フレーム計算する段彩(画像タイルは一枚もダウンロードしない)。世界のデータが担えるのは正直ここまでです。

そこから上は地域が引き継ぎます。入場するズームは地域の申告が決めます(日本は z6.5 から地理院のベクタ基図)。 ベクタタイルは tile と scene の worker を通ります。傾けた 3D の視点では、ズームアウトしても細かいタイルが地面を覆えている間は、粗いタイルに差し替えません。

画像タイル(XYZ・WMS・WMTS・PMTiles・手元の GeoPackage/MBTiles・四隅で貼る一枚の画像)は、まず地面のアトラスに合成し、 地形のシェーダがそのアトラスを画素ごとに引きます。だから画像は山の上に平らに乗るのではなく、斜面に沿います。 MapLibre の style.json も同じ流れに変換して読みます(map.setStyle)。

7. Gint — 問いに答えるベクタ

タイルは描くため、Gint は知るためにあります。Gint の層は GeoPBF の幾何を丸ごと GPU に持つので、 どの地物も選び・強調し・表と突き合わせられます。

8. 3D メッシュ — 建物・3D Tiles・I3S・模型

一つのメッシュの核が、あらゆる 3D データを流します。核は建物がどの国のものかを知りません。地域が申告するのはデータの在り処だけです。

データ入り方
都市の建物(日本の PLATEAU・オランダの 3DBAG)地域パックが申告する区ごとの読み込み
任意の 3D Tilesmap.add3DTiles(url) — 画面上の誤差で辿る・b3dm/i3dm/pnts/cmpt/glb
I3S のシーンレイヤmap.addI3S(url) — loaders.gl で解読
glTF/GLB の模型ファイルを落とす・?g= のリンク

道はどれも同じです:解読(Draco を含む)→ 地心座標 → 正射の球 → 重複面の除去 → 地形への接地 → LOD → 原点相対の頂点 → 基図の平らな建物の輪郭を下で隠す被覆マスク。 解読した区は GPU がそのまま食える形で OPFS と IndexedDB に置くので、二度目はディスクから GPU へ直行します。

9. 空と共通の時計

おおよそ z5 より下では空が見えます:実在の星・惑星と月・星座・黄道と天の赤道・夜の側。さらに引くと、実スケールの太陽系へ入っていきます。

これらはすべて一つの時計に従います(map.clock・@ortho-earth/ephem — 太陽系アプリと同じ時計)。 既定は実時間で、止める・早送り・巻き戻し・1800〜2049 年の任意の時刻に合わせることができます。 太陽直下点と恒星時は両アプリで同じ式から出すので、夜の側・星・人工衛星はいつも一致します。 時計は render worker に一つの基準 {sim, wall, rate} として渡り、状態が変わった時にだけ送られます。

10. 公開面

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 に合わせています。既存のスタイルや手癖がそのまま使えます。 上のすべては、公開パッケージそのものから頁を起動する関門で検めています — 検めたものが、インストールするものです。

@ortho-earth/core · @ortho-earth/globe · GPL-3.0 · Kenji Yoshida · 2026