ワールドポーズシステム(WPS)を使用してアプリをビルドする
Niantic Lightshipでは、標準的なGPSよりも高い精度と安定性で位置情報データやコンパスの方位を取得できるワールドポーズシステム(WPS)を提供しています。 このチュートリアルでは、UnityプロジェクトにWPSの基本機能を追加し、近くの場所にローカライズするように設定する方法を学びます。
前提条件
ARDKがインストールされているUnityプロジェクト、基本的なARシーン、そしてLightship Occlusionが必要です。 詳しくは、ARDK 3のインストール、ARシーンの設定、実世界オクルージョンの設定方法を参照してください。
また、プレイバック用のスキャンを作成する必要があります。 詳しくは、プレイバック用データセットの作成方法を参照してください。
この入門ガイドでオクルージョンを設定する際は、オクルージョンを設定するのステップ2(「キューブを追加する」セクション)をスキップし、オクルージョン抑制の設定の手順に従って、WPSオクルージョンをテストする際に空と地面を除外してください。
UnityプロジェクトにWPSを追加する
UnityプロジェクトにWPSを追加するには、次の手順を行います。
- 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 averaging に設定します。- Assets フォルダで右クリックし、 Create にマウスを合わせて C#スクリプト を選択します。 新しいスクリプトに
AddWPSObjects
という名前をつけます。 - Hierarchy に戻り、右クリックして Create Empty を選択し、新しい
GameObject
を追加します。WPSObjects
という名前を付けます。WPSObjects
を選択し、 Inspector で Add Component をクリックし、AddWPSObjects
をスクリプトコンポーネントとして追加します。
ロケーションを取得する
プロジェクトでWPSを使用する前に、プレイバックスキャンを作成した場所の緯度と経度を把握する必要があります。 ロケーションの座標を取得するには、以下の手順を行います。
- Googleマップを開き、再生スキャンをキャプチャした場所を探します。
- マップをクリックしてマーカーを追加します。
- マーカーを右クリックし、メニューの上部に表示される座標を選択してクリップボードにコピーします。
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()
{
}
}
スクリプトの内容を追加したら、アプリケーションをビルドして実行し、テストしてください。 配置した場所にキューブが表示されます。
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;
// ここに自分のロケーションの座標を入力
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つ目のキューブを作成し、GPSとコンパスを使用して予測された位置に移動させます
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);
}
}