デバイスマップを使用して仮想コンテンツを配置する
この機能は実験的なものであり、期待通りに動作しない可能性があります。 詳しくは、デバイスマッピング機能ページをご覧ください。
デバイスマップを作成し、ファイルに保存したので、これを読み込み、ARシーンに仮想オブジェクトを配置することができます。 この入門ガイドでは、デバイスマップファイルをUnityプロジェクトに読み込む方法と、それを使用してコンテンツを配置する方法について解説します。
前提条件
始める前に、デバイスマップを作成するを完了してください 。 このチュートリアルには、そのチュートリアルで作成したUnityプロジェクトが必要です。 また、基本的なキューブなど、仮想コンテンツとして配置するためのプレハブアセットが1つ必要です。
コンテンツをマップ上に配置する
-
Hierarchy から
DeviceMappingDemo
を選択し、 Inspector で Add Component をクリックします。 New Script を作成して追加し、Tracker.cs
という名前を付けます。 -
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
{
} -
Hierarchy で XROrigin を選択し、Inspector で Add Component をクリックし、
ARPersistentAnchorManager
を追加します。 -
これで永続的なアンカーマネージャーが追加されたので、使用するマッピングの種類を指定できるようになります。 次のスニペットを
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());
} -
デバイスマップを選択するためのUI要素を
Tracker
スクリプトに追加します。- トラッキングの開始と停止を行うためののボタンを追加します。
- Hierarchy で右クリックして Create メニューを開き、 UI サブメニューから Button を選択します。 これで、 Canvas が作成され、ボタンがその下に追加されます。
- スクリプト内に、 このボタンのシリアライズフィールドを追加します。
- プライベートメソッド
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()
{
} - トラッキングの開始と停止を行うためののボタンを追加します。
-
ボタンがクリックされるとトラッキング状態を切り替えるロジックを
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());
}
} -
ファイルからマップを使用してトラッキングを再開するためのコードスニペットを追加します。
ARDeviceMappingManager
用のシリアライズフィールドを追加します。- トラッキングを再開する前にいくつかの要素をクリーンアップする必要があります。
- 既存のアンカーがある場合は、破棄します。 状況によってはアンカーが破棄されるまでにフレームの遅れが生じることがあるため、少し待機してから次に進みます。
- トラッキングを再開するには、
ARPersistentAnchorManager
を無効にしてから再度有効にします。 位置データとロケーションマネージャーデータが非同期でクリーンアップされるように、トラッキングを停止してから再開するまでの間に少し待機します。
- クリーンアップが完了したら、保存済みのシリアライズ化されたマップデータを、以前保存したファイルから読み取って新しい
ARDeviceMap
を作成します。- シリアライズ化されたマップデータをメモリに読み込んでから、新しい
ARDeviceMap
を作成してARDeviceMappingManager.SetDeviceMap()
に渡し、トラッキングされるようにします。
- シリアライズ化されたマップデータをメモリに読み込んでから、新しい
- 新しいアンカーを使って再度トラッキングを開始するには、
ARPersistentAnchorManager.TryTrackAnchor()
を呼び出します。
-
このコードスニペットを
Tracker.cs
に追加したら、Hierarchy を開いて、 DeviceMappingDemo を選択します。 次に、 Inspector でTracker.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);
} -
アンカーが「トラッキング中」の状態になったら、デバイスマップに従って仮想オブジェクトを配置します。
- 仮想コンテンツを保持する変数を作成します。
- プレハブのシリアライズフィールド変数を追加し、これに自分のプレハブを割り当てます。
Start()
で、アンカー状態の変更に対するイベントリスナーを登録します。- イベント更新を処理する関数を作成します。
- アンカーがトラッキング状態にある場合、トラッキングされたアンカーを親オブジェクトとして、プレハブから仮想オブジェクトをインスタンス化します。
[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");
}
}
}
}