TOPIC 23|3D都市モデルを使った位置情報共有ゲームを作る[1/2]|基本のゲームを作る
本トピックでは、位置情報をオンラインでやり取りしたり、サーバーで処理してサービスを提供したりするときの参考になるように、PLATEAUの3D都市モデルを活用した位置情報ゲームを作りながら、位置情報の扱い方を説明します。まずは基本のゲームを作ります。
近年、位置情報を基盤としたサービスが、よく使われるようになりました。Google MapsやUberなどは、その典型でしょう。自分の位置情報をスマートフォン(以下、スマホ)端末のGPSで取得し、サービスのサーバーに送信することで、利便性が向上します。本トピックでは、こうした位置情報をオンラインでやり取りしたり、サーバーで処理してサービスを提供したりするときの参考になるように、例としてPLATEAUの3D都市モデルを活用した位置情報ゲームを作りながら、位置情報の扱い方を説明します。まずは基本のゲームを作ります。
【目次】
23.2.3 Paint in 3Dを導入し、PLATEAUを塗れるようにする
23.2.4 Geospatial Anchorで3D都市モデルの位置を指定する
23.1 _ このトピックの見どころ
このトピックでは、ARアプリを実際に作りながら、構築のポイントと注意点を説明します。
主な見どころは、以下のとおりです。
・ARのための設定
UnityでARアプリを作るとき、どのようなライブラリをインストールして、どのような設定をしなければならないのか、その基本を説明します。
・3D都市モデルの読み込みと追従
3D都市モデルを読み込み、自分の位置情報と合わせ、現実と重ね合わせてPLATEAUの3D都市モデルが表示されるようにするには、どのようにすればよいのかを説明します。
・ペイントゲームを作る
例題として挙げるのは、ペイントゲームです。現実に重ね合わさったPLATEAUの3D都市モデルが表示され、それをクリックすると、色が塗られる仕組みです。
・サーバー側APIとデータ保存
ペイントゲームで塗った位置情報をサーバーに送信します。サーバー側では、このデータをPostGIS(PostgreSQLにGIS情報が扱えるモジュールを追加したもの)に保存し、分析できるようにします。
・QGISによる可視化
PostGISに保存された場所を可視化します。可視化には、オープンソースのGISソフトであるQGISを使います。
・アプリの開発と運用
最後の節では、実際にアプリを開発したり運用したりするにあたっての注意点を解説します。具体的には、APIの鍵をどのようにして安全に扱えるようにするか、Google PlayやApp Storeに登録するにはどうすればよいのかなどを説明します。
23.2 _ まずは基本のゲームを作る
本トピックでは、Unityでスマホ用AR位置情報ゲームを作ります。
ゲームを起動すると、プレイヤーは最初に赤緑青の三色から選び、自分が属する陣営を決めます。AR画面に切り替わると、端末カメラが映す、実際の街並みが表示されます。
PLATEAUの3D都市モデルを使い、タップするとその場所の建築物に「ペンキ」が塗られ、町中のいろいろなところを塗って最初の点までつないで閉じると、そこが自陣営の陣地になります。ゲームは獲得した陣地の面積を競います。
サーバーサイドにはPostGIS拡張をインストールしたPostgreSQLデータベースを使います。
面積は、ゲームプレイ時は、取った陣地の合計をサーバーで計算しますが、ゲーム終了後にバッチ処理で重ね合わせを考慮した結果の面積を計算する仕様にします。これは、時間順に重ね合わせて面積を計算する処理が、リアルタイムに計算にするには重いためです。
23.2.1 _ ARの設定をする
まずプロジェクトを作成し、基本のAR部分を設定します。
本プロジェクトでは、iOS・Androidを対象として、AR FoundationおよびARCore ExtensionでGeospatial APIを使います。
ARの設定については、TOPIC14 「VR・ARでの活用[3/3]|Google Geospa tial APIで位置情報による3D都市モデルのARを作成する」も参考にしてください。また、UnityでのAR開発の公式ドキュメントや、AR Foundationの公式ドキュメントなども必要に応じて参照してください。本稿では、最低限の説明のみとなります。
◾️プロジェクトの新規作成
まずはUnityで新規プロジェクトを作成します。ここでは、Unity 2022.3.7f1を使います。
プロジェクトは、「3D(URP)」テンプレートで作ります。プロジェクト名は、「PlacePLATEAU」とします(PLATEAUを使った陣取りゲームという意味の命名としました)。
◾️プロジェクトの設定
プロジェクトが開いたら、ARプロジェクトに必要な設定をしていきます。
【手順】ARプロジェクトに必要な設定をする
[1]AR FoundationとGeospatial APIのインストール
AR FoundationとGeospatial APIをインストールします。
[Window]メニューから[Package Manager]を開きます。
Package Managerが開いたら、[Unity Registry]を選択し、「AR Foundation」をインストールします。
何らかのダイアログボックスが開いたら、画面の指示どおりに進めてください。[New Input System]の有効化が必要であれば、表示されたダイアログボックスの指示に従い、再起動などをしてください。
[2]Apple ARKit XR Plugin、Google ARCore XR Pluginのインストール
同様にして、「Apple ARKit XR Plugin」、「Google ARCore XR Plugin」をインストールしてください。
この段階で、必要に応じてインストール済みのパッケージのアップデートも行っておくとよいでしょう。
[3]Geospatial APIのインストール
次に、「ARCore Extensions for AR Foundation」をインストールします。このパッケージに、Geospatial APIの機能が含まれます。インストールに際しては、ARCore Extensionsのドキュメントと、Geospatial APIのドキュメントも参考にしてください。
Package Managerの左上の[+]をクリックし、[Add package from git URL]を選択します。そして次のURLを貼り付け、[Add]をクリックします。
【Google ARCore Extensions and Geospatial Creator for Unity's AR Foundation】
https://github.com/google-ar/arcore-unity-extensions.git
ARCore Extensionsの画面が表示されたら、[Samples]の項目にある[Geospatial Sample]の[Import]をクリックして、このサンプルもインポートしてください。
[4]ARCoreおよびARKitの有効化
Unityの[Edit]メニューから[Project Settings]を開き、いくつかの設定を加えます。まずは、ARCoreおよびARKitを有効化します。
【Androidの場合】
ARCoreにチェックを付けて、有効化します。
【iOSの場合】
ARKitにチェックを付けて、有効化します。
[5]プロジェクトをARに最適な形に修正する
[XR Plug-in Management]の[Project Validation]では、プロジェクトの設定を自動的にARに最適な形に修正してくれます。もし、このタブでエラーなどが出ていたら、[Fix All]ボタンを押して修正してください。
[6]Geospatial APIのAPIキーを設定する
Geospatial APIのAPIキーを設定します。Google Cloudのコンソールで作成し、[XR Plug-in Management]の[ARCore Extensions]に設定してください。
詳細な手順は公式ドキュメントや、TOPIC14 「VR・ARでの活用[3/3]|Google Geospa tial APIで位置情報による3D都市モデルのARを作成する」の「■ APIキーの作成」の項目を参照してください。
この設定画面では、[iOS Support Enabled]および[Geospatial]にチェックを付けてください。
【注意】
ここでは説明を簡易にするため、APIキーをそのまま設定していますが、秘密情報をアプリに組み込むことになるため、セキュリティ的には推奨されません。
「23.4 アプリをリリースする」で、より適切な方法を説明します。APIキーのままでアプリを公開しないように気をつけてください。
[7]プラットフォームの設定を変更する
[Player]タブで、AndroidおよびiOSの各プラットフォームを、以下のように設定します。
【Androidの場合】
・Minimum API Levelは、28以上が妥当です。
・IL2CPPでビルドします。
・Graphics APIは、OpenGL ES3以上が必要です(Vulkanは外しておいたほうが無難です)。
・Target ArchitectureのARMv7のチェックを外します。
【iOSの場合】
・サポートするOSは、iOS12以上です。
・ARM64でビルドします。
・[Require ARKit Support]にチェックを付けます。
・[Location Usage Description]に、位置情報を使う際にユーザーに通知するメッセージの文字列を設定します。
[8]GeospatialConfigを修正する
次に、Unityの[Project]ビューに移り、「Assets/Samples/ARCore Extensions/1.38.0/Geospatial Samples/Configurations/GeospatialConfig」をクリックします。[Inspector]ビューの[Geospatial]を[Enabled]にします。
[9]Renderer-Featuresを設定する
同じく[Project]ウィンドウで、[Assets]―[Settings]に含まれるURPの設定項目をクリックし、[Inspector]で、[Renderer Features]に[AR Background Renderer Feature]が設定されていない場合は、追加してください。使用するURP設定項目がわからなければ、Settings以下のURP-XXXXのすべてに対して追加してください。
ここまでの設定で、Geospatial APIを使ったARアプリの基本の設定が終わりました。一度各プラットフォーム向けに「Geospatial Samples」の「Geospatial」シーンをビルド対象にして、動作確認のためにビルドしておくとよいでしょう。
23.2.2 _ PLATEAUの3D都市モデルを読み込む
「PLATEAU SDK for Unity」をインストールし、ゲーム対象地域の3D都市モデルを読み込みます。
PLATEAU SDK for Unity自体のインストール方法については、TOPIC22 「3D都市モデルと位置情報をUnityで扱う[1/2]|3D都市モデルを読み込んでさまざまな地理情報を重ねる」を参照してください。ここでは、PLATEAU SDK for Unityのインストールが完了し、Unityに[PLATEAU]メニューが追加されたことを前提に進めます。
次の手順で、3D都市モデルをインポートします。
【手順】3D都市モデルをインポートする
[1]作業用シーンの準備
まず、作業用のシーンを用意します。ここでは、Geospatial Sampleのサンプルシーンをコピーして、作業用シーンとして使います。
[Project]ウィンドウから、Assets/Samples/ARCore Extensions/1.38.0/Geospatial Samples/Scenes/Geospatialシーンを開きます。
[Hierarchy]ウィンドウのシーン名を右クリックしてメニューを開くと、シーンを別名で保存する[Save Scenes As]という選択肢があるのでそれを選び、Assets/Scenesなどに保存します。
[2]PLATEAU SDKを起動する
作業用シーンを準備できたら、[PLATEAU]メニューから[PLATEAU SDK]を選択し、SDKのダイアログを表示します。
インポートの画面では、[ローカル]と[サーバー]のどちらを選んでもかまいません。[ローカル]を選択した場合は、あらかじめダウンロードしておいた使いたい地域のPLATEAUの3D都市モデルを展開したフォルダを選択します。[サーバー]を選んだ場合は、使いたい地域を選択します。
[3]範囲を選択する
続いて、インポート範囲を選択します。
[範囲選択]ボタンをクリックすると、選択UIが起動するので、必要な範囲をマウスでドラッグして指定します。あまり広い範囲を指定してしまうと処理負荷がかかるので、気を付けてください。
[4]地物別設定をする
次に地物別設定をします。ここでは、建築物のLOD1のみを「地域単位」で結合してインポートします。
具体的には、次のようにします。
・建築物以外の[インポートする]のチェックを外す
・[Mesh Colliderをセットする]のチェックを外す
・[LOD描画設定]を「1」に設定する
・[テクスチャを含める]のチェックを外す
・モデル結合[地域単位]を設定する
[5]インポートする
以上の設定をしたら、[モデルをインポート]をクリックし、インポートを開始してください。
範囲やPCの性能にもよりますが、数分の時間がかかることもあります。
[6]シーンを確認する
インポートしたら、3D都市モデルがシーンに読み込まれたことを確認します。
23.2.3 _ Paint in 3Dを導入し、PLATEAUを塗れるようにする
以上が、ゲーム開発の基本となる準備です。ここから、PLATEAUを使ったゲームロジックを実装していきます。
最初に、ARでPLATEAUの3D都市モデルをタップすると、ビルに印が塗られる仕組みを作ってみます。
◾️Paint in 3Dのインストール
印を塗るための処理として、Unity Asset Storeで「Paint in 3D」というアセットを購入($66)して、使うことにします。
このアセットは、3Dのオブジェクトにお絵描きができるようにするものです。購入したら通常のアセットの導入と同様に、Unity Package Managerからインストールしてください。
【Paint in 3D】
https://assetstore.unity.com/packages/tools/painting/paint-in-3d-26286
【メモ】
少し複雑になりますが、例えばコライダーとレイキャストの機能を使って、タップ位置からの当たり判定を計算し、そこにオブジェクトを表示するなどすれば、有料アセットを使わなくても、近い処理ができると思います。興味のある人はチャレンジしてみてください。
◾️3D都市モデルを分割する
さて、読み込んだままのPLATEAUの3D都市モデルだと、Paint in 3Dで使うのに不便です。その理由は、Paint in 3Dの描画の仕組みにあります。
Paint in 3Dは、設定したテクスチャ画像に描画することで、3Dモデルに描画しているように見せています。そのため、広範囲の3Dモデルを結合した巨大なモデルを対象とした場合、テクスチャの解像度が足りずジャギーが発生したりモザイクのようになったりしてしまいます。逆に、3Dモデルを細かく分割し、それぞれに高解像度のテクスチャを貼ってしまうと、今度は、描画が非常に高負荷になってしまいます。
ここでは、読み込んだPLATEAUの3D都市モデルを9分割して、「Mesh Combiner」というアセットで結合することで、テクスチャの品質と描画負荷のバランスのよい設定にします。
Unity Asset StoreでMesh Combinerを入手し、プロジェクトにインストールしてください。
【Mesh-Combiner】
https://assetstore.unity.com/packages/tools/modeling/mesh-combiner-157192
次のように操作することで、9分割して結合します。
【手順】3D都市モデルを9分割して結合する
[1]手作業で9つに分ける
まずはUnity上で、読み込んだ3D都市モデルをマウスで選択しながら、まとめるための空のGameObjectの子にしていき、縦横それぞれ3分割した9つのGameObjectに分けた階層構造にします。
[2]メッシュ結合する
Assets/MeshCombiner/Scripts/MeshCombiner.csを、9分割したそれぞれのGameObjectにドラッグ&ドロップしてアタッチします。
[Deactivate Combined Children]と[Generate UV Map]にチェックを付けて、[Combine Meshes]をクリックし、メッシュを結合します。正しく結合されていることがわかったら、子オブジェクトは消してしまっても問題ありません。
◾️メッシュの調整
Paint in 3Dは、モデルのUV座標に基づいて、テクスチャのどこにペイントするかを判定します。そのため、モデルに正しくUV座標が設定されていないと、おかしな描画になってしまいます。
Mesh Combinerで結合する際、UVは自動的に生成されていますが、現在の状態では、UV座標がUV1に格納されています。これをPaint in 3Dの機能を使って、UV0にコピーします。
【手順】UV1をUV0にコピーする
[1]FBXにエクスポートする
一度、FBXにエクスポートします。FBXにエクスポートするには、「FBX Exporter」というアセットを使います。Package Managerからインストールしてください。
FBXに変換するには、[Hierarchy]ウィンドウで、モデルを右クリックし、[Export to FBX...]を選択します。Mesh Combinerで結合したGameObjectを右クリックして、この操作をします。
エクスポートのオプションは、図23-25のとおりです。
・ [Export Name][Export Path]
書き出すファイル名と場所です。任意の場所を設定します。
・[Export Format]
エクスポートする際のファイルフォーマットです。Binaryにします。
・[Include]
エクスポートするデータに、どのような情報を含めるかの設定です。3Dモデルしか必要ないので、[Model(s)Only]にします。
その他のオプションはデフォルトもしくは図のように設定してください。
[2]UV0にコピーしたメッシュを作る
エクスポート時に指定したフォルダにFBXとして書き出され、[Project]ウィンドウに表示されます。
エクスポートしたFBXの階層を開き、MeshのInspectorを表示し、右側のメニューを開くと、「Coord Copier(Paint in 3D)」があるのでこれを選択します。
設定画面が開いたら、図23-27に示す設定をして、[Generate]ボタンをクリックします。
この設定は、モデルのUV座標を入れ替えるものです。
3Dモデルは、さまざまな用途で使えるようにするため、一つの頂点につき複数のUV座標を持てる構造になっています。今回用意したモデルでは、Paint in 3Dで使いたいUV座標が2番目に格納されています。これを1番目のUV座標にするため、[First]に[Second]を設定することで、2番目のUV座標を一番目に移動させます。2番目以降は[None]にしておくことで削除し、余分なUV座標が3Dモデルのサイズを大きくすることを防ぎます。
[3]メッシュを再設定する
すると、UV1の内容をUV0にコピーしたメッシュが新しく作成されます。
これを、元のメッシュの代わりに3D都市モデルのMesh FilterのMeshに設定します。
これで、Paint in 3D用に変換されたメッシュの準備ができました。
この一連の操作を、9つのGameObjectすべてに対して、行ってください。
◾️衝突判定用のColliderを追加する
次に、これらの9つのGameObjectそれぞれに、ペイントの衝突判定用にMesh Colliderを追加します。
◾️建築物をペイントできるようにする
結合したメッシュ(9個のGameObjectすべて)に対して、次の設定をすることで、Paint in 3Dで建築物をペイントできるようにします。
【手順】建築物をペイントできるようにする
[1]Make Paintableにする
結合したメッシュを選択し、InspectorのMesh Rendererの右肩のメニューボタンからメニューを開き、[Make Paintable(Paint in 3D)]を選択します。
[2]コンポーネントを追加する
P3D Paintableコンポーネントの画面が表示されたら、[Add Material Cloner]と[Add Paintable Texture]のボタンをそれぞれクリックし、コンポーネントを追加します。
[3]Paintable Textureを設定する
P3D Paintable Textureの設定を、図23-33のように変更します。Sizeを2048x2048に、ColorをR:0,G:0,B:0,A:0にしています。これでAR表示したときに、塗られていないところは完全な透過となります。
[4]マテリアルを設定する
Paint in 3Dは、モデルのテクスチャにペイントした結果を描画しますが、そのために、表示のための専用のペイント用のマテリアルが必要です(Paint in 3Dが自動的に実行時にコピーしてくれるので、このマテリアルを一個作成すればすべての3D都市モデルで共有できます)。
適当なフォルダにマテリアルを新規に作り、シェーダーを「Paint in 3D/Overlay」にします。
このマテリアルを建築物モデルに適用します。
なお、P3D Paintableの「Analyze Mesh」ボタンを押すと、現在のメッシュのUV座標を確認できます。
図のように、CoordにUV0を指定した状態で、矩形が多く並んだような状態になっていれば、ここまでの手順で正しく変換されていると考えられます。
これらの設定を、分割したすべてのモデルに対して行います。
【メモ】
ここまで説明してきたように、ゲームエンジンでPLATEAUの3D都市モデルを表示する以上の活用をしようとすると、ゲームエンジンのさまざまな機能の活用やその仕組みの理解が必要です。また、適切に3D都市モデルのデータを変換や調整していくことも必要です。
幸いにも、UnityやUnreal Engineには、公式非公式問わず、さまざまな入門コンテンツやサンプルが充実しています。一歩進んだ応用を目指して活用してみましょう。
◾️描画を制御するコンポーネントを追加する
最後に、Paint in 3Dの描画を制御するコンポーネントを追加します。
[Hierarchy]ウィンドウで、空のGameObjectを一つ追加し、「P3D Hit Screen」コンポーネントと「P3D Paint Sphere」コンポーネントを追加します。それぞれのコンポーネントは図23-36のように設定してください。
[P3D Hit Screen]の項目でデフォルトから変更するところは以下のとおりです。
・[Layers]を[Default]のみを選択した状態とします。
・[Camera]にシーン内の[AR Camera]を設定します。
・[Frequency]を[Once On Press]に設定し、タップしたときだけペイントされるようにします。
・[Advanced]内の[Store States]はチェックを外しておきます。
[P3D Paint Sphere]の項目でデフォルトから変更するところは、以下のとおりです。
・[Layers]を[Default]のみとします。
・[Blend Mode]を[Additive]に設定します。
・[Color]をいったん赤などわかりやすい色にしておきます。
・[Radius]を2にして、ペイントする球の半径を大きくして見やすくしておきます。
さらに、「P3D Pointer Mouse」と「P3D Pointer Touch」を追加します。これらはデフォルトの設定でかまいません。
ここまでで、建築物をペイントする仕組みができました。
Editor上で実行すると、マウスでクリックすると3D都市モデルにペイントできるようになっていることがわかります。確認してみてください。
【メモ】
PLATEAUの3D都市モデルは巨大なので、どうしてもテクスチャの解像度を上げるのが難しい場合があります。場合によっては、ドット絵風など、表現を工夫することも考えられます。その際には、[P3D Paintable Texture]の[Advanced/Filter]の設定を[Point]に変えると、ドット絵がくっきり見えるようになります。
23.2.4 _ Geospatial Anchorで3D都市モデルの位置を指定する
次に、Geospatial Anchorを設定することで、自分の位置と3D都市モデルの位置が合うようにします。
詳細は公式ドキュメントや、TOPIC14 「VR・ARでの活用[3/3]|Google Geospa tial APIで位置情報による3D都市モデルのARを作成する」を参照してください。
作成した3D都市モデルの親要素に、Geospatial APIの地理空間アンカーを利用して位置合わせを行う以下のAnchor.csスクリプトをアタッチします。また、このAnchor.csをアタッチしたゲームオブジェクト(3D都市モデル)を、AR Session Originの子要素に移動しておきます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using Google.XR.ARCoreExtensions;
public class Anchor : MonoBehaviour
{
public AREarthManager EarthManager;
public ARAnchorManager AnchorManager;
public double lat, lon, height;
private bool _isInitialized = false;
// Update is called once per frame
void Update()
{
// isInitializedフラグを見て、初回1回だけ実行
if (!_isInitialized && EarthManager.EarthTrackingState == TrackingState.Tracking)
{
var anchor = AnchorManager.AddAnchor(
lat,
lon,
height,
Quaternion.identity
);
// このアンカーを親として設定する
// そうすることで配下のオブジェクトは、設定した地理座標の位置に配置される。
gameObject.transform.parent = anchor.transform;
_isInitialized = true;
}
}
}
リスト 23-1 Anchor.csスクリプト
このスクリプトは、EarthManager、AnchorManager、lat、lon、heightの5つのプロパティを持ちます。それぞれ適切に設定します。
・EarthManagerとAnchorManager
AR Session Originへの参照を設定します。
・lat、lon、height
経緯度と高さを設定します。
緯度(lat)および経度(lon)は、読み込んだPLATEAUの3D都市モデルの中心の経緯度を設定します。SDKのインスペクターで表示されている経緯度を確認して入力してください。
高さ(height)は、地理空間アンカーにおいては、楕円体高なので、国土地理院のサイトなどを参考にしてジオイド高を加味した楕円体高を設定します。プロジェクトに読み込んでいる3D都市モデルの原点の高さは標高0mなので、ここではheightにはその地点のジオイド高を入力します。東京の平野部ではおよそ37mくらいの値を設定しておくと大体合うと思いますが、精確を期す場合は国土地理院のサイトなどで正しく計算したものを取得しましょう。
【文】
於保俊(株式会社ホロラボ)
【協力】
大澤文孝