やりたいこと
Mapbox GL JS、deck.glのような2.5次元表現ができるWebGISや、Cesium、iTownsといった3次元WebGIS上への3Dモデル配置の要望をよく聞くようになりました。
2020年4月に公開された国土交通データプラットフォームでも、Mapbox GL JS/deck.glを使用した点群データの表示が行われています。今後さらに事例は増えてくると思われます。
点群データの場合は、計測時の地理座標が付いてさえいれば、deck.glに単体のデータとして読み込むことや、3DTilesに変換した上で読み込むことができます。
一方、構造物の3DモデルをglTF、objで受け取った際は、地理座標はついていないし、方向はわからないし、苦労して単体のモデルを配置することになります。ジオリファレンスが必要なのですが、どういう手順が一番いいのか試行錯誤です。
特に迷うのが、3DTilesで扱いたい際にどうやって変換しようという点でした。
この記事は、適当な3Dモデルを強引に3DTilesに変換していい感じにdeck.glに配置してみたものです。たぶん、こんな方法じゃなく楽にできる方法があると思います。
BlenderGIS
インストール
まずは位置合わせを行いたいのですが、ここではBlenderのaddon「BlenderGIS」を使用します。
Blenderに各種GISフォーマットをインポートできたり、DEMを読み込み3D表示ができるのですが、ここでの目的はWEBメルカトル座標を定義して、GoogleMap等のWeb地図を読み込むことです。WEBメルカトル座標上で3Dモデルを配置します。
Install and usageを参考に、githubからソースのダウンロードを行い、addonへインストールします。
Quick startの2.に書かれていますが、「cache folder」を指定しておきます。また、「spatial reference systems」が「Web Mercator」になっていることも確認しておきましょう。
GoogleMap表示
インストールが完了すると、3Dビューウィンドウ上に「GIS」が追加されますので、「GIS」から「Web Geodata」→「Basemap」の順に選択を行います。
Source:Google
Layer:Map
を選択して「OK」をクリックします。
GoogleMapが表示されますので、ドラッグで移動、マウスホイールで拡大/縮小を行い、モデルを配置したい位置まで地図を移動します。移動が終わったら、「E」キーを押すことでtextured plane meshが作成されます。
この時に地図の中心とした位置の緯度経度は調べておきましょう。後で3DTilesに変換する際に、原点座標として使います。
objの位置合わせ
適当にfree素材のobjを配置してみます。CloudCompareで表示した例ですが、寸法も実寸にはなっていない建物の3Dモデルです。
このモデルは拡大したり、回転したり、移動したりして、なんとなく山頭火本店に合わせて配置してみます。
大体いいかなという位置に配置できたら、取り込んだtextured plane meshは削除した上で、建物モデルのみobjにexportしておきます。
obj23dtiles
インストール
objから3DTilesへの変換には、obj23dtilesを使用しました。メンテナンスされてないので注意が必要ですが、tileset.jsonまで作ってくれるので便利です。
インストール自体は、
npm install -g obj23dtiles
で完了です。
変換準備
BlenderGISで地図を切り出した際の中心緯度経度を、customTilesetOptions.jsonに記載しておきます。obj23dtilesで変換する際に、3Dモデルの原点座標(0,0)が緯度経度(ラジアン単位)でいくつかを与えます。
先ほど切り出した地図の場合、緯度:43.764783、経度:142.359914でしたので、これをラジアンに変換して記載します。
{
"longitude": 2.48464922215,
"latitude": 0.763839559769,
"transHeight": 0.0,
"region": true,
"box": false,
"sphere": false
}
変換
"Create a single tileset with .b3dm tile and custom tileset options"になるようにオプションを指定して、building.objを入力に3DTilesを作成します。
obj23dtiles -i ./building.obj --tileset -p ./customTilesetOptions.json
変換がうまくいくと、Batchedbuildingフォルダに、tileset.jsonとbuilding.b3dmが作成されます。
deck.glで表示
deck.glの3d-tilesサンプルを変更して表示
deck.glに3d-tiles表示のサンプルがあります。これを少しだけ変更します。
app.js内の_renderTile3DLayer()において、TILESET_URLは作成したtileset.jsonへのパスに、loaderとしてTiles3DLoaderを指定とします。
その他、実行まえに、
export MapboxAccessToken=<mapbox_access_token>
でmapboxのキーを設定することも忘れずに。
_renderTile3DLayer() {
return new Tile3DLayer({
id: 'tile-3d-layer',
pointSize: 2,
data: TILESET_URL,
loader: Tiles3DLoader,
loadOptions: {"_lighting": "pbr"},
onTilesetLoad: this._onTilesetLoad.bind(this)
});
}