フリーダムの日記

GIS(地理情報システム)を中心に技術的なことを書いています。

deck.gl で I3S (シーン サービス) を使用してみる

はじめに

今回は、deck.gl がサポートしている OGCI3S を使用した例を紹介したいと思います。

f:id:freedom0625:20200704225838p:plain

以前に紹介した記事「ArcGIS API for JavaScript で deck.gl を利用してみる」の中で、deck.gl が提供している Tile3DLayer に OGC の I3S がサポートされたことに触れました。今回は、I3S の紹介と deck.gl がサポートしている I3S についてサンプルアプリとともに紹介したいと思います。

freedom-tech.hatenablog.com

作成したサンプルアプリでは東京駅周辺の建物を表示しました。

使用したデータは、ESRI ジャパンが配信している以下のデータを使用しました。
https://www.arcgis.com/home/item.html?id=88d4fe21ea5f431d995eb8f45dd2e93cwww.arcgis.com

使用したサンプルアプリは以下の GitHub にも公開しています。 github.com

ソースは、Git でクローンして

npm install
npm start

で使用することができます。

また、

npm run build

でビルドすることもできます。

i3S とは

オープンスタンダートの Open Geospatial Consortium(OGC) にも準拠しており、3D GIS データを扱うための各種フォーマットをシーン サービスと呼ばれる I3S 形式で提供しています。

github.com

www.esrij.com

3D GIS で扱うデータは、2D で扱うデータとは違い、特殊なデータ形式が多く、Web などの各ブラウザやモバイルなどで配信する場合に最適化する必要があります。この I3S 形式を使用することで、データが最適化され、高パフォーマンスで配信することができます。

Esri が提供している I3S のデータ形式は、目的に応じてさまざまな形式で提供しています。

また、indexed 3D scene layer (I3S) の仕様と、シーン サービスの REST エンドポイントとして I3S リソースにアクセスするための仕様について、オープンフォーマットとして説明しています。

deck.gl の tile-3d-layer を使用

deck.gl で I3S が使用できるレイヤークラスは、Tile3DLayer で、その中で、実際にデータを呼び出している部分のライブラリとして、i3s-loader を使用しています。

deck.gl

loaders.gl

i3s-loader の API リファレンスを見ると「The I3SLoader is experimental. Currently only support I3S MeshPyramids data format.」とあり、残念ながらすべての I3S の形式をサポートしているわけではなく、I3S MeshPyramids data format のみをサポートしているとのことです。今のバージョンが v2.1 なので、今後のバージョンアップでサポートされるフォーマットが増えることを期待したいです。

ちなみに、MeshPyramids は、I3S のプロファイルで、サポートしているデータタイプとして、3D オブジェクト (3D objects) と 統合メッシュ (Integrated mesh) になります。今回使用したデータは、3D オブジェクト (3D objects) になります。

以下の表に、I3S Profile、I3Sコミュニティ仕様、OGC コミュニティ標準のそれぞれの関係図を示しています。

I3S Profile Supported Layer Types I3S community specification OGC I3S community standard
MeshPyramids 3D Object and Integrated Mesh 1.6 1.0
Points Point 1.6 1.0
PointClouds Point Cloud 2.0 1.1 (under adoption process)

詳細は、An OGC Community Standard も参照していただければと思います。

サンプルアプリの作成

サンプルアプリは、i3s-loader にも記載例をそのまま参考にしています。今回は、React を使用しました。
Tile3DLayer クラスを使用し、プロパティの data には、シーンサービスの REST のエンドポイントを指定し、loader には、i3s-loader を指定します。Callbacks 関数として、onTilesetLoadを指定します。こちらは、タイルがロードされた時に呼び出される関数です。

import React, {Component} from 'react';
import {render} from 'react-dom';

import {StaticMap} from 'react-map-gl';
import DeckGL from '@deck.gl/react';
import {MapController} from '@deck.gl/core';
import {Tile3DLayer} from '@deck.gl/geo-layers';
import {I3SLoader} from '@loaders.gl/i3s';

// How to get mapbox token https://docs.mapbox.com/help/how-mapbox-works/access-tokens/
const MAPBOX_TOKEN = 'pk.eyJ1IjoidmFsdWVjcmVhdGlvbiIsImEiOiJjanM0Z21xamQwNHRrM3lueXZrOHBxZmNmIn0.oF6cKsx1z4NzUNiJ7RTXNQ'; // add your Mapbox token here

const INITIAL_VIEW_STATE = {
  longitude: -120,
  latitude: 34,
  height: 600,
  width: 800,
  pitch: 45,
  maxPitch: 85,
  bearing: 0,
  minZoom: 2,
  maxZoom: 30,
  zoom: 14.5
};

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {viewState: INITIAL_VIEW_STATE};
  }

  _onTilesetLoad(tileset) {
    // update viewport to the tileset center
    const {zoom, cartographicCenter} = tileset;
    const [longitude, latitude] = cartographicCenter;

    const viewState = {
      ...this.state.viewState,
      zoom: zoom + 2.5,
      longitude,
      latitude
    };

    this.setState({viewState});
  }

  render() {
    const {viewState} = this.state;

    // construct Tile3DLayer to render I3S tileset
    const layer = new Tile3DLayer({
      id: 'tile-3d-layer',
      // Tileset entry point: Indexed 3D layer file url
      data: 'https://services.arcgis.com/wlVTGRSYTzAbjjiC/ArcGIS/rest/services/Tokyo_Building_MP/SceneServer/layers/0?f=pjson',
      loader: I3SLoader,
      onTilesetLoad: this._onTilesetLoad.bind(this)
    });

    return (
      <DeckGL
        layers={[layer]}
        viewState={viewState}
        controller={{type: MapController}}
        onViewStateChange={({viewState}) => {
          // update viewState when interacting with map
          this.setState({viewState});
        }}
      >
        <StaticMap
          mapStyle={'mapbox://styles/mapbox/streets-v11'}
          mapboxApiAccessToken={MAPBOX_TOKEN}
          preventStyleDiffing
        />
      </DeckGL>
    );
  }
}

export function renderToDOM(container) {
   render(<App />, container);
}

さいごに

今回は、前回紹介した「ArcGIS API for JavaScript で deck.gl を利用してみる」に続いて、deck.gl で Esri のサービスとして OGC にも準拠している I3S を使用した例について紹介しました。deck.gl で使用できる I3S のデータは幾つか公開されており、今回使用したデータ以外で確認したところ、うまく表示されないデータもあったりと、まだまだ不安定な状況みたいです。今後のバージョンアップに期待したいです。