本文へスキップ

デバイスマップを使用して仮想コンテンツを配置する

注目してほしい!

この機能は実験的なものであり、期待通りに動作しない可能性があります。 詳しくは、デバイスマッピング機能ページをご覧ください。

デバイスマップを作成し、ファイルに保存したので、これを読み込み、ARシーンに仮想オブジェクトを配置することができます。 この入門ガイドでは、デバイスマップファイルをUnityプロジェクトに読み込む方法と、それを使用してコンテンツを配置する方法について解説します。

前提条件

始める前に、デバイスマップを作成するを完了してください。 このチュートリアルには、そのチュートリアルで作成したUnityプロジェクトが必要です。 また、基本的なキューブなど、仮想コンテンツとして配置するためのプレハブアセットが1つ必要です。

コンテンツをマップ上に配置する

  1. Hierarchy から DeviceMappingDemo を選択し、 InspectorAdd Component をクリックします。 New Script を作成して追加し、 Tracker.cs という名前を付けます。

  2. Tracker.cs を開き、その内容を次のスニペットに置き換えます。

    using System.Collections;
    using System.IO;
    using Niantic.Lightship.AR.Mapping;
    using Niantic.Lightship.AR.PersistentAnchors;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.XR.ARSubsystems;

    public class Tracker : MonoBehaviour
    {

    }
  3. HierarchyXROrigin を選択し、InspectorAdd Component をクリックし、 ARPersistentAnchorManager を追加します。

  4. これで永続的なアンカーマネージャーが追加されたので、使用するマッピングの種類を指定できるようになります。 次のスニペットを Tracker クラスに追加します。

    // initialize the manager
    [SerializeField]
    private ARPersistentAnchorManager _persistentAnchorManager;

    private void Start()
    {
    // tell it we want device mapping (aka "slick" mapping)
    _persistentAnchorManager.DeviceMappingLocalizationEnabled = true;
    _persistentAnchorManager.CloudLocalizationEnabled = false;
    // enable continuous localization to mitigate tracking drift
    _persistentAnchorManager.ContinuousLocalizationEnabled = true;
    _persistentAnchorManager.TemporalFusionEnabled = true;
    _persistentAnchorManager.TransformUpdateSmoothingEnabled = true;
    _persistentAnchorManager.DeviceMappingLocalizationRequestIntervalSeconds = 0.1f;

    // start the manager with our options
    StartCoroutine(_persistentAnchorManager.RestartSubsystemAsyncCoroutine());
    }
  5. デバイスマップを選択するためのUI要素を Tracker スクリプトに追加します。

    1. トラッキングの開始と停止を行うためののボタンを追加します。
      1. Hierarchy で右クリックして Create メニューを開き、 UI サブメニューから Button を選択します。 これで、 Canvas が作成され、ボタンがその下に追加されます。
      2. スクリプト内に、 このボタンのシリアライズフィールドを追加します。
    2. プライベートメソッド OnStartTrackingClicked() を作成し、 Start() でボタンクリックをリッスンするようにします。
    [SerializeField]
    private Button _startTrackingButton;

    private void Start()
    {
    // Add this below the previous section's code in Start()
    // Listen for button click event
    _startTrackingButton.onClick.AddListener(OnStartTrackingClicked);
    }

    // When tracking button is clicked
    private void OnStartTrackingClicked()
    {
    }

  6. ボタンがクリックされるとトラッキング状態を切り替えるロジックを Tracker.cs に追加します。

    private ARPersistentAnchor _anchor;
    // variable for reference to the object on the map
    private GameObject _anchorVisualObject;
    private bool _isTrackingRunning;

    // When tracking button is clicked
    private void OnStartTrackingClicked()
    {
    var buttonText = _startTrackingButton.GetComponentInChildren<Text>();
    if (_isTrackingRunning)
    {
    // Stop tracking if running and clean up anchor
    if (_anchor)
    {
    _persistentAnchorManager.DestroyAnchor(_anchor);
    _anchor = null;
    _anchorVisualObject = null;
    }
    buttonText.text = "Start Tracking";
    _isTrackingRunning = false;
    }
    // otherwise, change the button to "stop" and start tracking
    else
    {
    buttonText.text = "Stop Tracking";
    _isTrackingRunning = true;
    StartCoroutine(RestartTracking());
    }
    }
  7. ファイルからマップを使用してトラッキングを再開するためのコードスニペットを追加します。

    1. ARDeviceMappingManager 用のシリアライズフィールドを追加します。
    2. トラッキングを再開する前にいくつかの要素をクリーンアップする必要があります。
      1. 既存のアンカーがある場合は、破棄します。 状況によってはアンカーが破棄されるまでにフレームの遅れが生じることがあるため、少し待機してから次に進みます。
      2. トラッキングを再開するには、 ARPersistentAnchorManager を無効にしてから再度有効にします。 位置データとロケーションマネージャーデータが非同期でクリーンアップされるように、トラッキングを停止してから再開するまでの間に少し待機します。
    3. クリーンアップが完了したら、保存済みのシリアライズ化されたマップデータを、以前保存したファイルから読み取って新しい ARDeviceMap を作成します。
      1. シリアライズ化されたマップデータをメモリに読み込んでから、新しい ARDeviceMap を作成して ARDeviceMappingManager.SetDeviceMap() に渡し、トラッキングされるようにします。
    4. 新しいアンカーを使って再度トラッキングを開始するには、 ARPersistentAnchorManager.TryTrackAnchor() を呼び出します。
  8. このコードスニペットを Tracker.cs に追加したら、Hierarchy を開いて、 DeviceMappingDemo を選択します。 次に、 InspectorTracker.cs を見つけ、スクリプト内のフィールドに XROrigin から ARDeviceMappingManager を割り当てます。

    [SerializeField]
    private ARDeviceMappingManager _deviceMappingManager;

    private IEnumerator RestartTracking()
    {
    if (_anchor)
    {
    _persistentAnchorManager.DestroyAnchor(_anchor);
    _anchor = null;
    _anchorVisualObject = null;
    }
    // wait a moment after destroying anchor
    yield return null;

    _persistentAnchorManager.enabled = false;

    // wait a moment before toggling tracking
    yield return null;

    _persistentAnchorManager.enabled = true;

    // Read a new device map from file
    var path = Path.Combine(Application.persistentDataPath, Mapper.MapFileName);
    var serializedDeviceMap = File.ReadAllBytes(path);
    var deviceMap = ARDeviceMap.CreateFromSerializedData(serializedDeviceMap);

    // Assign the device map to the mapping manager
    _deviceMappingManager.SetDeviceMap(deviceMap);

    // Set up tracking with a new anchor
    _persistentAnchorManager.TryTrackAnchor(
    new ARPersistentAnchorPayload(deviceMap.GetAnchorPayload()),
    out _anchor);
    }
  9. アンカーが「トラッキング中」の状態になったら、デバイスマップに従って仮想オブジェクトを配置します。

    1. 仮想コンテンツを保持する変数を作成します。
      1. プレハブのシリアライズフィールド変数を追加し、これに自分のプレハブを割り当てます。
    2. Start() で、アンカー状態の変更に対するイベントリスナーを登録します。
    3. イベント更新を処理する関数を作成します。
      1. アンカーがトラッキング状態にある場合、トラッキングされたアンカーを親オブジェクトとして、プレハブから仮想オブジェクトをインスタンス化します。
    [SerializeField]
    private GameObject _locationAnchorPrefab;

    private void Start()
    {
    // Add this below the previous section's code in Start()
    // Listen for anchor updates and catch them
    _persistentAnchorManager.arPersistentAnchorStateChanged += OnArPersistentAnchorStateChanged;
    }

    // Event listener for anchor updates
    private void OnArPersistentAnchorStateChanged(ARPersistentAnchorStateChangedEventArgs args)
    {
    if (args.arPersistentAnchor.trackingState == TrackingState.Tracking)
    {
    if (!_anchorVisualObject)
    {
    _anchorVisualObject = Instantiate(_locationAnchorPrefab, _anchor.transform);
    Debug.Log("Tracking");
    }
    }
    }

これで、仮想オブジェクトが表示されるようになります。

トラッカーの完成版スクリプト

トラッキングスクリプトの作成でお困りの場合は、以下の完成版スクリプトを参考にしてください。

クリックして最終版のTracker.csスクリプトを表示
using System.Collections;
using System.IO;
using Niantic.Lightship.AR.Mapping;
using Niantic.Lightship.AR.PersistentAnchors;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARSubsystems;

public class Tracker : MonoBehaviour
{
// initialize the managers, prefab, menu, and map file I/O
[SerializeField]
private ARPersistentAnchorManager _persistentAnchorManager;

[SerializeField]
private ARDeviceMappingManager _deviceMappingManager;

[SerializeField]
private GameObject _locationAnchorPrefab;

[SerializeField]
private Button _startTrackingButton;

private GameObject _anchorVisualObject;
private ARPersistentAnchor _anchor;
private bool _isTrackingRunning;

private void Start()
{
// Event listeners for anchor and drop-down menu
_persistentAnchorManager.arPersistentAnchorStateChanged += OnArPersistentAnchorStateChanged;
_startTrackingButton.onClick.AddListener(OnStartTrackingClicked);

// tell it we want device mapping (aka "slick" mapping)
_persistentAnchorManager.DeviceMappingLocalizationEnabled = true;
_persistentAnchorManager.CloudLocalizationEnabled = false;
// enable continuous localization to mitigate tracking drift
_persistentAnchorManager.ContinuousLocalizationEnabled = true;
_persistentAnchorManager.TemporalFusionEnabled = true;
_persistentAnchorManager.TransformUpdateSmoothingEnabled = true;
_persistentAnchorManager.DeviceMappingLocalizationRequestIntervalSeconds = 0.1f;

// restart the manager with our options
StartCoroutine(_persistentAnchorManager.RestartSubsystemAsyncCoroutine());
}

// When tracking button is clicked
private void OnStartTrackingClicked()
{
var buttonText = _startTrackingButton.GetComponentInChildren<Text>();
if (_isTrackingRunning)
{
// Stop tracking if running
if (_anchor)
{
_persistentAnchorManager.DestroyAnchor(_anchor);
_anchor = null;
_anchorVisualObject = null;
}
buttonText.text = "Start Tracking";
_isTrackingRunning = false;
}
else
{
buttonText.text = "Stop Tracking";
_isTrackingRunning = true;
StartCoroutine(RestartTracking());
}
}

private IEnumerator RestartTracking()
{
if (_anchor)
{
_persistentAnchorManager.DestroyAnchor(_anchor);
_anchor = null;
_anchorVisualObject = null;
}
yield return null;

_persistentAnchorManager.enabled = false;

// start tracking after stop tracking needs "some" time in between...
yield return null;

_persistentAnchorManager.enabled = true;

// Read a new device map from file
var path = Path.Combine(Application.persistentDataPath, Mapper.MapFileName);
var serializedDeviceMap = File.ReadAllBytes(path);
var deviceMap = ARDeviceMap.CreateFromSerializedData(serializedDeviceMap);

// Assign the device map to the mapping manager
_deviceMappingManager.SetDeviceMap(deviceMap);

// Set up tracking with a new anchor
_persistentAnchorManager.TryTrackAnchor(
new ARPersistentAnchorPayload(deviceMap.GetAnchorPayload()),
out _anchor);
}

// Event listener for anchor updates
private void OnArPersistentAnchorStateChanged(ARPersistentAnchorStateChangedEventArgs args)
{
if (args.arPersistentAnchor.trackingState == TrackingState.Tracking)
{
if (!_anchorVisualObject)
{
_anchorVisualObject = Instantiate(_locationAnchorPrefab, _anchor.transform);
Debug.Log("Tracking");
}
}
}
}