Newer
Older
#if UNITY_ANDROID && ETSIARF_ARCORE_EXTENSIONS
using System;
using System.Collections.Generic;
using Google.XR.ARCoreExtensions;
using Unity.XR.CoreUtils;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using static WorldAnalysisARFoundationModule;
public class WorldAnalysisARFoundationModuleGeospatial : WorldAnalysisARFoundationModule
{
/// <summary>
/// Anchor manager
/// </summary>
private ARAnchorManager m_anchorManager;
/// <summary>
/// Earth manager
/// </summary>
private AREarthManager m_arEarthManager;
/// <summary>
/// List of geospatial anchors with tracking infos
/// </summary>
private Dictionary<string, TrackableInfo> m_trackedGeospatialAnchors = new Dictionary<string, TrackableInfo>();
/// <summary>
/// Correspondance between local trackable and etsi uuid
/// </summary>
private Dictionary<string, string> m_localIdToEtsiId = new Dictionary<string, string>();
/// <summary>
/// Check if ARCore Geospatial is supported on the device
/// </summary>
private bool geospatialSupported = true;
/// <summary>
/// Initialize ARCore geospatial anchors tracking module
/// </summary>
public void Initialize()
{
XROrigin origin = UnityEngine.Object.FindAnyObjectByType<XROrigin>();
m_anchorManager = origin.gameObject.GetComponent<ARAnchorManager>();
if (m_anchorManager == null)
{
m_anchorManager = origin.gameObject.AddComponent<ARAnchorManager>();
GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab");
m_anchorManager.anchorPrefab = anchorPrefab;
}
m_arEarthManager = origin.gameObject.AddComponent<AREarthManager>();
m_anchorManager.anchorsChanged += OnTrackedGeospatialAnchorChanged;
}
/// <summary>
/// Get the pose of the trackable from its uuid
/// <param name="uuid">id of the trackable</param>
/// <returns>null or trackableInfo with last updated values</returns>
public TrackableInfo GetPoseTrackable(Guid uuid)
{
if (m_trackedGeospatialAnchors.ContainsKey(uuid.ToString()))
{
return m_trackedGeospatialAnchors[uuid.ToString()];
}
else
{
return null;
}
}
/// <summary>
/// Need to be a geopose
/// </summary>
/// <param name="trackable"></param>
/// <returns>geopose or not (does not check is solved)</returns>
public bool AddTrackable(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable)
{
Debug.Log("GEO : Add Geosptial Trackable");
if (!geospatialSupported) return false;
if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.GEOPOSE)
{
return false;
}
CreateGeosptialAnchor(trackable);
return true;
}
/// <summary>
/// Initialize capability object with the features of the geospatial module
/// </summary>
/// <returns>null if ARCore Geospatial is not supported on the device, or a Capability object</returns>
public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability()
{
if (!geospatialSupported) return null;
ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityGeospatialAnchor = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability();
capabilityGeospatialAnchor.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE;
ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure();
encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARCORE;
encodingInformation.Version = "1.01";
capabilityGeospatialAnchor.EncodingInformation = encodingInformation;
capabilityGeospatialAnchor.Framerate = 30; // Not particularly specified on ARKit and ARCore
capabilityGeospatialAnchor.Latency = 0; // Not particularly specified on ARKit and ARCore
capabilityGeospatialAnchor.Accuracy = 1; // Not particularly specified on ARKit and ARCore
return capabilityGeospatialAnchor;
}
/// <summary>
/// Creates a new ARCore Geospatial anchor using informations from a geopose trackable object
/// </summary>
/// <param name="trackable"></param>
public async void CreateGeosptialAnchor(ETSI.ARF.OpenAPI.WorldStorage.Trackable trackable)
{
double[] values = new double[trackable.TrackablePayload.Length / sizeof(double)];
for (int i = 0; i < values.Length; i++)
{
values[i] = BitConverter.ToDouble(trackable.TrackablePayload, i * sizeof(double));
}
if (geospatialSupported)
{
while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None || ARSession.state == ARSessionState.SessionInitializing || m_arEarthManager.EarthState != EarthState.Enabled || m_arEarthManager.EarthTrackingState != TrackingState.Tracking)
{
Debug.Log("Geo : checking " + ARSession.state + " " + m_arEarthManager.EarthState + " " + m_arEarthManager.EarthTrackingState);
await System.Threading.Tasks.Task.Delay(100);
}
if (m_arEarthManager.IsGeospatialModeSupported(GeospatialMode.Enabled) != FeatureSupported.Supported)
{
geospatialSupported = false;
Debug.Log("Geo : not supported");
}
else
{
values = new double[trackable.TrackablePayload.Length / sizeof(double)];
for (int i = 0; i < values.Length; i++)
{
values[i] = BitConverter.ToDouble(trackable.TrackablePayload, i * sizeof(double));
}
Quaternion rotation = Quaternion.Euler((float)values[3], (float)values[4], (float)values[5]);
if (m_arEarthManager.EarthTrackingState == TrackingState.Tracking)
{
var anchor = m_anchorManager.AddAnchor(values[0], values[1], values[2], rotation);
m_localIdToEtsiId.Add(anchor.trackableId.subId2.ToString("X16"), trackable.UUID.ToString());
}
}
}
}
/// <summary>
/// Update geospatial anchors informations
/// </summary>
/// <param name="eventArgs">Event arguments for the <see cref="ARAnchorManager.anchorsChanged"/> event</param>
private void OnTrackedGeospatialAnchorChanged(ARAnchorsChangedEventArgs eventArgs)
{
foreach (var trackedGeospatialAnchor in eventArgs.updated)
{
Vector3 position = trackedGeospatialAnchor.transform.position;
Quaternion rotation = trackedGeospatialAnchor.transform.rotation;
TrackableInfo info = new TrackableInfo();
info.name = trackedGeospatialAnchor.name;
string localId = trackedGeospatialAnchor.trackableId.subId1.ToString("X16");// there must be a better way : does it work every time?
if (m_localIdToEtsiId.ContainsKey(localId))
{
info.name = m_localIdToEtsiId[localId];
}
else
{
//Debug.Log("ARCore Geospatial Anchor No correspondance for Local Anchor " + localId);
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
continue;
}
if (trackedGeospatialAnchor.trackingState == TrackingState.Tracking)
{
info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK;
info.confidence = 100;
}
else if (trackedGeospatialAnchor.trackingState == TrackingState.Limited)
{
info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK;
info.confidence = 50;
}
else
{
info.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.FAILURE; //ADD NOT_TRACKED ?
info.confidence = 0;
}
info.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
info.position = position;
info.rotation = rotation;
info.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.GEOPOSE;
m_trackedGeospatialAnchors[info.name] = info;
}
}
}
#endif