/// <summary> /// Gets the underlying pointer for the native anchor. /// </summary> /// <param name="anchor"> /// The native anchor to obtain the pointer for. /// </param> /// <param name="cancellationToken"> /// A <see cref="CancellationToken"/> that can be used to cancel the operation. /// </param> /// <returns> /// A Task that yields the pointer. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if <paramref name="anchor"/> is <see langword = "null" />. /// </exception> /// <exception cref="PlatformNotSupportedException"> /// Thrown if the current platform is not supported by the SDK. /// </exception> /// <exception cref="InvalidOperationException"> /// Thrown if a pointer could not be obtained from the native anchor. /// </exception> /// <exception cref="OperationCanceledException"> /// The operation was canceled. /// </exception> /// <remarks> /// This method is async because ARKit cannot provide an anchor /// pointer until at least one frame has been processed. If a pointer /// is not returned on the first request, this operation will wait for /// one to be created. /// </remarks> static public IntPtr GetPointer(this NativeAnchor anchor) { // Validate if (anchor == null) { throw new ArgumentNullException(nameof(anchor)); } // Placeholder IntPtr ptr = IntPtr.Zero; #if UNITY_ANDROID || UNITY_IOS ptr = anchor.WorldAnchorHandle; #elif WINDOWS_UWP || UNITY_WSA ptr = anchor.GetNativeSpatialAnchorPtr(); #else throw new PlatformNotSupportedException("Unable to retrieve the native anchor pointer. 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 // Warn if the anchor didn't give us a valid value if (ptr == IntPtr.Zero) { throw new InvalidOperationException("Couldn't obtain a native anchor pointer"); } // Return the pointer return(ptr); #if UNITY_EDITOR #pragma warning restore CS0162 #endif }
/// <summary> /// Stores the specified cloud version of the anchor and creates or updates the native anchor /// to match. /// </summary> /// <param name="cloudAnchor"> /// The cloud version of the anchor. /// </param> /// <remarks> /// When this method completes, <see cref="CloudAnchor"/> will point to the anchor specified /// by <paramref name="cloudAnchor"/> and <see cref="NativeAnchor"/> will return a new or updated /// native anchor with the same information. /// </remarks> public void CloudToNative(CloudSpatialAnchor cloudAnchor) { // Validate if (cloudAnchor == null) { throw new ArgumentNullException(nameof(cloudAnchor)); } // Apply and store updated native anchor nativeAnchor = gameObject.ApplyCloudAnchor(cloudAnchor); }
/// <summary> /// Sets the pose of the attached <see cref="GameObject"/>, modifying /// native anchors if necessary. /// </summary> /// <param name="gameObject"> /// The <see cref="GameObject"/> to set the pose on. /// </param> /// <param name="position"> /// The new position to set. /// </param> /// <param name="rotation"> /// The new rotation to set. /// </param> public void SetPose(Vector3 position, Quaternion rotation) { // Changing the position resets both native and cloud anchors cloudAnchor = null; nativeAnchor = null; // Use extension method to update position and native anchor gameObject.SetPose(position, rotation); // Get the native anchor back (if there was one) nativeAnchor = gameObject.FindNativeAnchor(); }
/// <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 }
/// <summary> /// Creates or updates the <see cref="CloudSpatialAnchor"/> returned by /// <see cref="CloudAnchor"/> to reflect the same data as the native anchor. /// </summary> /// <param name="useExisting"> /// <c>true</c> to reuse any existing cloud anchor; <c>false</c> to /// always create a new one. /// </param> /// <returns> /// A <see cref="Task"/> that represents the operation. /// </returns> /// <remarks> /// <para> /// If no native anchor exists on the game object it will be created. /// </para> /// </remarks> public void NativeToCloud(bool useExisting) { // Make sure there's a native anchor if (nativeAnchor == null) { nativeAnchor = gameObject.FindOrCreateNativeAnchor(); } // If there is no cloud anchor, create it if ((!useExisting) || (cloudAnchor == null)) { cloudAnchor = nativeAnchor.ToCloud(); } }
/// <summary> /// Removes and destroys any native anchor applied to the object. /// </summary> /// <param name="gameObject"> /// The <see cref="GameObject"/> where the anchor should be removed. /// </param> /// <exception cref="System.ArgumentNullException"> /// Thrown if <paramref name="gameObject"/> is <see langword = "null" />. /// </exception> static public void DeleteNativeAnchor(this GameObject gameObject) { // Validate if (gameObject == null) { throw new ArgumentNullException(nameof(gameObject)); } // Try to find the native anchor NativeAnchor nativeAnchor = FindNativeAnchor(gameObject); // If found destroy (which will also remove it) if (nativeAnchor != null) { GameObject.DestroyImmediate(nativeAnchor); } }
/// <summary> /// Creates or updates the <see cref="CloudSpatialAnchor"/> returned by /// <see cref="CloudAnchor"/> to reflect the same data as the native anchor. /// </summary> /// <param name="anchor"> /// The native anchor to convert to a cloud anchor. /// </param> /// <returns> /// A Task that yields the <see cref="CloudSpatialAnchor"/>. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if <paramref name="anchor"/> is <see langword = "null" />. /// </exception> /// <remarks> /// This method is async because ARKit needs to process at least one /// frame before any requested anchor is fully created. This method /// will return only after any underlying native processes are /// complete. /// </remarks> static public CloudSpatialAnchor ToCloud(this NativeAnchor anchor) { // Validate if (anchor == null) { throw new ArgumentNullException(nameof(anchor)); } // Get the native pointer IntPtr ptr = anchor.GetPointer(); // Create the cloud version CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor(); // Set the local pointer cloudAnchor.LocalAnchor = ptr; // Done! return(cloudAnchor); }
/// <summary> /// Returns any existing anchor if found; otherwise, creates and returns /// a new anchor. /// </summary> /// <param name="gameObject"> /// The <see cref="GameObject"/> to search for or add the anchor. /// </param> /// <returns> /// The existing or newly created native anchor. /// </returns> /// <exception cref="System.ArgumentNullException"> /// Thrown if <paramref name="gameObject"/> is <see langword = "null" />. /// </exception> static public NativeAnchor FindOrCreateNativeAnchor(this GameObject gameObject) { // Validate if (gameObject == null) { throw new ArgumentNullException(nameof(gameObject)); } // Try to find an existing anchor NativeAnchor anchor = FindNativeAnchor(gameObject); // If not found, create if (anchor == null) { anchor = CreateNativeAnchor(gameObject); } // Return the anchor return(anchor); }
protected virtual void Awake() { // If there's already a native anchor, go ahead and reference it nativeAnchor = gameObject.FindNativeAnchor(); }