本文へスキップ

ワールドポーズシステム(WPS)を使用してアプリをビルドする

Niantic Lightshipでは、標準的なGPSよりも高い精度と安定性で位置情報データやコンパスの方位を取得できるワールドポーズシステム(WPS)を提供しています。 このチュートリアルでは、UnityプロジェクトにWPSの基本機能を追加し、近くの場所にローカライズするように設定する方法を学びます。

前提条件

ARDKがインストールされているUnityプロジェクト、基本的なARシーン、そしてLightship Occlusionが必要です。 詳しくは、ARDK 3のインストールARシーンの設定実世界オクルージョンの設定方法を参照してください。

また、プレイバック用のスキャンを作成する必要があります。 詳しくは、プレイバック用データセットの作成方法を参照してください。

備考

この入門ガイドでオクルージョンを設定する際は、オクルージョンを設定するのステップ2(「キューブを追加する」セクション)をスキップし、オクルージョン抑制の設定の手順に従って、WPSオクルージョンをテストする際に空と地面を除外してください。

UnityプロジェクトにWPSを追加する

UnityプロジェクトにWPSを追加するには、次の手順を行います。

  1. HierarchyXROrigin を選択し、InspectorAdd Component をクリックし、 ARWorldPositioningObjectHelper を追加します。 これにより、 ARWorldPositioningManager コンポーネントも作成されます。
  2. HierarchyXROriginCamera Offset を展開し、Main Camera を表示して選択します。 InspectorCameraClipping Planes を見つけ、 Far の値を1000に設定します。
  3. ARWorldPositioningObjectHelper コンポーネント で、 Altitude ModeCamera-relative with smart averaging に設定します。
  4. Assets フォルダで右クリックし、 Create にマウスを合わせて C#スクリプト を選択します。 新しいスクリプトに AddWPSObjects という名前をつけます。
  5. Hierarchy に戻り、右クリックして Create Empty を選択し、新しい GameObject を追加します。 WPSObjects という名前を付けます。 WPSObjects を選択し、 InspectorAdd Component をクリックし、 AddWPSObjects をスクリプトコンポーネントとして追加します。
WPS components in Unity with proper configuration

WPSスクリプトを作成する

スクリプトでWPSを基本的に使用するには、通常通り初期化し、 ARWorldPositioningObjectHelper から AddOrUpdateObject を呼び出して、WPSデータを使ってオブジェクトを更新します。 以下の例の AddWPSObjects.cs では、キューブを作成し、 ARWorldPositioningObjectHelper を使用してシーン内に動的に配置します。

備考

この方法を試す際には、スクリプト内の緯度と経度を、自分の近くのロケーション(リアルタイムテストの場合)やプレイバックスキャンの場所(リモートテストの場合)に設定してください。

クリックしてAddWPSObjects.csを表示
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Niantic.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);
}

// Updateメソッドはフレーム毎に1回呼び出される
void Update()
{

}
}

AddWPSObjects** コンポーネントを WPSObjects GameObject に追加し、positioningHelper フィールドに XROrigin GameObject の ARWorldPositioningManager コンポーネントを入力します。

場所の設定

プロジェクトでWPSを使用する前に、プレイバックスキャンを作成した場所の緯度と経度を把握する必要があります。 ロケーションの座標を取得するには、以下の手順を行います。

  1. Googleマップを開き、再生スキャンをキャプチャした場所を探します。
  2. マップをクリックしてマーカーを追加します。
  3. マーカーを右クリックし、メニューの上部に表示される座標を選択してクリップボードにコピーします。
  4. 緯度と経度の値を AddWPSObjects.cs に貼り付ける。

その後、アプリケーションをビルドして実行し、テストする。 配置した場所にキューブが表示されます。

ライブGPS位置情報の照会

あるいは、UnityのInput.location APIに問い合わせて、デバイスのライブGPS読み取り値を使用します:

クリックすると変更されたAddWPSObjects.csが表示されます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Niantic.Lightship.AR.WorldPositioning;

public class AddWPSObjects :MonoBehaviour
{
[SerializeField] ARWorldPositioningObjectHelper positioningHelper;

// Start は最初のフレーム更新の前に呼び出される
IEnumerator Start()
{
Input.location.Start();

// ロケーションサービスが初期化されるまで最大5秒待つ
int maxWait = 5;
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
{
yield return new WaitForSeconds(1);
maxWait--;
} // サービスが初期化されなかった場合。

//
if (maxWait < 1 || Input.location.status == LocationServiceStatus.Failed)
{
Debug.LogError("GPS failed to start");
yield break;
}

double latitude = Input.location.lastData.latitude;
double longitude = Input.location.lastData.longitude;
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.Lightship.AR.WorldPositioning;
using System;

public class AddWPSObjects :MonoBehaviour
{
[SerializeField] ARWorldPositioningObjectHelper positioningHelper;
[SerializeField] Camera trackingCamera;

// TODO: ここの座標をあなたの場所に置き換えてください。デフォルトはサンフランシスコのフェリービルです!
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);
}.
}

緯度と経度フィールドを、位置の設定セクションで取得したGPS座標で更新し、WPSとGPSを比較します。

結果例

Occluding a cube with a statue of Gandhi using WPS