/// <summary> /// This method is called when the AnchorLocatedEvent is fired. <see cref="CloudManager_AnchorLocated(object, AnchorLocatedEventArgs)"/> /// </summary> /// <param name="newAnchorFromAzure"></param> private void OnCloudAnchorLocated(CloudSpatialAnchor newAnchorFromAzure) { Pose anchorPose = newAnchorFromAzure.GetPose(); logger.Log($"Anchor from Cloud Pose: {anchorPose}"); createOrUpdatePrefabInstance(anchorPose); resetUI(); }
private void CloudManager_AnchorLocated(object sender, AnchorLocatedEventArgs args) { QueueOnUpdate(new Action(() => Debug.Log($"Anchor recognized as a possible Azure anchor"))); if (args.Status == LocateAnchorStatus.Located || args.Status == LocateAnchorStatus.AlreadyTracked) { currentCloudAnchor = args.Anchor; QueueOnUpdate(() => { Debug.Log($"Azure anchor located successfully"); // Notify AnchorFeedbackScript OnASAAnchorLocated?.Invoke(); #if UNITY_ANDROID || UNITY_IOS Pose anchorPose = Pose.identity; anchorPose = currentCloudAnchor.GetPose(); #endif #if WINDOWS_UWP || UNITY_WSA // HoloLens: The position will be set based on the unityARUserAnchor that was located. // Create a local anchor at the location of the object in question gameObject.CreateNativeAnchor(); // Notify AnchorFeedbackScript OnCreateLocalAnchor?.Invoke(); // On HoloLens, if we do not have a cloudAnchor already, we will have already positioned the // object based on the passed in worldPos/worldRot and attached a new world anchor, // so we are ready to commit the anchor to the cloud if requested. // If we do have a cloudAnchor, we will use it's pointer to setup the world anchor, // which will position the object automatically. if (currentCloudAnchor != null) { Debug.Log("Local anchor position successfully set to Azure anchor position"); gameObject.GetComponent <UnityEngine.XR.WSA.WorldAnchor>().SetNativeSpatialAnchorPtr(currentCloudAnchor.LocalAnchor); } #else Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'"); transform.position = anchorPose.position; transform.rotation = anchorPose.rotation; // Create a native anchor at the location of the object in question gameObject.CreateNativeAnchor(); // Notify AnchorFeedbackScript OnCreateLocalAnchor?.Invoke(); #endif }); } else { QueueOnUpdate(new Action(() => Debug.Log($"Attempt to locate Anchor with ID '{args.Identifier}' failed, locate anchor status was not 'Located' but '{args.Status}'"))); } }
protected virtual async Task SaveCurrentObjectAnchorToCloudAsync() { CloudNativeAnchor nativeAnchor = this.GetComponent <CloudNativeAnchor>(); nativeAnchor.SetPose(this.transform.position, this.transform.rotation); // If the cloud portion of the anchor hasn't been created yet, create it if (nativeAnchor.CloudAnchor == null) { nativeAnchor.NativeToCloud(); } CloudSpatialAnchor cloudAnchor = nativeAnchor.CloudAnchor; cloudAnchor.Expiration = DateTimeOffset.Now.AddDays(7); while (!GetComponent <SpatialAnchorManager>().IsReadyForCreate) { await Task.Delay(330); float createProgress = GetComponent <SpatialAnchorManager>().SessionStatus.RecommendedForCreateProgress; feedback.text = $"Move your device to capture more environment data: {createProgress:0%}"; } Pose anchorPose = cloudAnchor.GetPose(); feedback.text = "Anchor Position: " + anchorPose.position + " Rotation: " + anchorPose.rotation; try { // Actually save await GetComponent <SpatialAnchorManager>().CreateAnchorAsync(cloudAnchor); feedback.text = "Saved: " + cloudAnchor.Identifier; // Store currentCloudAnchor = cloudAnchor; // // Success? // success = currentCloudAnchor != null; // if (success && !isErrorActive) // { // // Await override, which may perform additional tasks // // such as storing the key in the AnchorExchanger // await OnSaveCloudAnchorSuccessfulAsync(); // } // else // { // OnSaveCloudAnchorFailed(new Exception("Failed to save, but no exception was thrown.")); // } } catch (Exception ex) { feedback.text = ex.ToString(); // OnSaveCloudAnchorFailed(ex); } }
/// <summary> /// Applies the specified cloud anchor to the GameObject by /// creating or updating the native anchor. /// to match. /// </summary> /// <param name="gameObject"> /// The <see cref="GameObject"/> where the cloud anchor should be /// applied. /// </param> /// <param name="cloudAnchor"> /// The cloud anchor to apply. /// </param> /// <returns> /// The <see cref="NativeAnchor"/> created or updated during the /// operation. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if <paramref name="gameObject"/> or <paramref name="cloudAnchor"/> /// are <see langword = "null" />. /// </exception> /// <exception cref="PlatformNotSupportedException"> /// Thrown if the current platform is not supported by the SDK. /// </exception> static public NativeAnchor ApplyCloudAnchor(this GameObject gameObject, CloudSpatialAnchor cloudAnchor) { // Validate if (gameObject == null) { throw new ArgumentNullException(nameof(gameObject)); } if (cloudAnchor == null) { throw new ArgumentNullException(nameof(cloudAnchor)); } // Placeholder NativeAnchor nativeAnchor = null; #if WINDOWS_UWP || UNITY_WSA // On UWP we can just update the pointer on any existing WorldAnchor. // Doing so will also automatically update the objects pose. // Find or create the world anchor nativeAnchor = gameObject.FindOrCreateNativeAnchor(); // Update the World Anchor to use the cloud-based native anchor nativeAnchor.SetNativeSpatialAnchorPtr(cloudAnchor.LocalAnchor); #elif UNITY_IOS || UNITY_ANDROID // On iOS and Android we need to remove any existing native anchor, // move the object to the new pose, and then re-apply the native anchor. // Delete any existing native anchor gameObject.DeleteNativeAnchor(); // Get the pose from the cloud anchor Pose pose = cloudAnchor.GetPose(); // Move the GameObject to match the new pose gameObject.transform.position = pose.position; gameObject.transform.rotation = pose.rotation; // Add the native anchor back on nativeAnchor = gameObject.CreateNativeAnchor(); #else throw new PlatformNotSupportedException("Unable to apply the cloud anchor. The platform is not supported."); #endif #if UNITY_EDITOR #pragma warning disable CS0162 // Conditional compile statements prevent reaching this code in the unity editor #endif // Return the created or updated anchor return(nativeAnchor); #if UNITY_EDITOR #pragma warning restore CS0162 #endif }
private void HandleAnchorLocated(object sender, AnchorLocatedEventArgs args) { Debug.Log($"Anchor recognized as a possible Azure anchor"); if (args.Status == LocateAnchorStatus.Located || args.Status == LocateAnchorStatus.AlreadyTracked) { currentCloudAnchor = args.Anchor; AppDispatcher.Instance().Enqueue(() => { Debug.Log($"Azure anchor located successfully"); var indicator = Instantiate(anchorPositionPrefab); #if WINDOWS_UWP || UNITY_WSA indicator.gameObject.CreateNativeAnchor(); if (currentCloudAnchor == null) { return; } Debug.Log("Local anchor position successfully set to Azure anchor position"); indicator.GetComponent <UnityEngine.XR.WSA.WorldAnchor>().SetNativeSpatialAnchorPtr(currentCloudAnchor.LocalAnchor); #elif UNITY_ANDROID || UNITY_IOS Pose anchorPose = Pose.identity; anchorPose = currentCloudAnchor.GetPose(); Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'"); indicator.transform.position = anchorPose.position; indicator.transform.rotation = anchorPose.rotation; // Create a native anchor at the location of the object in question indicator.gameObject.CreateNativeAnchor(); #endif indicator.Init(currentTrackedObject); anchorArrowGuide.SetTargetObject(indicator.transform); activeAnchors.Add(currentTrackedObject.SpatialAnchorId, indicator); // Notify subscribers OnFindAnchorSucceeded?.Invoke(this, EventArgs.Empty); currentWatcher?.Stop(); currentTrackedObject = null; }); } else { Debug.Log($"Attempt to locate Anchor with ID '{args.Identifier}' failed, locate anchor status was not 'Located' but '{args.Status}'"); } StopAzureSession(); }
private void CloudManagerAnchorLocated(object sender, AnchorLocatedEventArgs args) { if (args.Status == LocateAnchorStatus.Located && appStateManager.currentCloudAnchorState == CloudAnchorStateEnum.ReadyToLookForCloudAnchor) { if (spawnedAnchorObject == null) { currentCloudSpatialAnchor = args.Anchor; Pose anchorPose = currentCloudSpatialAnchor.GetPose(); spawnedAnchorObject = SpawnNewAnchoredObject(anchorPose.position, anchorPose.rotation); } appStateManager.currentCloudAnchorState = CloudAnchorStateEnum.NothingHappening; appStateManager.currentUIState = UIStateEnum.SceneryButtonsOnly_NothingHappening; appStateManager.currentOutputMessage = $"Found cloud anchor OK. Press 'Place' to add new scenery, or press 'Restore' to get previously saved scenery.."; } }
private void CloudAnchor_Located(object sender, AnchorLocatedEventArgs args) { feedback.text = "Anchor " + anchorNumber + " located"; currentCloudAnchor = args.Anchor; Pose anchorPose = currentCloudAnchor.GetPose(); feedback.text = "Anchor position: " + anchorPose.position; this.transform.SetPositionAndRotation(anchorPose.position, anchorPose.rotation); this.GetComponentInChildren <Renderer>().enabled = true; this.GetComponentInChildren <Renderer>().material.color = Color.green; this.GetComponentInChildren <TextMeshPro>().text = anchorNumber; GetComponent <SpatialAnchorManager>().StopSession(); feedback.text = "Stopped Session"; }
protected void OnCloudAnchorLocated(AnchorLocatedEventArgs args) { if (args.Status == LocateAnchorStatus.Located) { currentCloudAnchor = args.Anchor; UnityDispatcher.InvokeOnAppThread(() => { Pose anchorPose = Pose.identity; #if UNITY_ANDROID || UNITY_IOS anchorPose = currentCloudAnchor.GetPose(); #endif // HoloLens: The position will be set based on the unityARUserAnchor that was located. SpawnOrMoveCurrentAnchoredObject(anchorPose.position, anchorPose.rotation); }); } }
/// <summary> /// For each anchor located by the spatial anchor manager, instantiate and setup a corresponding GameObject. /// </summary> private void SpatialAnchorManagerAnchorLocated(object sender, AnchorLocatedEventArgs args) { Debug.Log($"Anchor recognized as a possible anchor {args.Identifier} {args.Status}"); if (args.Status == LocateAnchorStatus.Located) { UnityDispatcher.InvokeOnAppThread(() => { CloudSpatialAnchor cloudSpatialAnchor = args.Anchor; Pose anchorPose = cloudSpatialAnchor.GetPose(); GameObject anchorGameObject = Instantiate(m_sampleSpatialAnchorPrefab, anchorPose.position, anchorPose.rotation); anchorGameObject.AddComponent <CloudNativeAnchor>().CloudToNative(cloudSpatialAnchor); anchorGameObject.GetComponent <SampleSpatialAnchor>().Identifier = cloudSpatialAnchor.Identifier; anchorGameObject.GetComponent <SampleSpatialAnchor>().Persisted = true; m_foundOrCreatedAnchorObjects.Add(anchorGameObject); }); } }
/// <summary> /// The watcher created in <see cref="FindSpatialAnchor(string)"/> invokes this event for every anchor requested /// This event fires if an anchor is located or also if it cannot be located. /// </summary> /// <param name="args"></param> private void ReportAnchorLocationResultReceived(Microsoft.Azure.SpatialAnchors.AnchorLocatedEventArgs args) { if (args.Watcher != null) { args.Watcher.Stop(); } switch (args.Status) { case LocateAnchorStatus.AlreadyTracked: Log($"The requested anchor {args.Identifier} was already tracked.", true); SendUpdateOnMainThread(AsaStatusEventType.FindAnchor_AlreadyTracked, status); break; case LocateAnchorStatus.Located: CloudSpatialAnchor foundAnchor = args.Anchor; Log($"The requested anchor {args.Identifier} was found!", true); if (foundAnchor == null) { Log($"Found the requested anchor but the returned anchor is null!", true); return; } SendUpdateOnMainThread(AsaStatusEventType.FindAnchor_Finished, status); ExecuteOnMainThread(() => { Log("Processing the found anchor's position", true); // Notify AnchorFeedbackScript Pose anchorPose = Pose.identity; #if UNITY_ANDROID || UNITY_IOS anchorPose = foundAnchor.GetPose(); #endif #if WINDOWS_UWP || UNITY_WSA // HoloLens: The position will be set based on the unityARUserAnchor that was located. // Create a local anchor at the location of the object in question gameObject.CreateNativeAnchor(); // On HoloLens, if we do not have a cloudAnchor already, we will have already positioned the // object based on the passed in worldPos/worldRot and attached a new world anchor, // so we are ready to commit the anchor to the cloud if requested. // If we do have a cloudAnchor, we will use it's pointer to setup the world anchor, // which will position the object automatically. if (foundAnchor != null) { Log("Local anchor position successfully set to Azure anchor position", true); var worldAnchor = gameObject.GetComponent <UnityEngine.XR.WSA.WorldAnchor>(); if (worldAnchor != null) { worldAnchor.SetNativeSpatialAnchorPtr(foundAnchor.LocalAnchor); } else { Log("WorldAnchorComponent was null", true); } } #else Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'", true); transform.position = anchorPose.position; transform.rotation = anchorPose.rotation; // Create a native anchor at the location of the object in question //gameObject.CreateNativeAnchor(); #endif }); break; case LocateAnchorStatus.NotLocatedAnchorDoesNotExist: // The anchor was deleted or never existed in the first place // Drop it, or show UI to ask user to anchor the content anew Log($"The requested anchor {args.Identifier} does not exist.", true); SendUpdateOnMainThread(AsaStatusEventType.FindAnchor_DoesNotExist, status); break; case LocateAnchorStatus.NotLocated: // The anchor hasn't been found given the location data // The user might in the wrong location, or maybe more data will help // Show UI to tell user to keep looking around Log($"The requested anchor {args.Identifier} could not be located.", true); SendUpdateOnMainThread(AsaStatusEventType.FindAnchor_CouldNotLocate, status); break; } }
private void CloudAnchorManager_AnchorLocated(object sender, AnchorLocatedEventArgs args) { if (args.Status == LocateAnchorStatus.Located) { Debug.Log("Found anchor: " + args.Identifier); if (args.Identifier != null) { foundAnchors.Add(args.Anchor); } debugText.text = "Anchor Located: " + args.Identifier; //shift current to previous and get new current if (currentCloudAnchor == null || args.Anchor.Identifier != currentCloudAnchor.Identifier) { previousCloudAnchor = currentCloudAnchor; currentCloudAnchor = args.Anchor; } //get a list of all gameobjects with tag AnchorContainer. This will get a list of all anchor prefabs var anchorContainers = GameObject.FindGameObjectsWithTag("AnchorContainer"); debugText.text += "\nNum Anchors: " + anchorContainers.Length; GameObject anchorContainer = null; for (int i = 0; i < anchorContainers.Length; i++) { //if anchorcontainer is at location of the current anchor, this is the one we just found if (anchorContainers[i].gameObject.transform.position == currentCloudAnchor.GetPose().position) { anchorContainer = anchorContainers[i]; anchorContainer.gameObject.GetComponent <AnchorContainer>().anchorID = args.Anchor.Identifier; debugText.text += "\nAnchor Added: " + anchorContainer.gameObject.GetComponent <AnchorContainer>().anchorID; } //if we found the previous container, we need to reset this one so it isn't highlighted if (previousCloudAnchor != null) { if (anchorContainers[i].gameObject.transform.position == previousCloudAnchor.GetPose().position) { changeAnchorMaterials(anchorContainers[i], baseMaterial); } } } if (anchorContainer != null) { //make all the children in the anchorcontainer visible and highlight the cyclinder for (int i = 0; i < anchorContainer.transform.childCount; i++) { GameObject child = anchorContainer.transform.GetChild(i).gameObject; if (!child.name.Equals("Cylinder")) { child.SetActive(true); } //if (anchorContainer.transform.GetChild(i).gameObject.name.Equals("Cylinder")) //{ // anchorContainer.transform.GetChild(i).gameObject.GetComponent<Renderer>().material = highlightMaterial; //} } changeAnchorMaterials(anchorContainer, highlightMaterial); //set the curved text to the identifier TMP_Text containerText = anchorContainer.GetComponentInChildren <TMP_Text>(); containerText.text = "" + currentCloudAnchor.Identifier; //set the curved text to the label if it exists //TODO: change this so that it algorithmically determines the amount of // repeats and the amount of spacing so it looks good with // any word if (currentCloudAnchor.AppProperties.ContainsKey("label") && currentCloudAnchor.AppProperties["label"] != null) { string label = currentCloudAnchor.AppProperties["label"]; int anchorLabelLength = 0; containerText.text = ""; while (anchorLabelLength <= 26) { containerText.text += label + " "; anchorLabelLength += label.Length + 4; } } else { Debug.Log("Anchor found with ID: " + currentCloudAnchor.Identifier); } topText.text = "Anchors located! Localization complete!"; } else { debugText.text += "No Anchor Detected"; } } }