ワールド・ポーズ・システム(WPS)を使ったアプリの作り方
ナイアンティック・ライトシップは、ワール ド・ポーズ・システム(WPS)を提供し、標準的なGPSよりも高い精度と安定性で、位置やコンパスの方位方角を取得することができます。 このチュートリアルでは、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);
} // 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;
// ここの座標を自分の位置で置き換える
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);
}.
}