世界測位システム(WPS)を使ったアプリの作り方
ナイアンティック・ライトシップはワールド・ポジショニング・システム(WPS)を搭載しており、標準的なGPSよりも高い精度と安定性で位置やコンパスの方位を把握することができます。 このチュートリアルでは、Unityプロジェクトに基本的なWPS機能を追加し、近くにローカライズするように設定する方法を学びます。
前提条件
ARDKがインストールされたUnityプロジェクト、基本的なARシーン、Lightship Occlusionが必要です。 詳しくは、ARDK 3のインストール、ARシーンの設定、実世界オクルージョンの設定方法を参照してください。
また、再生スキャンを作成する必要があります。 詳しくは、再生用データセットの作成方法を参照してください。
このハウツーでオクルージョンを設定する場合は、オクルージョンの設定のステップ3と4(キューブを追加するステップ)をスキップして、オクルージョン抑制の設定のステップに従って、WPSオクルージョンのテスト時に空と地面を除外してください。
UnityプロジェクトにWPSを追加する
UnityプロジェクトにWPSを追加するには:
- Lightship GitHubからWPS UPMをダウンロードする。
- Unityのウィンドウトップメニューを開き、パッケージマネージャを選択します。 左上の**+**をクリックし、**Add package from tarball...**を選択します。 UPMを保存した場所に移動し、それを選択します。
- Hierarchy** で
XROrigin
を選択し、Inspector で Add Component をクリックしてARWorldPositioningObjectHelper
を追加します。 これはARWorldPositioningManager
コンポーネントも作成します。 - まだHierarchyにある
XROrigin
とCamera Offset
を展開してMain Camera
を露出させ、それを選択する。 Inspectorで、Cameraの下にあるClipping Planes**を探し、Farの値を1000に設定します。 - ARWorldPositioningObjectHelper`コンポーネントで、Altitude Mode をCamera-relative with smart averageaging に設定します。
- Assets**フォルダで右クリックし、Createの上にマウスを置き、C# Scriptを選択します。 新しいスクリプトの名前を
AddWPSObjects
とする。 - Hierarchy**に戻って右クリックし、Create Emptyを選択して新しい
GameObject
を追加します。 名前をWPSObjects
とする。 WPSObjectsを選択し、**Inspector** で **Add Component** をクリックし、スクリプトコンポーネントとして
AddWPSObjects` を追加します。
![WPS components in Unity with proper configuration](/docs/ja/assets/images/wps_components-7e018e60814e2c5fb3259c67f92a865c.png)
場所の確保
プロジェクトでWPSを使用する前に、再生スキャンを作成した場所の緯度と経度の座標を知る必要があります。 その場所の座標を取得する:
- Googleマップを開き、再生スキャンをキャプチャした場所を探します。
- 地図をクリックしてマーカーを追加します。
- マーカーを右クリックし、メニューの一番上にある座標を選択してクリップボードにコピーします。
WPSスクリプトの作成
スクリプトで WPS の基本的な使い方をする場合は、通常通り初期化し、ARWorldPositioningObjectHelper
から AddOrUpdateObject
を呼び出し、WPS データでオブジェクトを更新します。 以下の例では、AddWPSObjects.cs で立方体を作成し、ARWorldPositioningObjectHelper
を使ってシーンに動的に配置しています。
これを試すときは、スクリプトの緯度と経度を、あなたの近くの場所(ライブテストの場合)または再生スキャン(リモートテストの場合)に設定します。
クリックしてAddWPSObjects.csを表示する
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Niantic.Experimental.Lightship.AR.WorldPositioning;
public class AddWPSObjects :MonoBehaviour
{
[SerializeField] ARWorldPositioningObjectHelper positioningHelper;
// Start は最初のフレーム更新の前に呼び出される
void Start()
{
// ここの座標を自分の位置で置き換える
double latitude = 37.79534850764306;
double longitude = -122.39243231803636;
double altitude = 0.0; // カメラ相対位置決めを使用しているので、キューブをカメラと同じ高さに表示する
// キューブをインスタンス化し、可視性のためにスケールアップして(必要ならさらに大きくして)、その位置を更新する
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.localScale *= 2.0f;
positioningHelper.AddOrUpdateObject(cube, latitude, longitude, altitude, Quaternion.identity);
} // 1フレームにつき1回更新が呼び出される。
// Update はフレームごとに 1 回呼び出される
void Update()
{
}
}.
スクリプトの内容を追加したら、アプリケーションをビルドして実行し、テストします。 キューブは置いた場所に現れるはずです!
WPSとGPSの比較
WPSとGPSの違いを示すために、GPSを使用して2つ目のキューブを作成し、両方を一度に表示するスクリプト例も用意しました。 実際に試してみて、その違いを確かめてほしい!
クリックして比較スクリプトを表示
using UnityEngine;
using Niantic.Experimental.Lightship.AR.WorldPositioning;
using System;
public class AddWPSObjects :MonoBehaviour
{
[SerializeField] ARWorldPositioningObjectHelper positioningHelper;
[SerializeField] Camera trackingCamera;
// ここの座標を自分の位置に置き換える
double latitude = 37.795328;
double longitude = -122.392394;
double altitude = 0.0; // カメラ相対位置決めを使用しているので、立方体をカメラと同じ高さに表示する
// Start は最初のフレーム更新の前に呼び出される
void Start()
{
// 立方体をインスタンス化し、可視性のために拡大して(必要ならさらに大きくして)、位置を更新する
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.localScale *= 2.0f;
positioningHelper.AddOrUpdateObject(cube, latitude, longitude, altitude, Quaternion.identity);
} // 2つ目のキューブを作成して移動する。
//
private GameObject gpsCube = null;
void Update()
{
// まだキューブがない場合は、2つ目のキューブを作成する:
if(gpsCube == null)
{
gpsCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
gpsCube.GetComponent<Renderer>().material.color = Color.red;
}
if (Input.location.isEnabledByUser)
{
double deviceLatitude = Input.location.lastData.latitude;
double deviceLongitude = Input.location.lastData.longitude;
Vector2 eastNorthOffsetMetres = EastNorthOffset(latitude,longitude, deviceLatitude, deviceLongitude);
Vector3 trackingOffsetMetres = Quaternion.Euler(0, 0, Input.compass.trueHeading)*new Vector3(eastNorthOffsetMetres[0], (float)altitude, eastNorthOffsetMetres[1]);
Vector3 trackingMetres = trackingCamera.transform.localPosition + trackingOffsetMetres;
gpsCube.transform.localPosition = trackingMetres;
}.
}
public Vector2 EastNorthOffset(double latitudeDegreesA, double longitudeDegreesA, double latitudeDegreesB, double longitudeDegreesB)
{
double DEGREES_TO_METRES = 111139.0;
float lonDifferenceMetres = (float)(Math.Cos((latitudeDegreesA+latitudeDegreesB)*0.5* Math.PI / 180.0) * (longitudeDegreesA - longitudeDegreesB) * DEGREES_TO_METRES);
float latDifferenceMetres = (float)((latitudeDegreesA - latitudeDegreesB) * DEGREES_TO_METRES);
return new Vector2(lonDifferenceMetres,latDifferenceMetres);
}.
}
結果例
![Occluding a cube with a statue of Gandhi using WPS](/docs/ja/assets/images/wps_gandhi-cfa2fd674c6cca8193692897713e8dad.png)