tpc17-1

TOPIC 17|PLATEAU SDKでの活用[1/2]|PLATEAU SDK for Unityを活用する

PLATEAU SDK for Unityとは、PLATEAUの豊富なデータを活用して実世界を舞台にしたアプリの開発や都市シミュレーション等を行うためのツールキットです。このトピックでは、PLATEAU SDK for Unityの利用方法を説明します。

Share

【目次】

17.1   PLATEAU SDK for Unityとは

 17.1.1  PLATEAU SDK for Unityの機能

17.2   PLATEAU SDK for Unityを使用する

 17.2.1  サンプルプロジェクトを導入する

 17.2.2  PLATEAU SDK for Unityを使用する

17.3   PLATEAU SDK for Unityでできること

 17.3.1  GISサンプルアプリ

 17.3.2  ゲームサンプルアプリ

17.1 _ PLATEAU SDK for Unityとは

図17-1 PLATEAU SDK for Unity

PLATEAU SDK for UnityはPLATEAUをUnityで活用するためのオープンソースのツールキットです。PLATEAU SDK for Unityを利用することで、3D都市モデルのFBX、OBJ、GlTFデータへの変換・エクスポートや実世界を舞台にしたゲームの開発やPLATEAUの豊富なデータを活用した都市シミュレーションを簡単に行うことができます。

PLATEAU SDK for Unityのユーザーマニュアルは、次のURLで開けます。

https://Project-PLATEAU.github.io/PLATEAU-SDK-for-Unity

ここではPLATEAU SDK for Unityを初めて利用するユーザー向けのチュートリアルとして、SDKについての解説と、SDKで何ができるのかについて知っていただくための2種類のサンプルアプリの利用方法について解説します。

17.1.1 _ PLATEAU SDK for Unityの機能

図17-2 PLATEAU SDKの概要

PLATEAU SDK for Unityでは以下の機能を提供しています。

[1]都市モデルインポート機能

都市モデルインポート機能では、PLATEAUの3D都市モデル標準製品仕様書(第3版シリーズ)に準拠しているすべての3D都市モデルデータを入力としてUnityのシーンにインポートできます。

図17-3 PLATEAU SDKでのデータの流れ

インポート処理は以下の流れで行われます。

1. ファイルの取得

3D都市モデルのデータ(G空間情報センターから提供されているCityGML形式のデータセット)から必要なCityGML、コードリスト、テクスチャファイルを検索し取得します。なお、PLATEAUにおけるコードリストとは、GMLファイル内で使用される特定の値の集合を定義したリストのことを指します。GMLファイルを読み込むために技術上必要なファイルです。インポート元のファイルはローカルに保存されているものだけでなく、PLATEAUが提供する配信用サーバーからインポートすることも可能です。

2. 3D都市モデルの抽出

インポート時に設定された座標範囲内の3D都市モデルを抽出します。範囲指定は、5次メッシュ(250m×250mのタイルに相当)から任意の個数を選んで選択できます。選択範囲をまたぐ建物は、分割せずにいずれかの5次メッシュに属している扱いとします。

3. 平面直角座標への座標投影

CityGMLの各座標は経緯度で保持されています。Unity内ではメートル単位で座標値を扱う必要があるため、各座標は平面直角座標に変換されます。また、この際に各地物がUnityシーン内で原点近くに表示されるように座標値にオフセットをかけています。オフセット値は選択範囲の中心で初期設定されますが、インポート設定で自由なオフセット値に変更することも可能です。

4. CityGMLの形状データのポリゴンメッシュへの変換

CityGMLの形状データはそのままの形式ではゲームエンジンで可視化ができないため、インポート時にポリゴンメッシュへ変換しています。変換されたポリゴンメッシュはUnityシーン内でMeshオブジェクトとして可視化されます。ポリゴンメッシュに変換する際の結合単位は主要地物単位(建物、道路等)、最小地物単位(壁面、屋根面等)、地域単位(100m×100mの範囲の地物をすべて結合)から選択することができます。

5. テクスチャの結合
インポート設定でテクスチャを結合するよう指定されている場合、CityGML内のテクスチャはより少ない枚数のテクスチャにまとめられます。この処理はテクスチャアトラス化と呼ばれ、マテリアル数の削減によってゲームエンジンでのFPSが改善されます。

6. 地形への航空写真の貼り付け
インポート時に地図タイルをダウンロードしテクスチャとして貼り付けます。SDKは、地物の位置をもとに地図タイル座標を算出し、経緯度に対応する地図タイルをダウンロードします。デフォルトでは地理院地図の衛星写真のURLになっていますが、他の地図(標準地図、標高図など)も利用可能です。

7. マテリアルの適用
ゲームエンジン上で3D都市モデルを可視化する際、CityGMLのAppearance情報がゲームエンジンでのマテリアル情報に変換されます。ここで変換される情報にはテクスチャだけでなく、diffuseColor(拡散反射)、specularColor(鏡面反射)等の情報も含まれます。

[2]都市モデル調整機能

インポート機能でシーンにインポートされた3D都市モデルの見た目の調整が行えます。具体的には、以下の設定によって各地物の表示・非表示の切り替えができます。

● LOD

● 地物タイプ

 ◯ 建築物、道路、起伏等

 ◯ 最小地物単位でインポートされている場合、壁面、屋根面等面単位での表示・非表示ができます。

【メモ】LODとは

CityGMLには、各地物について複数の形状データが格納されている場合があります。LOD0は大まかな形状で、LOD1、LOD2 と数字が上がるほど細かい形状になります。建築物の場合、LOD0 は平面、LOD1は平面に一定の高さをつけたもの、LOD2はより細かい形状です(「TOPIC 1 1.3 3D都市モデルの特徴」を参照)。

[3]地物分割・結合機能

地物分割・結合機能ではエディタ上で3D都市モデル内の各オブジェクトの結合単位の変更が行えます。
分割・結合したいオブジェクトを選択し、結合単位を以下のオプションから指定して実行ボタンを押すと選択オブジェクトの結合単位が更新されます。

・地域単位
・主要地物単位
・最小地物単位

また、分割・結合処理の前後で以下の情報が保持されるようになっています。

・各オブジェクトの階層構造
・ポリゴンメッシュ情報
・マテリアル情報
・属性情報

[4]マテリアル分け機能

図17-4 マテリアル分け機能の適用例

マテリアル分け機能では3D都市モデル内の各オブジェクトについて、地物型によってマテリアルを分割・適用できます。この機能は主にLOD2以上の地物形状における構成部品(建築物での壁面、屋根面等)毎に分割を行う際に使用されることが想定されています。

[5]属性情報取得機能

図17-5 CityGMLとゲームエンジンでのオブジェクトの対応

属性情報取得機能ではC#ユーザー向けのAPIを提供しています。APIを利用することでCityGMLに含まれるすべての属性情報にアクセスできます。インポートされた3D都市モデルに含まれるUnityオブジェクトの名前はCityGMLでのIDに対応しているため、各オブジェクトの名前をAPIに指定することで付随する属性情報を取得できます。属性情報取得機能の詳細についてはユーザーマニュアルの都市情報へのアクセスのページをご覧ください。

[6]都市モデルエクスポート機能

都市モデルエクスポート機能ではインポートされた3D都市モデルを3Dファイル形式でエクスポートできます。

出力設定は以下の通りです。

ファイル形式OBJ、FBX、glTFに対応しています。
テクスチャ出力するメッシュにテクスチャを含めるかどうかを選択します。
非アクティブオブジェクトを含める都市モデル調整機能で非表示に設定されたオブジェクトを含めるかどうかを選択します。
座標変換出力座標系をLocal(Unityでの座標)とPlane Cartesian(平面直角座標)から選択します。
座標軸出力されるメッシュの座標軸を設定します。

17.2 _ PLATEAU SDK for Unityを使用する

PLATEAU SDK for UnityはUnityパッケージとして提供されています。本チュートリアルではSDKのサンプルを含んだプロジェクトを使用して解説しますが、個別のプロジェクトにSDKを導入したい場合はユーザーマニュアルのインストール手順に従ってください。

17.2.1 _ サンプルプロジェクトを導入する

[1]Unityをインストールする

PLATEAU SDK for Unity は、Unityバージョン 2021.3.35 を想定しています。そのバージョンがインストールされていない場合は、次の手順でインストールしてください。

1. Unity Hub をこちらからインストールします。Unity Hub とは、Unityのお好きなバージョンをインストールして起動できるソフトウェアです。

2.次のUnityのWebサイトにアクセスします。
https://unity.com/releases/editor/whats-new/2021.3.35

図17-6の赤枠部分をクリックするとUnity Hubが起動し、該当のUnityバージョンのダウンロードが始まります。

図17-6 UnityのWebサイト
図17-7 Unity HubでUnityをインストールしている画面

Unity 2021.3は2022年にリリースされたLTS(長期サポートリリース)であり、一般的に用いられているバージョンです。2023年5月に最新のLTSであるUnity 2022.3がリリースされておりますが、現在のSDKでは非対応となります。今後対応予定です。

[2]サンプルプロジェクトを導入する

1. ゲームサンプルアプリGISサンプルアプリのページからUnityプロジェクトをダウンロードしてzipファイルを展開します。

2. Unity Hubを開き、プロジェクト画面から[開く]を選択します。

図17-8 UnityHubからプロジェクトを開く

3. 先ほど展開したUnityプロジェクトを選択して開きます。

17.2.2 _ PLATEAU SDK for Unityを使用する

[1]データのダウンロード(ローカルのデータを利用する場合)

PLATEAUの3D都市モデルデータはポータルサイトで公開されています。ポータルサイトから地域を選び、CityGMLデータをダウンロードし、展開します。

3D都市モデル(Project PLATEAU)ポータルサイト

https://www.geospatial.jp/ckan/dataset/plateau

なお、CityGMLには「(v1)」と付くものと「(v2)」と付くものが両方配布されているなど、バージョン違いが配布されていることがあります。その場合、最新のバージョンであるv2またはv3をご利用ください。PLATEAU SDKはv2以上に対応しています。

図17-9 CityGMLのダウンロード

[2]インポート元の選択

ここからは、ユーザーマニュアルの3D都市モデルのインポートのページに沿って、展開したデータをインポートします。

Unityのメニューバーから [PLATEAU]→[PLATEAU SDK]を選択してSDK画面を開きます。上部のタブから[インポート]を選択してインポート画面を開きます。

インポート元として、事前にダウンロードしたデータを利用する「ローカル」、またはサーバーから直接データをダウンロードして利用する「サーバー」のどちらかを選択します。

[3-A]ローカルインポートの場合

フォルダパスには、展開したCityGMLデータの最上位フォルダ(「udx」などの1つ上の階層のフォルダ)を設定します。

図17-10 フォルダパスの設定

[3-B]サーバーインポートの場合

ローカルのデータではなくサーバーから直接シーンに3D都市モデルをインポートしたい場合、インポート元として[サーバー]を選択します。サーバー上に存在するデータセットの一覧が表示されるので、取得したいデータセットを選択します。

図17-11 サーバーのデータセットの選択

[4]基準座標系の選択

リストのうち、データが存在する場所と合致する基準座標系を選択します。基準座標系に関する詳細情報は、国土地理院のWebサイトに記載のある平成十四年国土交通省告示第九号をご覧ください。誤った基準座標系を選択した場合、本来の基準座標系から離れるほどインポートした都市モデルに歪みが生じてしまうのでご注意ください。

図17-12 基準座標系の選択

[5]インポートの範囲の選択

範囲選択ボタンを押します。現在のUnityシーンに変更がある場合、変更を保存するかどうかを尋ねるダイアログが表示されるので[Save] または[Don't Save]をクリックします。シーンビューの表示が切り替わり、範囲選択画面になります。 

図17-13 範囲選択画面

● 範囲選択画面の操作方法

 ◯ マウスホイールを上下に回してズームアウト、ズームインします。

 ◯ マウスホイールを押し込んだままドラッグしてカメラ移動します。

 ◯ 範囲の選択方法については、画面右下にある下記説明のとおりです。

 ・クリックで選択/選択解除

 ・ドラッグで矩形での選択追加

 ・Shift+ドラッグで矩形での選択除外

 ◯ シーンビュー左上の[決定]ボタンを押して範囲を確定します。すると元のシーンに戻ります。

● 画面の見方

 ◯ 青色の線は利用可能な地域を示します。

 ◯ 地域ごとに利用可能なGML種別と対応LODがアイコン形式で表示されます。

 ・ 対応LODは色で表現されます。画面左下の凡例の色と対応します。

 ◯ アイコンが多すぎると感じる場合は、画面左下の凡例のチェックを切り替えることでアイコンの表示/非表示をLODごとに切り替えることができます。

 ◯ 地図は国土地理院のサーバーから自動でダウンロードして表示されます。インターネットへの接続が必要です。

● メッシュコード検索機能

 ◯ シーンビュー左上のメッシュコード検索ボタンを押すと、メッシュコードの番号(地図上で青色で表示される数字)で検索できます。
なお、メッシュとは、経緯度に基づいて地域を同じ大きさの網の目に分けたものを指します。
メッシュコードとは、各メッシュを識別するために割り振られた番号を指します。

 ◯ 番号を入力してOKボタンを押すと、その範囲に視界が移動します。

図17-14 メッシュコードの入力画面

どの地域がどのメッシュコードに該当するかをWebで調べたい場合は、jSTAT MAPを利用します。jSTAT MAPで「ログインしないで始める」をクリックすると地図が開きます。右上のメニューから3次メッシュを選択し、「ラベル」にチェックを入れると地図上に3次メッシュコードが表示されます(図17-15)。

図17-15 3次メッシュコードの表示画面

[6]地物別設定

地物の種類ごとにインポートに関する設定を行います。

図17-16  地物別のインポート設定画面

設定項目について

● 一括設定

 ◯ 複数の地物タイプをまとめて設定したい場合に編集してください。

 ◯ 地物タイプごとの設定で「一括設定と同じ」を選択したときに、この設定が適用されます。

 ◯「一括設定と同じ」のチェックを外したときは、一括設定に関わらず、個別に設定を上書きするためのメニューが表示されます。

 ◯ 各設定の意味については後述します。

● インポートする

 ◯ チェックが付いている地物タイプのみインポートします。

● テクスチャを含める

 ◯ テクスチャが存在する地物タイプで表示される設定項目です。

 ◯ チェックが付いていて、かつテクスチャがある場合はそれを含めてインポートします。

 ◯ 都市によってはテクスチャがない場合があり、その場合はチェックを外した時と同様にデフォルトマテリアルが適用されます。

● テクスチャを結合する

 ◯ テクスチャを含める場合、テクスチャを結合するかしないかを設定します。

 ◯ PLATEAUのデータはテクスチャの枚数が多い傾向にあり、結合しないと描画負荷が高くなる傾向にあります。結合機能を有効にすると、複数のテクスチャを1枚の画像にまとめ、3DモデルのUVも合わせて調整されます。それによって描画負荷を改善できます。

● テクスチャ解像度

 ◯ テクスチャを結合する場合の、結合後のテクスチャの大きさを指定します。

● Mesh Collider をセットする

 ◯ チェックが付いている場合、各モデルに Mesh Colliderが追加されます。

 ◯ インポート後、クリックで属性情報を表示する機能を利用する場合、Mesh Colliderが必要です。

● LOD描画設定

 ◯ 複数のLODを利用可能な地物タイプで表示される設定項目です。

 ◯ バーの左端と右端をドラッグして、インポートするLODの範囲を指定できます。

● モデル結合

 ◯ 主要地物単位(建築物,道路等)

  モデルのメッシュは建物ごとに結合されて出力されます。建物ごとに地物データを取得したい場合はこちらを選択します。

 ◯ 最小地物単位(壁面,屋根面等)

  屋根、壁単位など非常に細かくオブジェクトを分けたい場合はこちらを選択します。

 ◯ 地域単位

  モデルのメッシュは地域ごとに結合されて出力されます。オブジェクト数を削減して軽量化できますが、建物ごとの地物データは取得不可になります。メッシュの結合はある程度の大きさの範囲ごとに行われます。

● 属性情報を含める

 ◯ 有効化すると、地物の属性情報がシーン中にコンポーネントで保存されます。

 ◯ 下図のように、PLATEAUCityObjectGroupコンポーネント内で属性情報が保持されます。

図17-17 PLATEAUCityObjectGroup

コンポーネントPLATEAUCityObjectGroupは、属性情報に関する機能を扱うためには必須となります。一方で、PLATEAUのゲームオブジェクトの数だけシーン中のコンポーネント数が増えることから、属性情報を利用しない、かつ軽量化が重要である場合には属性情報をオフとしてインポートするのが有利となります。

● デフォルトマテリアル

 ◯ PLATEAUの3D都市モデルのうち、テクスチャやマテリアル指定がない箇所のマテリアルを指定します。デフォルトでは、地物タイプに応じたマテリアルが指定されています。

[7]土地に衛星写真や地図を貼り付ける

土地に衛星写真や地図を貼り付けることができます。

図17-18  衛星写真を貼り付けた都市モデルの例

設定方法

● 範囲選択画面で土地起伏の3Dモデルが存在する地域を選択すると、インポート設定に「土地起伏」が表示されます。

● 土地起伏では、上述の地物別設定に加えて土地起伏専用の設定項目があります。

● 航空写真または地図の貼り付け

 ◯ チェックがONになっていると機能が有効化されます。

● URL

 ◯ 航空写真または地図の画像をダウンロードするためのURLです。

 ◯ デフォルトでは地理院地図の航空写真のURLが入力されています。

 ◯ このURLを変更すれば、航空写真だけでなく、国土地理院が提供している多種多様な地図や写真を土地に貼り付けることができます。利用できる地図については国土地理院のページを参照してください。そのページに記載されているURLを貼り付けることで地図を利用できます。

 ◯ 次の図17-19は地図を貼り付けた例です。

図17-19 地図を貼り付けた都市モデルの例

 ◯ 次の図17-20は陰影起伏図を貼り付けた例です。

図17-20 陰影起伏図を貼り付けた都市モデルの例

 ◯ URLには文字列 {z}, {x}, {y}を含めるようにしてください。これは地図タイルのxyz座標に変換されます。

 ・地図タイルのxyz座標については国土地理院のページを参照してください。

 ・SDKの機能により、土地の座標をもとに文字列{z}, {x}, {y}を適切な数値に置き換えて画像をダウンロードします。

 ◯ ズームレベル

 地図タイルのズームレベルです。

 ・数値が大きいほど高精細な画像になります。

 ・数値が1つ下がると、画素数が4分の1になります。

 ・ズームレベルは、地図タイルxyz座標のzの値に相当します。

 ◯ 利用可能なズームレベルの検索

 ・ボタンを押すと、現在入力されているURLでどのズームレベルが利用可能なのかを検索します。

 ・検索が完了すると、ズームレベルの入力欄がドロップダウンに変化し、利用可能なズームレベルから選択できるようになります。

図17-21 ズームレベルの選択画面

この機能でダウンロードされた地図タイルは、自動で1枚の画像に結合され、土地のUVとマテリアルが設定されてインポートされます。

[8]インポートの実行

[モデルをインポート]ボタンを押すとインポートが開始されます。

ウィンドウを下にスクロールすると、インポート処理の進捗が表示されます(図17-22)。処理が進むと、都市のオブジェクトが順次シーンに配置されていきます。進捗表示がすべて「完了」になったらインポート終了です。

図17-22 インポート処理の進捗状況
図17-23 インポートされた3D都市モデル

配置されたゲームオブジェクト階層のトップには、PLATEAUInstancedCityModelコンポーネントがアタッチされます。このコンポーネントのインスペクタから緯度、経度などの情報を確認できます(図17-24)。PLATEAUInstancedCityModelコンポーネントは、属性情報を含めない設定にした場合でもアタッチされます。

図17-24 都市モデルの経緯度情報

【メモ】

インポート元のファイルは Assets/StreamingAssets/.PLATEAU にコピーされます。.PLATEAUフォルダは隠しフォルダである点にご注意ください。「.PLATEAUフォルダ」はエクスポート機能の利用時に内部的に必要となるため、該当データのエクスポート機能を使う限りは削除しないでください。

[9]各機能へのアクセス

SDKの各機能にはSDK画面の上部タブ(図17-25)からアクセスできます。SDKの機能を利用することで、インポートした都市モデルについて表示地物の調整・メッシュファイル形式へのエクスポート・属性情報へのアクセスができます。各機能の利用方法はユーザーマニュアルを参照してください。

図17-25 SDKの機能タブ

17.3 _ PLATEAU SDK for Unityでできること

PLATEAU SDK for Unityを利用することで、PLATEAUの3D都市モデルを活用したGIS、AR/VR、ゲーム等さまざまなアプリケーションを開発できます。このトピックでは公開中のサンプルアプリを紹介し、SDKを利用すると実際にどのようなアプリケーションが作れるかについて解説します。

17.3.1 _ GISサンプルアプリ

PLATEAU SDKでは、どのような属性情報にアクセスできるかについて知るためのチュートリアルとして、GISサンプルアプリを提供しています。GISサンプルアプリでは、PLATEAUの3D都市モデルのさまざまな属性情報の表示や、属性情報に応じたフィルタリング・色分けができます。加えて、別途アドオンとして導入できるPLATEAU SDK Toolkits for Unityを利用して国土数値情報を表示する機能と、昼夜と天候を切り替える機能があります。GISサンプルアプリは、GitHubのリポジトリ「PLATEAU-SDK-for-Unity-GISSample」で公開中です。

なお、サンプルで利用しているPLATEAU SDK Toolkits for Unity(以下Toolkits)とは、PLATEAU SDKの機能を拡張するために別途導入可能なアドオンです。Toolkitsを導入しなくてもSDKは利用可能ですが、導入するとグラフィックを向上させるRendering Toolkit、映像制作やシミュレーションに役立つSandbox Toolkit、地図アプリ開発を支援するMaps Toolkit、およびARアプリ開発を支援するAR Extensionsを利用できます。ToolkitsはGitHubからダウンロードできます。

サンプルプロジェクトに含まれるAssets/GISSample/GISSample.unityを開き、Playすることで実行できます。

図17-26 GISサンプル

近くの建築物、および浸水想定区域の表示にはPLATEAUの3D都市モデルを利用しています。また、遠くの建築物および地形の表示は、Cesium for Unityによってインポートされた地形データ(Terrain)および建築物を利用しています。そのため、画面にはPLATEAUの3D都市モデルおよびCesium for Unityでインポートされたモデルの両方が表示されます。

[1]カメラ操作

画面上部の「操作方法 開く」ボタンをクリックすることでカメラ移動の操作方法が表示されます。具体的には次のとおりです。

水平移動マウス左ボタン+ドラッグ
回転マウス右ボタン+ドラッグ
前後移動マウスホイール回転
上下移動QEキー

[2]属性の確認

地物をクリックすると、その地物が赤色でハイライトされ、属性情報が可視化されます(図17-18)。

3D都市モデルに含まれる各地物(建築物、道路など)の属性情報の可視化は以下の流れで行われています。

① クリックされたゲームオブジェクトの取得

ゲームオブジェクトに対応する地物の属性情報の取得

属性情報のUIへの表示

クリックされたゲームオブジェクトの取得

ゲームオブジェクトの取得にはUnityのレイキャスティングという機能を使用しています。画面上をクリックした際、Camera.ScreenPointToRay関数によってカメラの原点からクリックされた地点に向けて仮想のビームが射出されて、ビームが衝突した中で最も手前にあるゲームオブジェクトが取得されます。

// SceneManager.csから抜粋


// <summary>
/// オブジェクトのピック
/// マウスの位置からレイキャストしてヒットしたオブジェクトのTransformを返します。
/// </summary>
/// <returns>Transform</returns>
private Transform PickObject()
{
   var camera = Camera.main;
   var ray = camera.ScreenPointToRay(Mouse.current.position.ReadValue());


   // 一番手前のオブジェクトを選びます。
   float nearestDistance = float.MaxValue;
   Transform nearestTransform = null;
   foreach (var hit in Physics.RaycastAll(ray))
   {
       var hitTrans = hit.transform;
       if (hitTrans.name.Contains("Cesium")) continue;
       if (hit.distance <= nearestDistance)
       {
           nearestDistance = hit.distance;
           nearestTransform = hitTrans;
       }
   }


   return nearestTransform;
}

ゲームオブジェクトに対応する地物の属性情報の取得

属性情報は、地物の各ゲームオブジェクトに付与された「PLATEAUCityObjectGroup」コンポーネントから取得できます。

// SampleGml.csから抜粋
// ゲームオブジェクトからコンポーネントを取得
var cityObjComponent = cityObjectTransform.GetComponent<PLATEAUCityObjectGroup>();

取得されたコンポーネントから以下の関数を呼び出すことで、属性情報を取得できます。

// SampleCityObject.csから抜粋
cityObjComponent.PrimaryCityObjects.First().AttributesMap

上記コードの解説

「PLATEAUCityObjectGroup」コンポーネントから「PrimaryCityObjects」を呼び出すと、コンポーネントに対応する主要地物(建物、道路など)の一覧が取得されます。本サンプルでは建物は主要地物単位でインポートされており、各コンポーネントは1棟の建物に対応しているため、一覧から先頭の要素(「First()」)を取り出すことで1棟の建物の情報を取り出しています。ここで取得されたインスタンスの「AttributesMap」プロパティに属性情報が格納されています。

地域単位でインポートした場合、複数の建物が1つのゲームオブジェクトに含まれるため、「PrimaryCityObjects」の中身は通常複数になります。この場合でも「PrimaryCityObjects」を参照する代わりに先ほど取得したレイキャストの結果を使用して「GetPrimaryCityObject(RaycastHit)」関数を呼び出すことでクリックされた建物の情報を取得できます。

属性情報のUIへの表示

GISSampleではUIの構築にUI Toolkitを使用しています。属性情報UIのビュー設定では、スクロールビューに2つのテキストを含んだ要素を上下に並べるように設定してあります(図17-28)。スクリプトから属性情報からすべてのキーと値を取得して、それぞれの組み合わせについてUIを追加していくことで属性情報UIを構成しています。

// AttributeUi.csから抜粋

public void SetAttributes(SampleAttribute data)
{
   // 属性データに合わせてUIElementを追加
   var elems = data.GetKeyValues()
       .Select((v, i) =>
       {
           var elem = new VisualElement();
           elem.AddToClassList("key-value");


           var keyLabel = new Label(v.Key.Path);
           keyLabel.AddToClassList("key");
           elem.Add(keyLabel);


           var valueLabel = new Label(v.Value);
           valueLabel.AddToClassList("value");
           elem.Add(valueLabel);


           // 属性情報テーブルの背景色ストライプ
           var bgColor = elem.style.backgroundColor.value;
           elem.style.backgroundColor = (i % 2 == 0)
               ? bgColor:
               bgColor + new Color(0.2f, 0.2f, 0.2f);


           return elem;
       });


   foreach (var elem in elems)
   {
       GetScrollView().Add(elem);
   }
}

上記コードにおいて、実際に属性情報を取得する箇所はdata.GetKeyValues()であり、そのメソッドの中身のうち主要部分を抜き出すと次のようになります。

// SampleAttribute.csから抜粋


private void GetKeyValuesInner(
  CityObjectList.Attributes attributesMap,
  string parentPath,
  List<KeyValuePair<KeyPath, string>> keyValues
)
{
  foreach (var keyValue in attributesMap)
  {
      // 中略
      if (keyValue.Value.Type == AttributeType.AttributeSet)
      {
          GetKeyValuesInner(keyValue.Value.AttributesMapValue, path, keyValues);
      }
      else
      {
          keyValues.Add(
              new KeyValuePair<KeyPath, string>(
                  new KeyPath { Key = keyValue.Key, Path = path },
                  keyValue.Value.StringValue
              )
          );
      }
  }
}

上記コードの解説

属性情報であるAttributeMapをforeachで回すと、属性情報のキーとバリューのペアが得られます。バリューになり得る型はいくつかあり、その一つとして入れ子構造のAttributeMapである場合があります。その場合は再帰処理をします。バリューがAttributeMapでないなら、バリューは文字列型、数値型など文字列に変換可能な型となるのでUI表示の対象とします。

図17-27 属性情報の表示
図17-28 属性情報UIのビュー設定(Assets/GISSample/UI/Uxml/Attribute.uxml)

[3]属性による色分け表示

高さや、各種浸水ランクで、地物を色分けすることができます(図17-29、図17-30)。

建築物の高さ情報は[bldg:measuredheight]をキーとして属性情報から取得しています。

// SampleAttribute.csから抜粋
if (Attributes.TryGetValue("bldg:measuredheight", out var val))
{
MeasuredHeight = val.DoubleValue;
}
else
{
MeasuredHeight = null;
}

各地物のゲームオブジェクトからRendererコンポーネントを取得して、すべてのマテリアルの色を変更することで地物の色の変更を行っています。

public void SetMaterialColorAndShow(Color color)
{
   SetActive(true);
   foreach (var lod in LodObjects)
   {
       if (lod == null) continue;
       var renderer = lod.GetComponent<Renderer>();
       if(renderer == null) continue;
       for (int i = 0; i < renderer.materials.Length; ++i)
       {
           var mat = renderer.materials[i];
           mat.color = color;
          
           // Rendering Toolkitsのauto textureに対応
           if (mat.HasProperty(BuildingColorPropertyId))
           {
               mat.SetColor(BuildingColorPropertyId, color);
           }
       }
   }
}
図17-29 色分けを選択するラジオボタン
図17-30 高さで色分けしたところ

[4]フィルタリング

高さや、LODの範囲を指定し、指定された範囲内の地物だけを抽出することができます。

SDKでインポートされた3D都市モデルのゲームオブジェクトは[3D都市モデル]/[CityGML]/[LOD]/[地物]/[子地物]という形で階層化されています。LODのゲームオブジェクト(lodObject)の名前はLOD0〜LOD3で設定されているので、名前を確認することでLODの値を取得しています。

各地物の表示・非表示の切り替えはGameObject.SetActive関数を使って行っています。

図17-31 フィルタリングの設定を行うスライダー
図17-32 高い建物を抽出し、低い建物を非表示にしたところ

[5]天候と昼夜の変更

画面上の天候スライダーと昼夜切替スライダーを変更することで見た目を変更できます(図17-33)。

図17-33 夜にし、雨と雪を降らせたところ

天候・時間の変更と夜に建物の窓が光る機能は、PLATEAU SDK Toolkits for Unityの一つ、Rendering Toolkitの機能です。
エディタモードでの天候・時間変更は、Rendering Toolkitの画面を操作することでプログラミングなしで行うことができます(図17-33)。

図17-34 エディタでの見た目変更

夜に建物の窓を光らせる機能については、事前にRendering Toollkitの自動テクスチャ生成機能を使うことで専用のシェーダーを適用して実現しています。
天候と時間に関して、このサンプルではエディタ中ではなく実行時に変更可能としています。

/// TimeUi.csから抜粋
private void OnTimeChanged(ChangeEvent<float> evt)
{
environmentController.TimeOfDay = evt.newValue;
}

environmentControllerはRendering Toolkitで提供されているコンポーネントEnvironmentControllerであり、事前にシーンに配置したものを参照しています。

天候の変更処理は以下のコードによって実装しています。

/// WeatherController.csから抜粋


private void OnRainSliderChanged(ChangeEvent<float> e)
{
  environmentController.Rain = e.newValue;
}
private void OnSnowSliderChanged(ChangeEvent<float> e)
{
  environmentController.Snow = e.newValue;
}

private void OnCloudySliderChanged(ChangeEvent<float> e)
{
  environmentController.Cloud = e.newValue;
}

private void OnCloudIntensitySliderChanged(ChangeEvent<float> e)
{
  environmentController.CloudIntensity = e.newValue;
}

[6]国土数値情報の表示

都市上空に浮かぶテキストは、国土数値情報から入手したGISデータを表示したものです。路線名、公園名、学校名が表示されます(図17-35)。

図17-35 国土数値情報の表示

国土数値情報は国土交通省が配布しており、Webページから誰でもダウンロードできます。このようなGISデータをUnityに読み込む機能が、PLATEAU SDK Toolkits for Unityの一つであるMaps Toolkitに実装されています。
この機能を使うと、GISのデータがシーン中に配置され、付与されるDbfComponentから属性情報を読み取ることができます。

/// GISAttrDisplayFactoryBase.csから抜粋


public void Exec()
{
  var dbfs = GameObjectUtil.FindComponentsInChild<DbfComponent>(target.transform);
  foreach (var dbf in dbfs)
  {
      if (dbf.Properties.Count <= propertyIndex)
      {
          Debug.LogError("Invalid propertyIndex.");
          return;
      }

      var instanced = Instantiate(display, dbf.transform);
      instanced.transform.position = CalcPosition(dbf, out bool isSucceed);
      if (!isSucceed) return;

      instanced.SetContent(dbf.Properties[propertyIndex].Trim());
      instanced.SetColor(backgroundColor, textColor, pillarColor);
  }
}

上記コード内の propertyIndex は、GISデータ内の何番目の属性値を利用するかを指定しています。

[7]都市モデルを差し替えたい場合

サンプルの都市は竹芝の3D都市モデルを利用しています。3D都市モデルを別の都市に置き換えたい場合、以下の手順に従ってください。

 1. シーンに配置されている現在の3D都市モデルを削除します。

 2. PLATEAU SDKで3D都市モデルをインポートします。インポート時の設定では「Mesh Collider をセットする」にチェックを入れます。これはクリックを検知するために必要です。また、地形のインポートはオフにします。これはCesiumと重複しないようにするためです。

 3. サンプルに含まれるスクリプトAutoTextureRunnerを任意のゲームオブジェクトに付与し、インスペクタから対象と水害表示マテリアルを指定してRunボタンを一度だけ押します。

 4. PLATEAU SDK Toolkits for Unityの一つであるMap Toolkitの機能である、モデル位置合わせ機能を利用して都市モデルとCesiumの位置を合わせます。

 5. ゲームオブジェクトCesium3DTilesetにはコンポーネントCesiumBoxExcluderが付与されています。この機能は、BoxColliderの範囲をCesiumから除外することでCesiumとPLATEAUで建物が重複しないようにするものです。ここでBoxColiderの範囲を調整し、PLATEAUモデルと被せることで重複を防ぎます。

 6. Main Cameraの位置を調整し、都市が映るようにします。

 7. Maps ToolkitのGISデータ読み込み機能を使って、国土数値情報などからお好みのデータを追加します。
  a. これにより生成されたDbfComponentの親ゲームオブジェクトに、GIS形式に合わせて次のコンポーネントを追加します。
   ・LineであればGISAttrDisplayFactoryByLine
   ・PointであればGISAttrDisplayFactoryByPoint
  b. インスペクタからコンポーネントを設定します。設定項目は対象としたいDbfComponentの親ゲームオブジェクト、表示するPropertyのインデックス、テキストウィンドウの色です。

図17-36 コンポーネント設定画面

 8. UnityのメニューバーからPLATEAU GIS Sample→Destroy Far GISsを押します。これにより、遠すぎて見えないGISデータを削除できます。

 9. GISのLine形式のデータはLine Rendererによって表示されますが、デフォルト設定では線がループするようになっています。ループさせたくない場合は、UnityのメニューバーからPLATEAU GIS Sample→Adjust Linesを押すことですべてのループを解除できます。

 10. Playボタンを押して表示されたら成功です。

17.3.2 _ ゲームサンプルアプリ

都市空間上でのインタラクションの作成方法について知るためのチュートリアルとして、ゲームサンプルアプリを提供しています。ゲームサンプルアプリは、制限時間内にロボットに襲われている要救助者を救出するゲームとなっています。敵を避けながら要救助者と接触し、なるべく多くの人数をゴールに連れて行き救助することを目指します。ゴールの場所は紙飛行機を取得すると明らかになります。敵は街を歩き回りますが、プレイヤーを見つけると襲ってきます。要救助者も街を歩き回りますが、プレイヤーと接触すると同行者として付いてくるようになります。同行者がいる状態でゴールとなる建物に接触すると救助となります。プレイヤーは走る、ジャンプ、およびロボットの足止めをする攻撃ができます。ゲームサンプルアプリは、サンプルプロジェクトに含まれるAssets/GameSample/Scenes/GameSample.unityを開き、Playすることで実行できます。

図17-37 スタート画面
図17-38 ゲーム画面

[1]環境構築の手順

Unityエディタ上でゲームサンプルを動かすには、「Starter Assets - Third Person Character Controller」を導入する必要があります。以下の手順に従って、このアセットをプロジェクトにインポートしてください。

 1. Asset Storeから「Starter Assets - Third Person Character Controller」のページを開き、Add To My Assetsを選択してください。この際、Unityエディタで使用しているUnityアカウントへのログインが必要となります。

図17-39 Asset Storeの画面

 2. UnityHubからゲームサンプルのプロジェクトを開き、Unityエディタ上部にあるメニューバーから「Window」を選択し、「Package Manager」をクリックして、PackageManagerウィンドウを開きます。

 3. Package Managerウィンドウの左上にあるドロップダウンメニューから「MyAssets」を選択し、「Starter Assets - Third Person Character Controller」を探した後、そのアセットをクリックし、表示される「Install」または「Download」ボタンをクリックします。

図17-40 Package Manager上でのStarter Assets - Third Person Character Controllerの画面

 4. ボタンが「Import」に変化するので、「Import」をクリックします。その後、Import Unity Packageウィンドウが表示されるので、右下の「Import」を選択します。

図17-41 Import Unity Packageウィンドウ

5. アセットがプロジェクトに正しくインポートされたかを確認します。正しくインポートされていれば、プロジェクト内のAssetフォルダにStarterAssetsフォルダが追加されています。以上が完了すれば、「Starter Assets - Third Person Character Controller」の導入は完了です。

図17-42 AssetフォルダにStarterAssetsフォルダが追加された画面

[2]プレイヤーの操作方法

プレイヤーを動かすには、キーボード・マウスを使います。

W前進
S後退
A 左への移動
D右への移動
スペースジャンプ
左クリック攻撃用フックショット
マウス操作視点移動

[3]紙飛行機を取得した時の処理

紙飛行機を取得すると、ゴールがミニマップに表示されゴールとなる建物が発光します。ゴールが生成されるとき、1つの建物で救出可能な人数は建物の高さと比例するように設定しています。このサンプルでは建物の属性情報から高さを取得しています。
OnControllerColliderHit関数を利用することで、プレイヤーと他のオブジェクトが衝突した際の処理を実装しています。

紙飛行機には”Hint”という名前のタグが付けられており、接触したオブジェクトのタグを調べることで、接触したオブジェクトが紙飛行機であるかという判定を行っています。紙飛行機を取得した場合、ゴールの設置とUIの更新が行われます。一連の処理が終了した後、紙飛行機のオブジェクトを削除します。

private void OnControllerColliderHit(ControllerColliderHit hit)
{
if(hit.gameObject.CompareTag ("Hint"))
{
GameManageScript.GetHintItem();
//アイテムを削除
ItemManageScript.GetItem(hit.gameObject);
}
図17-43 紙飛行機を取得した様子

ゴールに選ばれた建物の色を変え、発光させます。

/ 建物の色を変更 (UIManage.cs)
GameObject building = GameObject.Find(hintBuildingName);
Renderer renderer = building.GetComponent<Renderer>();
for (int i = 0; i < renderer.materials.Length; ++i)
{
  renderer.materials[i].color = selectedColor; 
  renderer.materials[i].EnableKeyword("_EMISSION");
  renderer.materials[i].SetColor("_EmissionColor", selectedColor);
}

[4]キャラクターの挙動

ゲームには、要救助者キャラクターと敵キャラクターが登場します。

図17-44 要救助者キャラクター(左)と敵キャラクター(右)

各キャラクターの挙動について説明します。

基本的な動き

キャラクターの基本的な動きは、UnityのCharacterControllerコンポーネントを使用しています。キャラクターはUnityの物理エンジンに従って、重力の影響を受け、地形上を移動します。

キャラクターのアニメーションはAnimatorコンポーネントを使用しています。歩行や走行など、移動速度に応じたアニメーションが適用されます。

巡回行動

キャラクターが街をランダムに巡回します。

キャラクターの巡回ルートは、ゲームオブジェクト”RoadObjects”で管理されています。”RoadObjects”は3D都市モデルの道路用オブジェクトを基にして作成されており、細分化された道路オブジェクトの集合で構成されています。

図17-45 RoadObjectsと細分化された道路オブジェクト

巡回行動の処理は以下になります。

1. 現在地から次の目的地への移動: キャラクターは現在地の道路オブジェクトから「新しい目的地」の道路オブジェクトへ移動します。

2. 新しい目的地の設定: 現在地の周辺からランダムに「新しい目的地」を選びます。

//巡回地点まである程度ちかづいたら別の地点へ移動
            if (currentDistance< arrivedDistance)
            {
                //かつての目的地を現在地にセット
                pastRoadObj = currentRoadObj;
                currentRoadObj = nextRoadObj;
                //自身の周辺のランダムな道路オブジェクトを新たな目的地として設定する
                nextRoadObj = pathManager.GetRandomNeighbor(currentRoadObj, pastRoadObj);
          SetEnemyDestination(nextRoadObj.GetComponent<Renderer>().bounds.center);
            }

キャラクターの視界

キャラクターの視界として、配下にゲームオブジェクト”SearchArea”を設定しています。SphereColliderコンポーネントを設定しています。OnCharacterEnterとOnCharacterExitメソッドを用いて、プレイヤーを追跡開始または見失ったことを検知します。

図17-46 キャラクターの視界範囲”SearchArea”

追跡行動

プレイヤーを追跡する処理です。プレイヤーが視界に入ると実行されます。
この処理が実行されることによる各キャラクターの行動は以下になります。

1. 要救助者キャラクター:救助中の要救助者キャラクターとして、プレイヤーに追従します。

2. 敵キャラクター:プレイヤーや要救助者キャラクターを追跡します。

[5]生存者キャラクターとのインタラクション

ゲームにおけるプレイヤーと生存者キャラクターのインタラクションについて説明します。

同行者数の追加

プレイヤーが要救助者キャラクターに近づくと、同行者数が追加され、画面に表示されます。

図17-47 救助中の様子

救助者数の追加

避難所(青色の建物)に触れると、避難所の収容可能人数だけ救助されます。救助された数だけ同行者数が減り、救助者数が追加され、画面に表示されます。収容可能人数は以下のコードによって取得された建物の高さ情報をもとに計算されています。

private void SelectGoal()
{
      var cityObjGroups =  targetParent.GetComponentsInChildren<PLATEAUCityObjectGroup>();
      var cityObjGroup = cityObjGroups.ElementAt(rnd.Next(0, cityObjGroups.Length));
      var target = cityObjGroup.transform;
      foreach (var cityObj in cityObjGsroup.GetAllCityObjects())
      {
       var attributes = cityObj.AttributesMap;
            if(attributes.TryGetValue("bldg:measuredheight", out var height))
            {
                  string buildingName = target.name;
                  string height = height.StringValue;
            }
}
}
図17-48 救助完了の様子

【文】

崎山 和正(株式会社シナスタジア)