8 using System.Collections.Generic;
9 using System.Collections.ObjectModel;
10 #if UNITY_2017_2_OR_NEWER 40 if (_Instance == null)
42 _Instance = FindObjectOfType<UNetAnchorManager>();
52 public string AnchorName =
"";
57 public bool UseSpatialMapping =
true;
62 public bool AnchorEstablished {
get;
set; }
67 public bool ImportInProgress {
get;
private set; }
72 public bool DownloadingAnchor {
get;
private set; }
77 private NetworkManager networkManager;
85 const string SavedAnchorKey =
"SavedAnchorName";
90 private bool StartedObserver =
false;
95 private SpatialMappingManager spatialMapping;
100 private GameObject objectToAnchor;
106 private const uint MinTrustworthySerializedAnchorDataSize = 500000;
111 private List<byte> exportingAnchorBytes =
new List<byte>(0);
116 private bool createdAnchor =
false;
121 private string oldAnchorName =
"";
126 private byte[] anchorData = null;
131 private bool gotOne =
false;
136 private string exportingAnchorName;
143 private bool CheckConfiguration()
146 if (networkTransmitter == null)
148 Debug.Log(
"No UNetNetworkTransmitter found in scene");
152 networkManager = NetworkManager.singleton;
153 if (networkManager == null)
155 Debug.Log(
"No NetworkManager found in scene");
161 Debug.Log(
"No SharedCollection found in scene");
168 if (UseSpatialMapping)
170 spatialMapping = SpatialMappingManager.Instance;
171 if (spatialMapping == null)
173 Debug.Log(
"Spatial mapping not found in scene. Better anchor locations can be found if a SpatialMappingManager is in the scene");
183 if (!CheckConfiguration())
185 Debug.Log(
"Missing required component for UNetAnchorManager");
190 #if UNITY_WSA && !(ENABLE_IL2CPP && NET_STANDARD_2_0) 191 #if UNITY_2017_2_OR_NEWER 192 if (HolographicSettings.IsDisplayOpaque)
194 if (!VRDevice.isPresent)
197 AnchorEstablished =
true;
201 networkTransmitter.DataReadyEvent += NetworkTransmitter_DataReadyEvent;
204 AnchorEstablished =
true;
209 if (debugPanel != null)
215 private void Update()
218 #if UNITY_2017_2_OR_NEWER 219 if (HolographicSettings.IsDisplayOpaque)
224 if (!VRDevice.isPresent)
232 Debug.Log(
"Importing");
234 ImportInProgress =
true;
235 WorldAnchorTransferBatch.ImportAsync(anchorData, ImportComplete);
238 if (oldAnchorName != AnchorName && !createdAnchor)
240 Debug.LogFormat(
"New anchor name {0} => {1}", oldAnchorName, AnchorName);
241 oldAnchorName = AnchorName;
242 if (
string.IsNullOrEmpty(AnchorName))
244 Debug.Log(
"Anchor is empty");
245 AnchorEstablished =
false;
247 else if (!AttachToCachedAnchor(AnchorName))
249 Debug.Log(
"Requesting download of anchor data");
260 private string GenerateDebugData()
263 return string.Format(
"Anchor Name: {0}\nAnchor Size: {1}\nAnchor Established?: {2}\nImporting?: {3}\nDownloading? {4}\n",
265 anchorData == null ? exportingAnchorBytes.Count : anchorData.Length,
266 AnchorEstablished.ToString(),
267 ImportInProgress.ToString(),
268 DownloadingAnchor.ToString());
270 return "No Anchor data";
280 exportingAnchorBytes.Clear();
283 FindAnchorPosition();
288 private void FindAnchorPosition()
297 if (PlayerPrefs.HasKey(SavedAnchorKey) && AttachToCachedAnchor(PlayerPrefs.GetString(SavedAnchorKey)))
299 exportingAnchorName = PlayerPrefs.GetString(SavedAnchorKey);
300 Debug.Log(
"found " + exportingAnchorName +
" again");
304 else if (spatialMapping == null)
306 if (UseSpatialMapping)
308 Debug.Log(
"No spatial mapping...");
311 ExportAnchorAtPosition(objectToAnchor.transform.position);
316 ReadOnlyCollection<SpatialMappingSource.SurfaceObject> surfaces = spatialMapping.GetSurfaceObjects();
317 if (surfaces == null || surfaces.Count == 0)
320 if (spatialMapping.IsObserverRunning() ==
false)
322 spatialMapping.StartObserver();
323 StartedObserver =
true;
327 Invoke(
"FindAnchorPosition", spatialMapping.GetComponent<SpatialMappingObserver>().TimeBetweenUpdates);
331 float startTime = Time.realtimeSinceStartup;
334 Mesh bestMesh = null;
335 MeshFilter bestFilter = null;
338 for (
int index = 0; index < surfaces.Count; index++)
344 MeshFilter currentFilter = surfaces[index].Filter;
345 if (currentFilter == null)
350 Mesh currentMesh = currentFilter.sharedMesh;
351 if (currentMesh == null)
357 MeshCollider currentCollider = surfaces[index].Collider;
358 float volume = currentCollider == null ? 1.0f : currentCollider.bounds.extents.magnitude;
361 int meshVerts = (int)(currentMesh.vertexCount / volume);
364 mostVerts = Mathf.Max(meshVerts, mostVerts);
365 if (mostVerts == meshVerts)
367 bestMesh = currentMesh;
368 bestFilter = currentFilter;
373 if (bestMesh != null && mostVerts > 100)
376 Vector3[] verts = bestMesh.vertices;
377 Vector3 avgVert = verts.Average();
380 Vector3 center = bestFilter.transform.TransformPoint(avgVert);
382 Debug.LogFormat(
"found a good mesh mostVerts = {0} processed {1} meshes in {2} ms", mostVerts, surfaces.Count, 1000 * (Time.realtimeSinceStartup - startTime));
384 ExportAnchorAtPosition(center);
389 Debug.LogFormat(
"Failed to find a good mesh mostVerts = {0} processed {1} meshes in {2} ms", mostVerts, surfaces.Count, 1000 * (Time.realtimeSinceStartup - startTime));
390 Invoke(
"FindAnchorPosition", spatialMapping.GetComponent<SpatialMappingObserver>().TimeBetweenUpdates);
400 private void ExportAnchorAtPosition(Vector3 worldPos)
403 WorldAnchor worldAnchor = objectToAnchor.GetComponent<WorldAnchor>();
404 if (worldAnchor != null)
406 DestroyImmediate(worldAnchor);
410 objectToAnchor.transform.position = worldPos;
413 worldAnchor = objectToAnchor.AddComponent<WorldAnchor>();
416 exportingAnchorName = Guid.NewGuid().ToString();
417 Debug.Log(
"preparing " + exportingAnchorName);
420 worldAnchor.OnTrackingChanged += WorldAnchor_OnTrackingChanged;
423 WorldAnchor_OnTrackingChanged(worldAnchor, worldAnchor.isLocated);
431 private void WorldAnchor_OnTrackingChanged(WorldAnchor
self,
bool located)
436 Debug.Log(
"exporting " + exportingAnchorName);
438 self.OnTrackingChanged -= WorldAnchor_OnTrackingChanged;
447 private void ExportAnchor()
449 WorldAnchorTransferBatch watb =
new WorldAnchorTransferBatch();
450 WorldAnchor worldAnchor = objectToAnchor.GetComponent<WorldAnchor>();
451 watb.AddWorldAnchor(exportingAnchorName, worldAnchor);
452 WorldAnchorTransferBatch.ExportAsync(watb, WriteBuffer, ExportComplete);
458 spatialMapping.StopObserver();
459 StartedObserver =
false;
466 public void WaitForAnchor()
469 if (!DownloadingAnchor)
471 Invoke(
"WaitForAnchor", 0.5f);
479 private bool AttachToCachedAnchor(
string cachedAnchorName)
481 if (
string.IsNullOrEmpty(cachedAnchorName))
483 Debug.Log(
"Ignoring empty name");
488 Debug.Log(
"Looking for " + cachedAnchorName);
489 string[] ids = anchorStore.GetAllIds();
490 for (
int index = 0; index < ids.Length; index++)
492 if (ids[index] == cachedAnchorName)
494 Debug.Log(
"Using what we have");
495 anchorStore.Load(ids[index], objectToAnchor);
496 AnchorEstablished =
true;
509 private void NetworkTransmitter_DataReadyEvent(byte[] data)
511 Debug.Log(
"Anchor data arrived.");
513 Debug.Log(data.Length);
514 DownloadingAnchor =
false;
523 private void ImportComplete(SerializationCompletionReason status, WorldAnchorTransferBatch wat)
525 if (status == SerializationCompletionReason.Succeeded && wat.GetAllIds().Length > 0)
527 Debug.Log(
"Import complete");
529 string first = wat.GetAllIds()[0];
530 Debug.Log(
"Anchor name: " + first);
532 WorldAnchor existingAnchor = objectToAnchor.GetComponent<WorldAnchor>();
533 if (existingAnchor != null)
535 DestroyImmediate(existingAnchor);
538 WorldAnchor anchor = wat.LockObject(first, objectToAnchor);
539 anchor.OnTrackingChanged += Anchor_OnTrackingChanged;
540 Anchor_OnTrackingChanged(anchor, anchor.isLocated);
542 ImportInProgress =
false;
548 Debug.Log(
"Import fail");
552 private void Anchor_OnTrackingChanged(WorldAnchor
self,
bool located)
556 AnchorEstablished =
true;
558 self.OnTrackingChanged -= Anchor_OnTrackingChanged;
566 private void WriteBuffer(byte[] data)
568 exportingAnchorBytes.AddRange(data);
575 private void ExportComplete(SerializationCompletionReason status)
577 if (status == SerializationCompletionReason.Succeeded && exportingAnchorBytes.Count > MinTrustworthySerializedAnchorDataSize)
579 AnchorName = exportingAnchorName;
580 anchorData = exportingAnchorBytes.ToArray();
582 createdAnchor =
true;
583 Debug.Log(
"Anchor ready " + exportingAnchorBytes.Count);
585 AnchorEstablished =
true;
589 Debug.Log(
"Create anchor failed " + status +
" " + exportingAnchorBytes.Count);
590 exportingAnchorBytes.Clear();
592 DestroyImmediate(objectToAnchor.GetComponent<WorldAnchor>());
601 public void AnchorFoundRemotely()
603 Debug.Log(
"Setting saved anchor to " + AnchorName);
605 PlayerPrefs.SetString(SavedAnchorKey, AnchorName);
612 public void MakeNewAnchor()
615 if (PlayerPrefs.HasKey(SavedAnchorKey))
617 PlayerPrefs.DeleteKey(SavedAnchorKey);
621 WorldAnchor currentAnchor = objectToAnchor.GetComponent<WorldAnchor>();
622 if (currentAnchor != null)
624 DestroyImmediate(currentAnchor);