ESRIジャパンでは、ヤマハ発動機株式会社様と株式会社大林組様とともに森林のデジタルツインに関する共同研究を行い、その一環で ArcGIS Maps SDK for Unity (以下、ArcGIS SDK) を用いた Unity アプリの開発を行いました。先日そのプロジェクトを、弊社 GitHub にて公開いたしました。
本稿では、Unity アプリでどのように ArcGIS SDK 特有の要素が利用されているかご紹介し、その実装方法もお見せしていきます。
アプリの利用方法に関しては、GitHub の README をご参照ください。
本プロジェクトで ArcGIS SDK は主に 3 つの要素で使われています。それぞれ、①ベースマップの表示、②パッケージ ファイルの読み込み、③オブジェクトの座標管理です。順番に解説します。
1. ベースマップの表示
ベースマップの表示は GIS における基本的な機能です。もちろん、ArcGIS SDK でも用意されています。今回のアプリケーションでは、ArcGIS SDK の機能である Map Creator UI を利用してベースマップを生成しています。この Map Creator UI では、ArcGIS Online 上で管理されているレイヤーもご利用いただけます。本プロジェクトでは、周辺環境の再現として、清瀬市 3D 都市モデル(Project PLATEAU)を表示しています。Map Creator UI
また、今回は広域な森林の中のどこにいるかが直感的に伝わるように、もう 1 つのマップをミニマップとしても利用しています。ArcGIS SDK のバージョン 2.0 以降では、複数マップの表示がサポートされています。これにより、複数のマップを見比べることが可能になり、より表現の幅が広がりました。複数マップにつきましては、Esri のサンプルである Overview Map でも確認できます。
2. パッケージ ファイルの読み込み
本プロジェクトでは、StreamingAssets フォルダー配下にある「.tpkx」もしくは「.slpk」という拡張子のファイルを自動で読み込むようになっています。tpkx はタイル パッケージを指し、本プロジェクトでは標高を表現する地形情報であることを前提としています。また、slpk はシーン レイヤー パッケージを指し、本プロジェクトでは、3D オブジェクト シーン レイヤーの形式を前提としています。StreamingAssets フォルダー
これらのファイルは LoadPackage というスクリプトでゲーム内のマップに読み込んでいます。
例えば地形情報ですが、フォルダー内に見つからなかった場合は、ArcGIS Online が提供する Terrain 3D 標高データを取得し、読み込みます。
if(tpkxFiles.Length > 0)
{
for (int i = 0; i < tpkxFiles.Length; i++)
{
string elevationPath = tpkxFiles[i];
mapComponent.Map.Elevation = new ArcGISMapElevation(new ArcGISImageElevationSource(elevationPath, i.ToString(), ""))
{
ExaggerationFactor = elevEx
};
}
}
else
{
string elevationPath = "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
mapComponent.Map.Elevation = new ArcGISMapElevation(new ArcGISImageElevationSource(elevationPath, "Terrein 3D", ""))
{
ExaggerationFactor = elevEx
};
}また、本プロジェクトでは林道を 3D オブジェクト シーン レイヤーとして読み込んでいます。ファイルは tex_elev008_w07.slpk として StreamingAssets フォルダー内に格納されています。下記コードの「ArcGISLayerType」を別の値に書き換えるとその他のレイヤー タイプを読み込むことができるようになります。ぜひ、お手持ちのデータでお試しください。
if (slpkFiles.Length > 0)
{
for (int i = 0; i < slpkFiles.Length; i++)
{
string sceneLayerPath = slpkFiles[i];
ArcGISLayer layer = new ArcGISLayer(sceneLayerPath, ArcGISLayerType.ArcGIS3DObjectSceneLayer, "");
mapComponent.Map.Layers.Add(layer);
}
}
3. オブジェクトの座標管理
本プロジェクトではサンプル データとして、1000 本以上の立木を表示しています。これらの座標は StreamingAssets フォルダー内に格納されている CSV のデータを参照していますが、立木のオブジェクトすべてに ArcGIS Location Component というコンポーネントがアタッチされています。ArcGIS Location Component
しかし、上の画像をよく見ると緯度と経度(Latitude, Longitude)に関しては値が入力されていますが、高度(Altitude)は値が入力されていません。どのように高度を設定しているのでしょうか。
実は高度はコンポーネントの一番下にある Surface Placement で設定しています。この項目は、オブジェクトの高さを地形に対してどのように配置するかを決定する項目です。今回は没入感重視のため「On the Ground」で強制的に地表面にフィットさせています。この他にも、Altitude の値に準拠する「Absolute Height」と地表面との差分を設定できる「Relative to Ground」があります。
この設定は、TreeGenerator というスクリプトで行っています。この他にもオブジェクトの角度も同様に設定できるため、木によってばらつきを出すためにランダムな回転でバリエーションを出しています。
// LocationComponent 関連
var treeLocation = tree.GetComponent<ArcGISLocationComponent>();
if (treeLocation == null) treeLocation = Undo.AddComponent<ArcGISLocationComponent>(tree);
treeLocation.SurfacePlacementMode = ArcGISSurfacePlacementMode.OnTheGround;
treeLocation.Position = new ArcGISPoint(feature.POINT_X, feature.POINT_Y, 0, ArcGISSpatialReference.WGS84());
float randomizeAngle = UnityEngine.Random.Range(0.0f, 359.9f);
treeLocation.Rotation = new ArcGISRotation(randomizeAngle, 90, 0);Tips: キャラクターなどの移動体に「On the Ground」を設定すると、地表面に押さえつけられるようになるため、アニメーションなどと干渉し意図しない挙動を起こすことがあります。その場合は、「Absolute Height」の設定がおすすめです。
本プロジェクトでは森林管理のデジタルツイン化を目指し、ArcGIS SDK を用いて雑木林の再現を行いました。ArcGIS と森林管理や林業をつなぎ、ゲームエンジンの可能性を広げることができたら嬉しく思います。
植林や樹木の範囲指定など、まだまだ実装の余地があると私は思っています。本プロジェクトは GitHub で公開していますので、ご興味のある方はプロジェクトをクローンして、自由にご活用ください。