deck.glのTile3dLayerでPLATEAUの3D都市モデルを表示してみた


はじめに

今話題のPLATEAUのデータをdeck.gl+Mapbox GL JSで表示してみるぞ!

Tile3dLayer

みんな大好きdeck.glにTile3dLayerというクラスがあり、これはいわゆる3d-tilesを読むためのレイヤーです。

点群でも3Dモデルでも、3d-tilesならこのレイヤーで表示する事が出来ます(一応Experimentalです)。以下のように定義します。


import { Tile3DLayer } from '@deck.gl/geo-layers';
import { Tiles3DLoader } from '@loaders.gl/3d-tiles';

const tile3dLayer = new Tile3DLayer({
    id: 'tile3dlayer',
    pointSize: 1,
    data: 'https://s3-ap-northeast-1.amazonaws.com/3dimension.jp/13000_tokyo-egm96/13101_chiyoda-ku_notexture/tileset.json', // PLATEAU千代田区
    loader: Tiles3DLoader,
    onTilesetLoad: (tileset) => {
        const { cartographicCenter } = tileset;
        const [longitude, latitude] = cartographicCenter;
        console.log(longitude, latitude); // 3dtilesの中心座標を取れるぞ
    },
});

Mapbox GL JS上に表示してみる

deck.glレイヤーをMapbox GL JS上で表示する手法はhttps://deck.gl/docs/api-reference/mapbox/mapbox-layerを見ればわかります。

表示は出来ましたがなんかモデルが宙に浮いています(静止画像なのでわかりにくいですがかなり浮いています)。

モデルが浮く問題

PLATEAU-Viewをみてみると、モデルは標高とリンクしている事がわかります。おそらく標高と建物は同時に計測されているのかと思われます。

Mapbox GL JSは基本的に平面地図で標高はゼロです(v2なら3D表現ができるが…)。仮に3Dだとしても、PLATEAUで使われている標高データはすぐウェブで使える形式では公開されていないので、やはり基準の標高値がゼロでも、マシな見た目にする事を考えた方がいいでしょう。つまり全体の高度を一律に下げる事を考えます。

標高データはCityGMLで公開されていて中身をみる限りTINなので、何かしらウェブで使える標高データに変換する方法はあるでしょう

高度を調整してみた

さっきのtile3dLayerにオプションを追加します。


import { Tile3DLayer } from '@deck.gl/geo-layers';
import { Tiles3DLoader } from '@loaders.gl/3d-tiles';
import { Vector3 } from 'math.gl';

const tile3dLayer = new Tile3DLayer({
    id: 'tile3dlayer',
    pointSize: 1,
    data: 'https://s3-ap-northeast-1.amazonaws.com/3dimension.jp/13000_tokyo-egm96/13101_chiyoda-ku_notexture/tileset.json',
    loader: Tiles3DLoader,
    onTilesetLoad: (tileset) => {
        const { cartographicCenter } = tileset;
        const [longitude, latitude] = cartographicCenter;
        console.log(longitude, latitude);
    },
    onTileLoad: (tileHeader) => {
        tileHeader.content.cartographicOrigin = new Vector3(
            tileHeader.content.cartographicOrigin.x,
            tileHeader.content.cartographicOrigin.y,
            tileHeader.content.cartographicOrigin.z - 40,
        );
    },
});

タイル単位で保持しているらしい基準標高値を、一律40m下げました。

さっきよりも地に足のついた見た目になりましたね。

終わりに

3Dデータを表示するなら素直にCesium使っておいた方が良い気がしていますが、ベクタータイルや2D地図表現はやはりMapbox GL JSの強みだと思います(最近では3D地形も表示出来ますし…)。