メルマガはこちらから

PAGE
TOP

はじめてのWeb 3D GIS ハンズオン~3D都市モデルをJavaScriptで配置してみよう

PLATEAU AWARDの作品づくりの第一歩

特集
Project PLATEAU by MLIT

「GISでの3Dビジュアライゼーション」と題し、CesiumJSやWeb GIS初学者に向けて実施された「PLATEAU Hands-on 02」の模様がYouTubeで公開されました。本記事ではこれを基に、講師・久田 智之氏(株式会社アナザーブレイン)による誌上ハンズオンをお届けします。なおPLATEAUでは、賞金100万円のコンテスト企画「PLATEAU AWARD」も募集(11月末締め切り)しています。ハンズオンなどを参考にぜひ応募してみてください。

最初に

 PLATEAUは国土交通省の日本全国のデジタルツイン化を主導するプロジェクトです。さまざまな取り組みがありますが、その中のひとつ に、PLATEAU VIEWというビューワー (3D GIS Web Viewer) があります。

 GIS (Geographic Information System) とは「地理情報システム」のこと。当初は2Dの地図上での表現が主流でしたが、近年のコンピューターの処理能力の向上とともに3Dの地図上での表現が急速に広がっており、そのため「地理空間情報システム」と表記されることも多くなっています。

※3D位置情報と共に時間軸があるデータを表現する場合は、その表現方法を4Dと表記されていることもあります。

 PCにインストールして使うGISアプリケーションも多くありますが、情報を手軽に共有しやすいWeb GIS もかなり進化してきています。

 PLATEAU VIEW (1.0系) は、オープンソースプロジェクトの TerriaJS という仕組みをベースに開発されており、TerriaJSは CesiumJSというオープンソースのWeb GIS エンジン(ライブラリ)をベースに開発されています。

 そのためこの誌上Hands-onでは「CesiumJS」をメインに取り扱います。Webブラウザ上に地球(地球儀のような球体状のモデル)を表示し、その地球上にJavaScriptでさまざまな3Dモデルを配置し表現できるようになることをゴールにしています。GISをいままで触ったことがない方にも、このHands-onをGIS理解の第一歩にしていただければと思っています。

TerriaJS : https://terria.io/
CesiumJS : https://cesium.com/platform/cesiumjs/

Sandcastle(CesiumJS開発実験環境)

 このHands-onでは次の開発環境を利用します。Google Chrome などのブラウザで試すことができますので、WindowsでもMacでもお試しいただきやすいです。

 以下、Cesiumが提供するCesiumJS開発実験環境です。アカウント作成などは必要ありません。
https://sandcastle.cesium.com/

 Sandcastle は直訳すると「砂の城」です。

 海岸の砂浜で、砂の城を作っては壊しまた作ってみるような気軽な感覚でプログラミングを試してみましょう。

「CesiumJS」とは

 Cesium社が開発し公開しているJavaScriptのWeb GIS オープンソースライブラリです。

 Cesium社は、オンラインで3Dデータを変換したり保存・公開ができる有償クラウドサービス「Cesium ion」などを提供しています。

 公共機関採用例では、国土交通省 PLATEAU VIEW (Ver 1.0系)、 東京都デジタルツイン3Dビューア(β)、 産総研 3DDB Model Viewer, 広島県 DoboXなどがあり、日本国内の近年のプロジェクトでの採用が盛んです。

※Cesium ion SDKというCesiumJSの強化版有償ライブラリもあり、CesiumJSの関数などについて検索される際に有償ライブラリのリファレンスマニュアルが検索結果にでてくることもあるので注意しましょう。

CesiumJS と似たオープンソースライブラリ

 CesiumJSのほかには、Mapbox GL JSやiTowns、DeckGLなどがあります。

Mapbox GL JS
https://github.com/mapbox/mapbox-gl-js

 2Dの表現から利用者も多く、近年3Dへの対応も急速に進んでいます。Ver 2.0からオープンソースライブラリのライセンス条項が変更になったので利用に注意が必要です。

iTowns
https://www.itowns-project.org/

 CesiumJSというよりも、TerriaJSに近いレイヤーまでをカバーするオープンソースプロジェクトです。ThreeJSをベースに開発されているので、ThreeJSとの連携で何か表現しようとするなら便利かもしれません。

DeckGL
https://deck.gl/

 Uber (ライドシェア・飲食宅配事業者)が開発。自社事業のために開発した仕組みの一部をオープンソースで公開しています。魅せるデザインに凝っているCoolな印象があります。

CesiumJSをSandcastleで試そう

 まずは、実際にCesiumJSを試してみましょう。

https://sandcastle.cesium.com/

画面構成説明

(1) 画面下部のGalleryにさまざまな利用例のサムネイル画像が並んでいます。気になるものを選んでいろいろ表示してみましょう。
(2) 選んだ利用例のJavaScriptコードが表示されます。ここは自由に編集することもできます。
(3) Runをクリックすることで、(2) のJavaScriptのコードが実行されます。
(4) 実行結果が表示されます。マウス操作でカメラの移動拡大縮小、角度変化など、3D操作することができます。(GISに限らずゲームなどにおいても3D Viewのプログラミングを考える時は、カメラ操作をイメージするとわかりやすくなります)

参考)3D Viewにおけるカメラ操作とは

1. Sandcastle で 飛行機を飛ばそう

 画面下部Showcaseの一番左に表示されている3D Modelsを選んでみてください。

 飛行機の3Dモデルが表示されます。

 マウスでZoom Out操作をしてみてください(ホイールをスクロールするなど)。地球が丸く表示され、アメリカ大陸の西海岸上空に飛行機が飛んでいることを確認できます。

2. 飛行機を日本の上空に移動させてみよう

 GISの基本的な位置情報は緯度・経度で表されます。(3D GISの場合はそこに高さも関係してきます)

 ソースコードのなかで、緯度・経度を発見してみましょう。


11:   const position = Cesium.Cartesian3.fromDegrees(
12:     -123.0744619,
13:     44.0503706,
14:     height
15:   );

 西経 123度、北緯 44度のような設定が見て取れます。これがアメリカ西海岸の座標です。

 さて日本の標準時をきめる子午線上空に飛行機を移動させてみましょう。

 標準時子午線がどこか覚えていますか? 中学生くらいのときに習ったのではないでしょうか。兵庫県は明石市ですね。

 ソースコードの該当部分 (12行目と13行目) を東経 135度、北緯35度に変更し [Run] してみましょう。


11:   const position = Cesium.Cartesian3.fromDegrees(
12:     135,
13:     35,
14:     height
15:   );

  マウスホイール操作などで Zoom Out (カメラを上空に上げてゆくような操作を)すると、日本列島の関西方面に飛行機が移動したことを確認できます。

 ここで、Cesium.Cartesian3.fromDegreesという関数についても調べてみましょう。

 CesiumJS のリファレンスマニュアル(英語)のこのページの中ほどに記されています。

 Cesium.Cartesian3.fromDegrees(longitude, latitude, height, ellipsoid, result)

 longitudeは経度です。西経 -180 ~ 東経 +180 での表現になります。

 latitudeは緯度です。南緯 -90 ~ 北緯 +90 での表現になります。

 heightは高さ(楕円体高)です。Sandcastle のこのコード上では height という変数渡しとなっています。

 ellipsoidとresultは省略されています。

※3D GISでは高さはheightあるいはaltitudeという言葉ででてきますが、日本国内で一般的に土地建物の高さ表現につかわれてきた「標高」ではなく「楕円体高」という基準を用いることが多いです。「標高 = 楕円体高 - ジオイド高」という関係性があるのですが 国土地理院のジオイドの説明などのページを参考に概念を理解しておくことをお勧めいたします。

 この関数(メソッド)にあるfromDegreesですが、GISにおいては緯度や経度の角度を表現するためにDegreeやRadianの両方を用いるケースが多いです。Degreeではいわゆる「度」を扱い、一周が360度で人が慣れている角度の表現になります。対してRadianは一周が2πとなり、三角関数などの演算と組み合わせて利用することが多くなります。角度を扱うときは「度」か「π」か注意しながら処理を進めましょう。

Coffree Break「longitude と latitude」

 longitudeとlatitude。GISをあつかっていると頻出するのですが、スペルがなんとなく似ているためどちらが経度でどちらが緯度かうっかり覚えにくい方もいらっしゃるのではないでしょうか。

 longが入っているからlongitudeは長い方で経度
 (緯度は -90~+90, 経度は -180~+180、緯度よりも経度の方が長い単位を扱う)

 というふうに覚えてみるのもよいかもしれません。

 また変数系は省略して使われることも多いです。lon, lat などです。latitudeはおおむねlatと略されることが多いようですが、lon, lng, longとlongitudeはバリエーションがさまざまです。

 もうひとつ注意点です。緯度経度を扱うとき、GIS以外においても日本では「緯度、経度」という順番に並んでいるケースが多いです。これは規格などでそう定められていることも多いためです。ところが日本国外のデータや関数を取り扱う場合は「経度→緯度」の順番に並んでいることも少なくありません。lat, lonもしくはlon, latのどちらの並びかは常に注意しましょう。CesiumJSも日本の一般的な取り扱い順と逆になる「経度、緯度」順ですね。

3. 高度 (height) が低い (0m) ミルクトラック を表示してみましょう

 ビューワーの左上のプルダウンでAircraft (飛行機)からMilk Truckに変更してみましょう。こちらはソースコード上の高度が0mとなっています(80行目)。そのため地表に表示されます。


75:   {
76:     text: "Milk Truck",
77:     onselect: function () {
78:       createModel(
79:         "../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb",
80:         0
81:       );
82:     },
83:  }

 このcreateModelの2番目の引数が高度となっています。ちなみに Aircraftは5,000m上空に設定されている(44行目)ことも確認しておきましょう。

4. スケールの自動調整機能をOFFにしてみる

 飛行機もミルクトラックも、マウスのホイールで地球全体を縮小表示した際に、下記のような表示になります。少し、いやかなり大きすぎますよね。

 これは、GISで数々のデータを表現する際に便利な自動スケーリングが働いています。

 イメージしてみてください。3D地図上でトラックをリアルなサイズの 幅3mx長さ5mくらいに表示した場合、すこしカメラをズームアウトするだけでトラックがとても小さく表示され人間の目ではまったく発見できなくなります。

参考)衛星や車の軌道を地球規模で表現したケース。自動スケーリングが機能しているのでズームイン・ズームアウトしても目的のモデルを発見しやすい。
https://sandcastle.cesium.com/?src=CZML.html&label=DataSources

 ためしにスケールの自動調整機能をOFFにしてみましょう。


25:  const entity = viewer.entities.add({
26:    name: url,
27:    position: position,
28:    orientation: orientation,
29:    model: {
30:       uri: url,
31:       minimumPixelSize: 128,
32:       maximumScale: 20000,
33:     },
34:   });
35:   viewer.trackedEntity = entity;
36: }

 ソースコードを眺めてみると、31行目の maximumScale: 20000というのが怪しいですよね。この20000を1に変更して [Run] してみましょう。

 たとえば左上のプルダウンからまたミルクトラックを選択し、カメラをズームイン・ズームアウトさせてみるとリアルなスケールで表示されるようになります。

 GIS上で表現したい内容によって自動スケーリング機能をONにしたりOFFにしたり使い分けましょう。

 ちなみに、このトラックが表示されている 東経135度、北緯35度は「日本へそ公園」です。トラックの左(西)の方に関連建物施設や遊具があり、このトラックが表示されている箇所には「日本のヘソモニュメント」があるそうです。

5. いざ PLATEAU 3D都市モデルを表示しよう

https://github.com/Project-PLATEAU/plateau-streaming-tutorial/blob/main/3d-tiles/plateau-3dtiles-streaming.md

 まずはこのGitHubにあるPLATEAUのレポジトリをブラウザで開いてみてください。

 そしてページの中程にある「3.1. Cesium.js での利用方法」のサンプルコードの中にある に挟まれている下記部分をコピーしてきましょう。


// Cesium Ionの読み込み指定
    Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5N2UyMjcwOS00MDY1LTQxYjEtYjZjMy00YTU0ZTg5MmViYWQiLCJpZCI6ODAzMDYsImlhdCI6MTY0Mjc0ODI2MX0.dkwAL1CcljUV7NA7fDbhXXnmyZQU_c-G5zRx8PtEcxE";
    // Terrainの指定(EGM96、国土数値情報5m標高から生成した全国の地形モデル、5m標高データが無い場所は10m標高で補完している)
    var viewer = new Cesium.Viewer("cesiumContainer", {
      terrainProvider: new Cesium.CesiumTerrainProvider({
        url: Cesium.IonResource.fromAssetId(770371)
      })
    });
    
    // PLATEAU-Orthoの参照
    var imageProvider = new Cesium.UrlTemplateImageryProvider({ url: 'https://gic-plateau.s3.ap-northeast-1.amazonaws.com/2020/ortho/tiles/{z}/{x}/{y}.png', maximumLevel : 19});
    var current_image = viewer.scene.imageryLayers.addImageryProvider(imageProvider); 
    
   // 東京都千代田区の建物データ(3D Tiles)
    var your_3d_tiles = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
      url : 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13101_chiyoda-ku/notexture/tileset.json'
    }));
    
    // カメラの初期位置の指定
    viewer.camera.setView({
      destination : Cesium.Cartesian3.fromDegrees(139.76, 35.68, 5000.0)
    });

  そしてSandcastleにもどります。

(1) [New] を選んで
(2) コピーしたコードをここにペーストして
(3) [Run] します
(4) 千代田区あたりが表示され、マウスでいろいろうごかすと 3D都市モデルも表示されていることを確認いただけます。

 コードをひとつひとつ確認していきましょう。

Cesium Ionの読み込み指定


1:     // Cesium Ionの読み込み指定
2:     Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI5N2UyMjcwOS00MDY1LTQxYjEtYjZjMy00YTU0ZTg5MmViYWQiLCJpZCI6ODAzMDYsImlhdCI6MTY0Mjc0ODI2MX0.dkwAL1CcljUV7NA7fDbhXXnmyZQU_c-G5zRx8PtEcxE";

 PLATEAU の各種データが、Cesium Ion というクラウドサービス上にあるのですが、それを取り出すためのアクセストークンの設定です。

Terrainの指定

 Terrain(テレイン)とは地形データのことです。CesiumJSでもTerrain データの用意があるのですが、PLATEAUで用意されているそれのほうが精度が非常に高いです。(※ただし日本国内に限る)



3:     // Terrainの指定(EGM96、国土数値情報5m標高から生成した全国の地形モデル、5m標高データが無い場所は10m標高で補完している)
4:     var viewer = new Cesium.Viewer("cesiumContainer", {
5:       terrainProvider: new Cesium.CesiumTerrainProvider({
6:         url: Cesium.IonResource.fromAssetId(770371)
7:       })
8:    });

 ここがその地形データをCesiumJS上に読み込むコードとなっています。

 ビューワーで富士山を見つけてみましょう。きちんと日本で一番高い山が表現されています。

 ちなみに飛行機を飛ばしたりミルクトラックを表示した時の地形は真っ平の状態でTerrainを考慮していませんでした。

PLATEAU-Orthoの参照

 Ortho (オルソ) 画像とは、いろいろなところでつかわれる用語ですが、ここでは「地表を写した衛星写真の画像」という理解でよいです。 こちらもCesiumJSの標準的な衛星画像の用意もあるのですが、日本国内に限っては、PLATEAUで用意されている画像のほうが精細になっています。


10: // PLATEAU-Orthoの参照
11:     var imageProvider = new Cesium.UrlTemplateImageryProvider({ url: 'https://gic-plateau.s3.ap-northeast-1.amazonaws.com/2020/ortho/tiles/{z}/{x}/{y}.png', maximumLevel : 19});
12:     var current_image = viewer.scene.imageryLayers.addImageryProvider(imageProvider); 

 ここで読み込みが指定されています。

 これを試しに「地理院タイル」で提供されている標準地図に差し替えてみましょう。
地理院タイル一覧:https://maps.gsi.go.jp/development/ichiran.html


11:     var imageProvider = new Cesium.UrlTemplateImageryProvider({ url: 'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', maximumLevel : 18});

 11行目のURLを差し替えて、maximumLevelを18にして [Run] すると、地表が衛星画像ではなく、よく見かける地図の表示になります。

東京都千代田区の建物データ(3D Tiles)

 これも建物データの差し替えや追加を試してみましょう。

 先ほど開いたGitHubのPLATEAU レポジトリをもう一度みてみましょう。
https://github.com/Project-PLATEAU/plateau-streaming-tutorial/blob/main/3d-tiles/plateau-3dtiles-streaming.md

 「4. 配信データ(3DTiles)一覧」に各地の建物データのURLが記載されています。最初に千代田区の建物データを「テクスチャ付き(低解像度)」に変更してみましょう。

※低解像度でない高解像度のテクスチャ付きの建物データの表示にはCPU (GPU) パワーが必要になります。とくに新宿区などは顕著なので必要に応じて選んでください。


13:     // 東京都千代田区の建物データ(3D Tiles)
14:     var your_3d_tiles = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
15:       url : 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13101_chiyoda-ku/notexture/tileset.json'
16:     }));

 この15行目のurlのnotextureをlow_resolutionに変更する感じです。


15:       url : 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13101_chiyoda-ku/low_resolution/tileset.json'

 そして [Run] してみましょう。

 表示される3Dモデルの壁や屋上が写真(テクスチャ)になります。

※このとき建物が暗く表示されることがあります。これは日差しや影も計算されているためです。画面下の「タイムライン」部分を変更して「日本がお昼の時間帯」になるように調整すると、明るくなります。ここはいまUTCという世界標準時になっているため日本との時差は9時間あります。UTCを19:00 ~ 22:00あたりにすると日本は午前中 (4:00 〜 7:00)の扱いとなり明るくなります。

タイムライン

 次に港区も追加して表示してみましょう。港区のURLは先ほどのレポジトリのページに書かれています。千代田区につづいてコードを追加しましょう。


17:     // 東京都港区の建物データ(3D Tiles)
18:     var your_3d_tiles_2 = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
19:       url : 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13103_minato-ku/low_resolution/tileset.json'
20:     }));

 [Run] すると千代田区と港区の3D都市モデルが表示されます。

 港区にある東京タワーを見つけてみましょう。

カメラの初期位置の指定

 これは [Run] したあとにカメラを千代田区上空に配置する指定となっています。 東経 139.76度、北緯 35.68度、高さ 5000.0m から真下にカメラを向けるような指定となっています。


22:     // カメラの初期位置の指定
23:     viewer.camera.setView({
24:       destination : Cesium.Cartesian3.fromDegrees(139.76, 35.68, 5000.0)
25:     });

 すこしカメラの位置と角度も変えてみましょう。


22:     // カメラの初期位置の指定
23:     viewer.camera.setView({
24:       destination : Cesium.Cartesian3.fromDegrees(139.755, 35.66, 250.0),
25:       orientation: {
26:         direction : {x :0.5430334390652102, y :0.8161005711342862, z :-0.1977233973289519},
27:         up : {x :-0.6093028759577892, y :0.5449770222469744, z :0.5759774740147289}
28:       }
29:     });

 こうして [Run] すると、初期カメラ位置が、東京タワーと遠くに富士山が見える角度になります。

※setViewメソッドについて詳しくはリファレンスマニュアルを参照してみてください。
https://cesium.com/learn/cesiumjs/ref-doc/Camera.html

6. (参考)Share してみよう

 Sandcastleの便利な機能のひとつに Share (共有) があります。

(1) [Share] をクリックしてから
(2) [Copy] すると下記のような長い URL が生成されています

https://sandcastle.cesium.com/#c=zVVbbxpHFP4rI15sS3ivLAvEiYrAsrAgdhJwbQsJjXfHMLAXOjtgFstSMIkSK47ah1S9OXLSVE3StE4i9aFy7ObHrMHOU/5CZ7kF23lpnyqxMHP2O9+c850zBwAA4HmQQA6umSBlW17r4Oy3P7zW+7O/j9h3d/de5+DHvMVgAxDHQJyO1mHNoHFNQ46TtSvIAldBPoDc+dLanIYX8Hwq10yJ13HKSVk3FS2RCqcq1eWlxHyUY6Cv9LkKA6WU61LOzZS1jYVbgpBJrojp7I3GSnmWrpRXyxlXEFayOWE1W1Qy5hJe+fIGTifmq6uMbCEZbzK8kzKNks72meyKwHiEhWRKyiwLnF7ZiKfFhGaUc0vq9bi6nlwrLS9bprt6I1fQpueU5s1GZJHOao3ZfOBKPz0mQxYRArGvQT/vj0f3Z+cy0bB3u9X56bizt9/99k3n9i/d9t3Ok7eK2X3xw4dX33utB972zumj/e79b7zWd15rv3P3BYMzls7em87xz16bfe557VeMZuTkG4687fdea/f0zlOvdafz5M/uzm2v9VoURsTPz57tdQ52e6y/Moy3/eDj0U4/3DokoI7RBiJMegttDMuz1LNN5gNab5+wLcpSQiQfCILNvisAtJ/oIrHrWEckNk7Q/8meR0yOXAGoESM21gw3kWPXiIa4dWKbccdBNKVPqqogq+LU0GlrsNqaGog9knwxHc/OxnPTC4SWbF+yr7dP7z7PW3562IRFNIzgfJY5YmSRWTUgRSkfRdxPkfYDnChRWnViPK+5a4iUYRVaOqSQKzqYK9pcuco33CbvUJ3fbG7xmw32uFtc1SpOBIEJG9ismWlURwaIATHC4h5qrtUIQRYt9IJjQfVrwDkashCH+7GkoYuIw0FdvxjcuZQY6QU1uo/fnhz+/qF93HnYPnn37PTRm87uoa/Ku8PTnZejpmF9KSdBFhvIOdcPLitEQdYL1H9zMbYqwSamuI56gU1eqric7BEi+qnWTEgwpmRPbljjish2qpBiaPgymqxNeF9aXtaneyfza4Ze5EVZFIQCtSuu3VuLBa2EXVuH05Uab9gbBcIax6hRbFs87Z/MlR3bmhi2ytSVy7p0/3r93xUpSP83TeSCiS1I7X8ryUgYb/uV137qtV/6ktx/3N3bPzl+eHp8MBphAyn6SWvQRARyjNafEp9y0pFD/TjYuWB0tROQULaClty72UlUJAg5k6Ic5VRFCQJZ4cLhIJAUgROmgkMqm2B2O3pUMTA2NHRMkDY4YLMBYgKnhGRBlkNyVAgrkihIQeD65ogYZhopqijKISkSZuYmiE0LnBhVVUmWo6osRaKKGN0Kjk2k6oCV4cJCVBakiKpEFVWNRIe0SijECARJkkLhqBoK9WiZmeFUNaSGBDGkMuKt0cQaG1iBYGDwLzF8AJhxqGuga0P4F9is2oT63THJcTwdzCZW9ppWYVXUHGdYuxl+3HVGx3WA9aufmddAM6DjsDfrNcO4hZsoH7g2wzP8JVfDhjq2igt1RAzo+rCSeC3dN3IcN8Oz7ec9qW0ba5BcYP4H

 これをブラウザで開くと先ほど編集したコードがSandcastle上に表示され実行されます。

 知り合いに共有される際はこのURLだと長すぎますので、bit.lyなどのURL短縮サービスと組み合わされることをお勧めします。
https://bit.ly/3UohUg9

※注意:短縮元のURLが長すぎると短縮サービスが対応しておらずエラーになるケースもあります

(参考)CesiumJS x Babylon.js

 ここからは、少し中級~上級編になるのですが、発想を広げていただけるかもしれない裏技的手法を記しておきます。

 CesiumJSだけでもさまざまな3D表現を行うことができるのですが、もしドローンを数百機飛ばしてみたくなったり、土石流が流れてくるような物理演算の表現をさせたくなった場合は、CesiumJSだけだとすこしコードが煩雑になってしまったり、動作が想像しているよりも遅くなったりするケースもでてくるでしょう。

 そのときは、Babylon.jsやThree.jsなどのJavaScript 3Dライブラリを併用すると道が開けるかもしれません。

 やり方としては、レイヤーを二種類用意し、重ねて表現するような手法です。

 HTML5 Canvasを二つ用意し、それぞれをフロント側(Babylon.js 側になることが多い)とバック側(CesiumJS)の描写ターゲットとし、フロント側の背景を透過にしてz-orderなどで前後に並べて配置する。

 描写については、たとえばCesiumJSを主とするなら、そのカメラ位置が移動するようなイベントが起きた際に、Babylon.js側のカメラ位置も相当分移動させる。(逆のパターンがよいケースもある)

 という処理を行い、二種類の3D仮装空間を重ねて、閲覧者にはひとつの空間のようにみせる手法です。

 サンプルコード (Sandcastle) を用意してみました。(リンク先参照)

  バック側は、CesiumJSで地球が描かれていて、フロント側に Babylon.js でキューブおよび、それを3D操作する3Dギズモなハンドルをおいています。

 ①でマウス操作のターゲットを切り替えることができます。Cesium モードのときは地球をみる角度などを変更できます。Babylon モードのときは②の3Dギズモを操作することで、キューブを移動させたり回転させたるすることができます。

 例えば物理演算させようとすると、実際は「TerrainがCesiumJS側だけど、その情報をどのようにBabylon.jsに渡せばいいか」など、詳細に検討し開発していく必要があるのですが、このような手法もあるということを作品作りのヒントにしていただければと思います。

(参考)CesiumJSより一段階上位レイヤーのTerriaJS

 続いては、PLATEAU VIEW (Ver 1.x) が採用している TerriaJSの機能についても簡単に紹介しておきます。TerriaJSはCesiumJSをベースに開発されています。

■Coffee Break 「PLATEAU VIEW」をハックしてみよう

 リアルタイムなバスの位置情報を表示してみましょう。

 このようなJSON データ (カタログデータ) を用意します。


{
  "version": "8.0.0",
  "initSources": [
    {
      "catalog": [
        {
          "id": "北海道拓殖バス",
          "name": "北海道拓殖バス ロケーション情報",
          "description": "北海道拓殖バス オープンデータ CC BY 4.0 を利用 https://www.takubus.com/%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%83%87%E3%83%BC%E3%82%BF/",
          "type": "gtfs",
          "hideSource": true,
          "image": "https://d2jfi34fqvxlsc.cloudfront.net/usecase/13100_tokyo/realtime/tokyo_bus.png",
          "refreshInterval": 30,
          "url": "https://proxy.cors.sh/http://takubus.bustei.net/VehiclePosition.pb",
          "scaleImageByDistance": {
            "far": 1,
            "farValue": 1,
            "near": 0,
            "nearValue": 1
          }
        }
      ],
      "initialCamera": {
        "west": 141.28691189946244,
        "south": 42.07811366127045,
        "east": 144.2989291770435,
        "north": 43.57697185362125,
        "position": {
          "x": -3869894.60309132,
          "y": 2988657.4451773623,
          "z": 4283363.9154840885
        },
        "direction": {
          "x": 0.6572947579177821,
          "y": -0.7386210117298919,
          "z": 0.14967498870858514
        },
        "up": {
          "x": -0.23126864551511844,
          "y": -0.008665005215941768,
          "z": 0.9728513407947847
        }
      },
      "baseMaps": {
        "defaultBaseMapId": "/basemap//地理院地図 (淡色)"
      },
      "workbench": [
        "北海道拓殖バス"
      ]
    }
  ]
}

北海道拓殖バス オープンデータ CC BY 4.0を利用しています。

※CORS回避にhttps://cors.sh/というサービスをお試し利用で経由させています。そのサービスの制限や稼働状態によって上手に表示できないケースもあります。

 Chrome などのブラウザのアドレスバーにhttps://plateauview.mlit.go.jp/#start=と入力してから、つづけて上記 JSON をコピー&ペーストして表示すると「北海道拓殖バスのリアルタイム位置情報」が表示されます。

※注意:夜間や豪雪時に実行した場合はバスが運行していないためなにも表示されません。

 このようなURLになります。

 https://plateauview.mlit.go.jp/#start={%22version%22:%20%228.0.0%22,%22initSources%22:%20[{%22catalog%22:%20[{%22id%22:%20%22%E5%8C%97%E6%B5%B7%E9%81%93%E6%8B%93%E6%AE%96%E3%83%90%E3%82%B9%22,%22name%22:%20%22%E5%8C%97%E6%B5%B7%E9%81%93%E6%8B%93%E6%AE%96%E3%83%90%E3%82%B9%20%E3%83%AD%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E6%83%85%E5%A0%B1%22,%22description%22:%20%22%E5%8C%97%E6%B5%B7%E9%81%93%E6%8B%93%E6%AE%96%E3%83%90%E3%82%B9%20%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%83%87%E3%83%BC%E3%82%BF%20CC%20BY%204.0%20%E3%82%92%E5%88%A9%E7%94%A8%20https://www.takubus.com/%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%83%87%E3%83%BC%E3%82%BF/%22,%22type%22:%20%22gtfs%22,%22hideSource%22:%20true,%22image%22:%20%22https://d2jfi34fqvxlsc.cloudfront.net/usecase/13100_tokyo/realtime/tokyo_bus.png%22,%22refreshInterval%22:%2030,%22url%22:%20%22https://proxy.cors.sh/http://takubus.bustei.net/VehiclePosition.pb%22,%22scaleImageByDistance%22:%20{%22far%22:%201,%22farValue%22:%201,%22near%22:%200,%22nearValue%22:%201}}],%22initialCamera%22:%20{%22west%22:%20141.28691189946244,%22south%22:%2042.07811366127045,%22east%22:%20144.2989291770435,%22north%22:%2043.57697185362125,%22position%22:%20{%22x%22:%20-3869894.60309132,%22y%22:%202988657.4451773623,%22z%22:%204283363.9154840885},%22direction%22:%20{%22x%22:%200.6572947579177821,%22y%22:%20-0.7386210117298919,%22z%22:%200.14967498870858514},%22up%22:%20{%22x%22:%20-0.23126864551511844,%22y%22:%20-0.008665005215941768,%22z%22:%200.9728513407947847}},%22baseMaps%22:%20{%22defaultBaseMapId%22:%20%22/basemap//%E5%9C%B0%E7%90%86%E9%99%A2%E5%9C%B0%E5%9B%B3%20(%E6%B7%A1%E8%89%B2)%22},%22workbench%22:%20[%22%E5%8C%97%E6%B5%B7%E9%81%93%E6%8B%93%E6%AE%96%E3%83%90%E3%82%B9%22]}]}

 これは PLATEAU VIEW (Ver 1.x) が採用している TerriaJS の機能となりますので、カタログファイルの作り方は、下記のドキュメントに記載されています(英語です)。

https://docs.terria.io/guide/customizing/initialization-files/

 CesiumJS でこのようなバスのリアルタイムな位置情報を表現するプログラムを書こうとしたら……

(1) リアルタイムな位置情報をFetchしてくる
(2) pb形式 (Binary) のデータをデコードする
(3) バスのアイコンなどを適切な緯度経度に描写する
(このとき前回の描写があれば、それらのアイコンを消去する)
(4) 一定時間(たとえば 30秒)リアルタイム位置情報が更新されるのを待つ
(5) (1) へ戻る

 を自作することになります。

最後に

 PLATEAU Project で用意されているさまざまなデータは、デジタルツインで何かを表現するために自由に活用することができます。

 そこにほかのオープンデータあるいは自作のデータを重ねたり、見せ方・表現を工夫することで、価値を生み出し、

・とにかく楽しいFunな作品
・不便を解消するような作品
・未来を想像させるような作品
・誰かがもっとデジタルツインを作りやすくするような 中間ライブラリやAPI
・物理的な空間とIoTでつながる作品

 さまざまな切り口でのPLATEAU AWARD応募作品が増えるのが楽しみです。

 そしてこのHands-on記事が何かの一助となれたなら大変うれしいです。

合わせて読みたい編集者オススメ記事

バックナンバー