本文へスキップ

ワールドポーズシステム(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を使用する前に、プレイバックスキャンを作成した場所の緯度と経度を把握する必要があります。 ロケーションの座標を取得するには、以下の手順を行います。

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

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);
}
}

結果例

Occluding a cube with a statue of Gandhi using WPS