はじめに
第1回は Cesium ion(セジウムアイオン)にアカウントを作って、3D可視化環境の Sandcastle(サンドキャッスル)を試しました。
今回はいよいよ実践編です。国土交通省のプロジェクト PLATEAU(プラトー)が提供する、日本全国の高精度な3D都市モデルを使って、リアルな都市空間をブラウザ上に再現してみましょう。
Sandcastle で JavaScript のコードを少しずついじっていきますよ!
連載第2回のステップ
- PLATEAU の地形モデルと 3D都市モデルを読み込む
- 3D地形モデルを見てみる
- 3D都市モデルを見てみる
- 熱気球の 3Dモデルを街の上空に配置する
Step 1: PLATEAUの地形モデルと3D都市モデルを読み込む
PLATEAUの地形モデルは、国土地理院が全国をカバーして作っている「基盤地図情報 数値標高モデル(DEM:デム)5mメッシュ」から作られています。メッシュサイズが 5m の DEM はこんな感じでかなり細かいので、詳細な地形が表現できます。なお、5m メッシュ標高が未整備の場所では 10m DEM が使われています。
そしてなんと、東京都23区では 1mメッシュ!という超細かい DEM が提供されていますので、こんな感じのシャキっと綺麗に角が立った 3D地形を見ることができます。
では前説はこれくらいにして、早速やって行きましょう♪
Cesium ion アカウントにログイン
まずは Cesium ion のアカウントにログインします。
アカウントを作れていない人は、第1回を見てくださいね。
Sandcastleで始めるCESIUM ion 超入門(連載 第1回)
https://qiita.com/YutakaYasoshima/items/aafd8155f78e8801f6e2
ログインしたら「My Assets」タブを見てみましょう。
前回、Google Photorealistic 3D Tiles を My Assets に追加したのが残っていると思います。
今回は、My Assets に PLATEAU の地形モデルと建物モデルを追加します。
Asset Depot から選ぶ
隣の「Asset Depot(アセットデポ)」タブを選択すると、たくさんのアセットが並んでいます。
この中から「Japan」で始まる2行を見つけて「+」ボタンを押します。これらは、PLATEAU プロジェクトで作成された 3D地形モデルと 3D建物モデルです。
もう一度「My Assets」タブに戻って見ると、選択した 2つのデータが追加されています。
追加された2個のデータ
-
PLATEAU Terrain(プラトーテレイン)
Terrain とは 3D地形モデルのことです。場所によって 1mメッシュ、5mメッシュ、10mメッシュと細かさが違いますが、PLATEAU Terrain は日本全国をカバーしていますので、どこまでもスクロールして、地形を眺めて楽しめるデータです。 -
PLATEAU 3D建物モデル
2025年5月11日までに、国内 236都市の 3D建物モデルが完成して、オープンデータとして公開されています。
先に、PLATEAU の 3D地形モデルの方から Sandcastle で表示してみましょう。
Step 2: PLATEAU の 3D地形モデルを見てみる
「My Assets」タブで Japan Regional Terrain(ジャパン リージョナル テレイン)を見つけましょう。
初期表示は地球全体になりますが、地球儀を回して日本を拡大すると、綺麗な地形を見ることができます。
しかしその前に、ちょっとまった!
もう第2回ですから、左側のコード部分も観察しておきましょう。
PLATEAU Terrain( 3D地形モデル)のコードを見てみる
とても短いので、恐れるに足らず。2つのブロックしかありません。
まずは先頭のこの部分から。
// Grant CesiumJS access to your ion assets
Cesium.Ion.defaultAccessToken = "****ここは自分のアクセストークンが書かれています****";
これは、AccessToken(アクセストークン)と言って、自分の Cesium ion アカウントにアクセスするための、専用のトークン(鍵として働く秘密の文字列)です。それぞれのアカウントに個別のトークンが割り当てられています。
コメントの表記について
この後のコードにも出てくるのですが、
// こんなふうにスラッシュ2個があったら、その右側に書いてあることは、コメントです。プログラムコードに書き込まれた、いわゆる「メモ」です。
コメントはプログラムの動作の説明や、数値の意味など、後で見た時にコレ何だったけ?と思うようなところに細かく入れることになっています。頑張ってコードを書いて徹夜しちゃった翌朝には、内容などすっかり忘却の彼方...なんてことがありますからね😅
コードにコメントをいっぱい入れるのは、とっても良い習慣、良いプログラマです。
コードにはクドいくらいにコメントを入れよう!
さて、次の部分はここ。 ```js try { const viewer = new Cesium.Viewer("cesiumContainer", { terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(2767062), }); } catch (error) { console.log(error); } ``` try で始まるブロックは、 ```{カッコで囲まれた中} ``` の実行をトライする、という意味です。
ここで大切なのはここだけ。
terrainProvider:
await Cesium.CesiumTerrainProvider.fromIonAssetId(2767062)
これは、Cesium ion のアセットID「2767062」が地形データなのですが、それを
CesiumTerrainProvider(セジウム テレインプロバイダー:地形配信元)
として使おうとしています。
そして、2767062 と言えば...実はさっき見ています。
これ。
ここで登録した地形データ (2767062) を呼び出しているのですね。
まとめると、この画面でやっていることは2個でした。
① Cesium ion のアクセストークンを渡す
// Grant CesiumJS access to your ion assets
Cesium.Ion.defaultAccessToken = "Cesium.Ion.defaultAccessToken = "****ここは自分のアクセストークンと差し替えて****";";
② 登録しておいた AssetID 2767062(PALTEAU 地形データ)を呼び出す。
try {
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider:
await Cesium.CesiumTerrainProvider.fromIonAssetId(2767062),
});
} catch (error) {
console.log(error);
}
これで、コードの説明はおしまい。
せっかくなので、地球儀を回して富士山を見ておきます...😆
地図を回しても、左側のコード自体は変わらないですね。
カメラの現在位置は、Cesium.jsの内部に保持されているので、
ユーザーが地図を操作してもプログラムコードが書き換わることはありません。
Step 3: PLATEAU の 建物モデルを見てみる
続けて、PLATEAUの 3D建物を見てみましょう。
My Assetsタブを選択して、 Japan 3D Building Data を見つけてください。その行を選択したら、左下の Open complete code example をクリックします。
最初から日本付近が拡大されていますね。
そして、グリグリっと拡大すると、東京タワーだってちゃんと再現されています!
PLATEAU の3D建物モデル、すごいですね。
PLATEAU 3D建物表示のコードを観察
ここで、左側のコード表示にご注目。
ここの部分です。
これ、さっき地形のコードを見たときに、同じようなことが書いてありましたよね!
ここのところ、そっくりですね。
これらは、両方とも PLATEAU Terrain データを呼び出しています。
あらためて、建物のコードを見ていきます。
// Grant CesiumJS access to your ion assets
Cesium.Ion.defaultAccessToken = "Cesium.Ion.defaultAccessToken = "****ここには自分のアクセストークンが書かれています****";";
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(
2767062,
),
});
viewer.scene.globe.depthTestAgainstTerrain = true;
try {
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2602291);
viewer.scene.primitives.add(tileset);
await viewer.zoomTo(tileset);
// Apply the default style if it exists
const extras = tileset.asset.extras;
if (
Cesium.defined(extras) &&
Cesium.defined(extras.ion) &&
Cesium.defined(extras.ion.defaultStyle)
) {
tileset.style = new Cesium.Cesium3DTileStyle(extras.ion.defaultStyle);
}
} catch (error) {
console.log(error);
}
最初の部分は、地形のコードと同じで、Cesium ion のアクセストークンが書いてあります。
// Grant CesiumJS access to your ion assets
Cesium.Ion.defaultAccessToken = "****自分のアクセストークンが表示される
ご注目いただきたいのは、次のブロック。
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(
2767062,
),
});
地形のコードとは微妙に書き方が違いますが、ここで、PALTEAU 地形データを呼び出しています。
あれれ?
さっきの操作では、PLATEAU 建物を選んで Sandcatsle を開いただけのに、なぜか、選んでもいない PLATEAU 地形まで、勝手についてきているぞ!?
PLATEAU 建物には PLATEAU 地形が勝手についてくる
そうなんです。
これは、Cesium 君(Cesium 社の誰かさん)が親切心からやってくれていることで、PLATEAU の建物を Sandcatsle で使う時には、PLATEAU 地形も一緒に組み込んでくれるという🥺 素晴らしい仕組みになっているんですね。
Cesium ion で標準的に使われる地形は、 Cesium World Terrein(セジウム ワールド テレイン)というものです。これは第1回の最初で出てきましたが、世界向けの製品なので、日本の国交省プロジェクト PLATEAU が独自に作っている建物とは相性が悪いのです。
PLATEAU 建物には PLATEAU 地形を合わせないと具合悪い
日本のプロジェクトである PLATEAU では、地面の高さの基準を 「東京湾平均海面」 としています。国内で「標高」と呼ばれている高さは全て、この「東京湾平均海面」を 0m とした高さで統一されています。この時点ですでに、世界基準で作られている地形とは、ぴったり合わない予感しかしませんよね。
実際に PLATEAU の3D建物モデルを Cesium World Terrein に配置しても、高さが全く合わずに地面から浮いた感じになってしまいます。
なぜ、高さの一致しない地形が存在するのかの理由を説明するには、お話が長くなりますので、また次回、あるいは番外編で扱おうと思います。とりあえず、Sandcatsle を使っている間は Cesium 君の粋な計らいで、PLATEAU の建物は PLATEAU Terrain とセットで扱われますのでご安心を。
Step 4: 気球の3Dモデルを街の上空に配置する
せっかく、東京タワーまで見られたのですから、上空に何か飛ばしてみようではありませんか。
実際のところ、3Dプロジェクトで PLATEAU の3D都市モデルだけで完結することはほとんどなくて、大概は他の 3Dモデルと組み合わせて、あれこれと楽しんだり、分析したり、という事になると思います。そうしたことも Sandcatsle でサクッとできちゃいますので、まずはやってみましょう。
気球の 3Dモデルを配置してみる
熱気球を配置するのは今回作った、PLATEAU 3D建物の上にしましょう。
PLATEATU の建物を読み込んだら、左側のコードに少し呪文を加えます。
コード全体を入れ替えるのではなく、コードの最後に追加です。
// 気球を追加する位置を設定する
const balloonPosition = Cesium.Cartesian3.fromDegrees(139.7457, 35.6586, 450.0); // 概ね東京タワー付近、地上450m
const balloonEntity = viewer.entities.add({
name: "Hot Air Balloon",
position: balloonPosition,
model: {
uri: "https://sandcastle.cesium.com/SampleData/models/CesiumBalloon/CesiumBalloon.glb",
},
});
// 気球にカメラをズーム
viewer.zoomTo(balloonEntity, new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(0), // heading(方位)
Cesium.Math.toRadians(-20), // pitch(見下ろし)
400 // range(距離m)
));
中身をみて行きましょう。
(139.7457, 35.6586, 450.0) の3つの数値は、それぞれ
東経 139.7457°
北緯 35.6586°
標高 450.0m
を表しています。
そして、const balloonPosition = Cesium.Cartesian3.fromDegrees によって、カッコ内の緯度、経度、高さを balloonPosition に保存しています。
ここの数値を変えれば、好きな場所(緯度経度)、好きな高さに気球を配置できます。
次のブロックには、熱気球のモデルの名前と配置する位置 3Dモデルのファイルを書いてあります。
名前はこれです。name: "Hot Air Balloon"
クリックした時に表示される名前を設定しています。ここを日本語で「熱気球」などと変えてもOKです。
position: balloonPosition
では、上の方で balloonPosition に設定した気球の表示位置を読み込ませています。
最後にこの部分で、表示させる気球の 3Dモデルを指定しています。
model: {
uri: "https://sandcastle.cesium.com/SampleData/models/CesiumBalloon/CesiumBalloon.glb",
}
次の部分で気球にズームしています。
ズームは簡単で、ズームする対象を指定して、カメラ位置(視点)を設定するだけ。
viewer.zoomTo(balloonEntity, new Cesium.HeadingPitchRange はこの一行でカメラをズームする呪文になっています。
balloonEntity には、何行か上の「balloonEntity = ...」のとこで設定した、3Dモデルの情報が入っています。
そして、その対象物に対して、カメラの方位、見上げあるいは見下ろし角、カメラとの距離を指定します。
Cesium.Math.toRadians(0), // heading(方位)
Cesium.Math.toRadians(-20), // pitch(見下ろし)
400 // range(距離m)
heading:北を 0°としたカメラの向きを角度で表したもの
pitch:水平を 0°としたときに下方向のカメラの角度
range:対象物までの距離(m)
完成したコードはこうなります。
もし自分の Sandcatsle で上手く動かない場合は、下記のものと貼り替えてみてください。
// Grant CesiumJS access to your ion assets
// 自分のアカウントのアセットを追加する
Cesium.Ion.defaultAccessToken = "****ここは自分のアクセストークンと差し替えて****";
// Terrain(地形モデル)の指定
// PLATEAUのTerrain(地形データ)の AssetID をCesiumTerrainProvider に指定して、Cesium.Viewerを開く
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: await Cesium.CesiumTerrainProvider.fromIonAssetId(2767062), });
// 地下に埋まっているものを表示しない呪文
viewer.scene.globe.depthTestAgainstTerrain = true;
//ここから
try {
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(2602291); //PLATEAUの3D建物モデル
viewer.scene.primitives.add(tileset);
await viewer.zoomTo(tileset); //建物3Dにズームする。あとで気球にズームするので、この行は削除してOK。
// Apply the default style if it exists
const extras = tileset.asset.extras;
if (
Cesium.defined(extras) &&
Cesium.defined(extras.ion) &&
Cesium.defined(extras.ion.defaultStyle)
) {
tileset.style = new Cesium.Cesium3DTileStyle(extras.ion.defaultStyle);
}
} catch (error) {
console.log(error);
}
// 気球を追加する
const balloonPosition = Cesium.Cartesian3.fromDegrees(139.7457, 35.6586, 450.0); // 概ね東京タワー付近、地上450m
const balloonEntity = viewer.entities.add({
name: "Hot Air Balloon",
position: balloonPosition,
model: {
uri: "https://sandcastle.cesium.com/SampleData/models/CesiumBalloon/CesiumBalloon.glb",
},
});
// 気球にカメラをズーム
viewer.zoomTo(balloonEntity, new Cesium.HeadingPitchRange(
Cesium.Math.toRadians(0), // heading(方位)
Cesium.Math.toRadians(-20), // pitch(見下ろし)
400 // range(距離m)
));
いかがですか? 下の絵みたいに、東京タワーの横に、ちっちゃい熱気球が出てきたら勝利です!🎉
マウスで地図を拡大縮小しているうちに、気球がどこかに行ってしまったら「Run (F8)」ボタンを押して、コードを再実行してください。最初の表示に戻ります。
そうそう、Cesium は、その時間の太陽高度を再現しようとするので、夜見ると、何だか暗い感じの画面になります。そんなときは、タイムラインの青ボールを動かして、いい感じの日当たりになるように、調整してみてください。
おわりに
Sandcatsle を使うと、ブラウザだけでプログラムコードをいじりながら、3D地図で遊べてしまいましたね。
このままずっと遊び続けても良いのですが、次回はちょっと頑張って、自分のパソコンの中にコードを動かす環境を作ります。そうすると、Sandcastle で動かしたコードを自分のパソコンにコピペして、Sandcastle 無しでもプログラミングを楽しめるようになります。
さらに、自分のパソコン環境で動かしたコードを、そのままホームページに掲載して、他の人たちに見てもらうことも出来るようになります!
例えば、今回のコードもこんな感じで公開すれば、みんなに見てもらえます。
↑このコードのように、Cesium ion の アクセストークンをコード内に書く場合には以下の設定を行いましょう。
①あたらしくトークンを作る
②読み込み専用(ReadOnly)にする
③このアクセストークンで利用できる AssetID を制限する。
こんな感じです。
さらに、設定欄の下の方に、このアクセストークンで利用できる Assett ID を制限できる場所があります。
これらの設定はいつでも変更可能です。
第2回はこれでおしまい😃
ちょっと長めでしたか?ご感想をいただけたら嬉しいです。
これまでの連載記事
第1回では Cesium ion のアカウントの作り方をご紹介しています。
Sandcastleで始めるCESIUM ion 超入門(連載 第1回)
https://qiita.com/YutakaYasoshima/items/aafd8155f78e8801f6e2