Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#if UNITY_IOS
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARKit;
using System.IO;
using Unity.XR.CoreUtils;
using static WorldAnalysisARFoundationModule;
using ETSI.ARF.OpenAPI.WorldStorage;
using Unity.Collections;
public class WorldAnalysisARFoundationModuleARKitWorldMap : WorldAnalysisARFoundationModule
{
/// <summary>
/// Anchor manager
/// </summary>
private ARAnchorManager m_anchorManager;
///Has loaded a worl map
private bool m_hasAddedMap ;
/// Possible trackable id (arfoundation) of an anchor contained in the world map. Take the pose of this anchor if it exists or zero
private string m_arfoundationAnchorTrackableId ;
/// uuId of the map trackabled
private Guid m_trackedUUID ;
/// computed and updated pose
private TrackableInfo m_trackedPose ;
/// <summary>
/// Initialize image tracking module
/// </summary>
public void Initialize()
{
XROrigin origin = UnityEngine.Object.FindAnyObjectByType<XROrigin>();
m_anchorManager = origin.gameObject.AddComponent<ARAnchorManager>();
GameObject anchorPrefab = (GameObject)Resources.Load("ARFAnchorTrackingPrefab");
m_anchorManager.anchorPrefab = anchorPrefab;
m_anchorManager.anchorsChanged += OnTrackedAnchorChanged;
m_trackedPose = null ;
m_hasAddedMap= false ;
}
/// <summary>
/// found
/// </summary>
/// <param name="uuid">name of the mesh trackable</param>
public TrackableInfo GetPoseTrackable(Guid uuid)
{
if (m_trackedPose != null)
{
if (m_trackedUUID == uuid)
{
return m_trackedPose ;
}
}
return null;
}
/// <summary>
/// Add a trackable : need to be a map
/// </summary>
/// <param name="trackable">Image trackable</param>
/// <returns>Supported or not</returns>
public bool AddTrackable(Trackable trackable)
{
if (trackable.TrackableType != ETSI.ARF.OpenAPI.WorldStorage.TrackableType.MAP)
{
return false;
}
if (m_hasAddedMap)
{
Debug.Log("Only one ARKit map can be loaded");
return false ;
}
// Check if a map url is provided
string url = "" ;
if (trackable.KeyvalueTags.ContainsKey("url"))
{
foreach(string s in trackable.KeyvalueTags["url"])
{
// first one
url = s ;
break ;
}
}
bool resul = AddWorldMapToARKit(url);
m_trackedUUID = trackable.UUID ;
m_arfoundationAnchorTrackableId = trackable.Name ;
m_hasAddedMap = resul ;
return resul;
}
/// <summary>
/// Initialize capability object with Mesh tracking
/// </summary>
public ETSI.ARF.OpenAPI.WorldAnalysis.Capability GetSupportedCapability()
{
ETSI.ARF.OpenAPI.WorldAnalysis.Capability capabilityMesh = new ETSI.ARF.OpenAPI.WorldAnalysis.Capability();
capabilityMesh.TrackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP;
ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure encodingInformation = new ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructure();
encodingInformation.DataFormat = ETSI.ARF.OpenAPI.WorldAnalysis.EncodingInformationStructureDataFormat.ARKIT;
encodingInformation.Version = "1.01";
capabilityMesh.EncodingInformation = encodingInformation;
capabilityMesh.Framerate = 30; // Not particularly specified on ARKit
capabilityMesh.Latency = 0; // Not particularly specified on ARKit
capabilityMesh.Accuracy = 1; // Not particularly specified on ARKit
return capabilityMesh ;
}
/// <summary>
/// Callback when Unity anchors are updated
/// </summary>
/// <param name="eventArgs">update values</param>
private void OnTrackedAnchorChanged(ARAnchorsChangedEventArgs eventArgs)
{
foreach (var trackedAnchor in eventArgs.updated)
{
Debug.Log("Anchor found " +trackedAnchor.trackableId.ToString());
if (trackedAnchor.trackableId.ToString() == m_arfoundationAnchorTrackableId)
{
/// look for an anchor with the trackable Id correspond to the ETSI ARF trackable name
UpdateTrackableInfoWithPose(trackedAnchor.transform.position,trackedAnchor.transform.rotation);
break ;
}
}
}
/// <summary>
/// Add a map to arkitsubsystem : check local file exist or download from given url
/// </summary>
/// <param name="url">url of a map to download</param>
/// <returns>found or not</returns>
protected bool AddWorldMapToARKit(string url)
{
if (url.Length > 0)
{
Debug.Log("Load AR Map from URL");
LoadWorldMapFromURL(url);
// don't check if url is valid
return true ;
}
else
{
Debug.Log("Load AR Map locally");
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
string localMap = Application.persistentDataPath + "/ARkitWorlMap.map";
if (File.Exists(localMap))
{
var coroutine = CoroutineLoadWorldMap(localMap);
WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine);
return true ;
}
}
// no url and no local map
return false ;
}
/// <summary>
/// Update pose of the map trackable
/// </summary>
/// </param name="position"> evaluated position of trackable/param>
/// </param name="rotation"> evaluated rotation of the trackable</param>
private void UpdateTrackableInfoWithPose(Vector3 position, Quaternion rotation)
{
m_trackedPose = new TrackableInfo();
m_trackedPose.name = m_arfoundationAnchorTrackableId;
m_trackedPose.state = ETSI.ARF.OpenAPI.WorldAnalysis.PoseEstimationState.OK; // here : could check the state of the ARKit slam
m_trackedPose.confidence = 100;
m_trackedPose.timeStamp = unchecked((int)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
m_trackedPose.position = position;
m_trackedPose.rotation = rotation;
m_trackedPose.trackableType = ETSI.ARF.OpenAPI.WorldAnalysis.TrackableType.MAP;
}
/// <summary>
/// Load a world map from a url
/// </summary>
/// </param name="url"> url to the worlmap to download</param>
private async void LoadWorldMapFromURL(string url)
{
Debug.Log("Download WorlMap from url "+ url);
KeyValuePair<string , string> downloaded = await WorldAnalysisARFoundationHelper.DownloadFileHTTP(url);
var coroutine = CoroutineLoadWorldMap(downloaded.Key);
WorldAnalysisARFoundationCoroutineHelper.Instance.StartACoroutine(coroutine);
}
/// <summary>
/// Load current map from path
/// </summary>
/// <param name="mapPath">path of the map</param>
/// <returns>coroutine</returns>
public IEnumerator CoroutineLoadWorldMap(string mapPath)
{
while (ARSession.state == ARSessionState.CheckingAvailability || ARSession.state == ARSessionState.None ||ARSession.state == ARSessionState.SessionInitializing)
{
// wait for ar session to be ready
yield return null ;
}
ARSession session = Component.FindAnyObjectByType<ARSession>() ;
ARKitSessionSubsystem sessionSubsystem = (ARKitSessionSubsystem)session.subsystem;
if (sessionSubsystem == null)
Debug.Log("Cannot load map: no ARKitSessionSubsystem");
else
FileStream file;
file = File.Open(mapPath, FileMode.Open);
const int bytesPerFrame = 1024 * 10;
var bytesRemaining = file.Length;
var binaryReader = new BinaryReader(file);
var allBytes = new List<byte>();
while (bytesRemaining > 0)
{
var bytes = binaryReader.ReadBytes(bytesPerFrame);
allBytes.AddRange(bytes);
bytesRemaining -= bytesPerFrame;
yield return null;
}
var data = new NativeArray<byte>(allBytes.Count, Allocator.Temp);
data.CopyFrom(allBytes.ToArray());
ARWorldMap worldMap;
if (ARWorldMap.TryDeserialize(data, out worldMap))
{
data.Dispose();
}
sessionSubsystem.ApplyWorldMap(worldMap);
UpdateTrackableInfoWithPose(Vector3.zero, Quaternion.identity); // before trying to find an anchor: default pause is origin of the map