Come creare e individuare ancoraggi usando Ancoraggi nello spazio di Azure in Unity

Ancoraggi nello spazio di Azure è un servizio che consente di condividere ancoraggi nel mondo tra dispositivi diversi. Supporta vari ambienti di sviluppo differenti. Questo articolo illustra nel dettaglio come usare l'SDK di Ancoraggi nello spazio di Azure, in Unity, per:

  • Configurare e gestire in modo corretto una sessione di Ancoraggi nello spazio di Azure.
  • Creare e impostare le proprietà sugli ancoraggi locali.
  • Caricarli nel cloud.
  • Trovare ed eliminare gli ancoraggi nello spazio nel cloud.

Prerequisiti

Per completare le procedure contenute in questa guida, verificare che siano soddisfatti i requisti seguenti:

Cross Platform

Inizializzare la sessione

Il punto di ingresso principale dell'SDK è la classe che rappresenta la sessione. In genere nella classe si dichiara un campo che gestisce la visualizzazione e la sessione AR nativa.

Altre informazioni sulla classe CloudSpatialAnchorSession.

    CloudSpatialAnchorSession cloudSession;
    // In your view handler
    this.cloudSession = new CloudSpatialAnchorSession();

Configurazione dell'autenticazione

Per accedere al servizio, è necessario fornire una chiave dell'account, un token di accesso o un token di autenticazione di Microsoft Entra. Per altre informazioni, vedere la pagina relativa al concetto di autenticazione.

Chiavi dell'account

Le chiavi dell'account sono credenziali che consentono all'applicazione di eseguire l'autenticazione con il servizio degli ancoraggi nello spazio di Azure. Le chiavi dell'account consentono di essere subito operativi, soprattutto durante la fase di sviluppo dell'integrazione dell'applicazione con gli ancoraggi nello spazio di Azure. Di conseguenza, è possibile usare le chiavi dell'account incorporandole nelle applicazioni client durante lo sviluppo. Man mano che si procede oltre lo sviluppo, è consigliabile passare a un meccanismo di autenticazione a livello di produzione, supportato dai token di accesso o dall'autenticazione utente di Microsoft Entra. Per ottenere una chiave dell'account per lo sviluppo, visitare l'account ancoraggi nello spazio di Azure e passare alla scheda "Chiavi".

Altre informazioni sulla classe SessionConfiguration.

    this.cloudSession.Configuration.AccountKey = @"MyAccountKey";

Token di accesso

I token di accesso sono un metodo più affidabile per l'autenticazione con gli ancoraggi nello spazio di Azure, soprattutto quando si prepara l'applicazione per una distribuzione di produzione. Il riepilogo di questo approccio consiste nel configurare un servizio back-end con cui l'applicazione client può eseguire l'autenticazione in modo sicuro. Il servizio back-end si interfaccia con AAD in fase di esecuzione e con il servizio token sicuro degli ancoraggi nello spazio di Azure per richiedere un token di accesso. Questo token viene quindi distribuito all'applicazione client e usato nell'SDK per eseguire l'autenticazione con gli ancoraggi nello spazio di Azure.

    this.cloudSession.Configuration.AccessToken = @"MyAccessToken";

Se non è impostato alcun token di accesso, è necessario gestire l'evento TokenRequired oppure implementare il metodo tokenRequired per il protocollo delegato.

È possibile gestire l'evento in modo sincrono impostando la proprietà sugli argomenti dell'evento.

Altre informazioni sul delegato TokenRequiredDelegate.

    this.cloudSession.TokenRequired += (object sender, TokenRequiredEventArgs args) =>
    {
        args.AccessToken = @"MyAccessToken";
    };

Se è necessario eseguire operazioni asincrone nel gestore, è possibile rinviare l'impostazione del token richiedendo un oggetto deferral e quindi completarlo, come nell'esempio seguente.

    this.cloudSession.TokenRequired += async (object sender, TokenRequiredEventArgs args) =>
    {
        var deferral = args.GetDeferral();
        string myToken = await MyGetTokenAsync();
        if (myToken != null) args.AccessToken = myToken;
        deferral.Complete();
    };

Autenticazione Microsoft Entra

Ancoraggi nello spazio di Azure consente anche alle applicazioni di eseguire l'autenticazione con token microsoft Entra ID (Active Directory). Ad esempio, è possibile usare i token Microsoft Entra per l'integrazione con Ancoraggi nello spazio di Azure. Se un'azienda gestisce gli utenti in Microsoft Entra ID, è possibile fornire un token Microsoft Entra utente in Azure Spatial Anchors SDK. In questo modo è possibile eseguire l'autenticazione direttamente nel servizio Ancoraggi nello spazio di Azure per un account che fa parte dello stesso tenant di Microsoft Entra.

    this.cloudSession.Configuration.AuthenticationToken = @"MyAuthenticationToken";

Analogamente ai token di accesso, se non è impostato un token Microsoft Entra, è necessario gestire l'evento TokenRequired o implementare il metodo tokenRequired nel protocollo delegato.

È possibile gestire l'evento in modo sincrono impostando la proprietà sugli argomenti dell'evento.

    this.cloudSession.TokenRequired += (object sender, TokenRequiredEventArgs args) =>
    {
        args.AuthenticationToken = @"MyAuthenticationToken";
    };

Se è necessario eseguire operazioni asincrone nel gestore, è possibile rinviare l'impostazione del token richiedendo un oggetto deferral e quindi completarlo, come nell'esempio seguente.

    this.cloudSession.TokenRequired += async (object sender, TokenRequiredEventArgs args) =>
    {
        var deferral = args.GetDeferral();
        string myToken = await MyGetTokenAsync();
        if (myToken != null) args.AuthenticationToken = myToken;
        deferral.Complete();
    };

Configurare la sessione

Richiamare Start() per consentire alla sessione di elaborare i dati dell'ambiente.

Per gestire gli eventi generati dalla sessione, collegare un gestore eventi.

Altre informazioni sul metodo Start.

#if UNITY_ANDROID || UNITY_IOS
    this.cloudSession.Session = aRSession.subsystem.nativePtr.GetPlatformPointer();
#elif UNITY_WSA || WINDOWS_UWP
    // No need to set a native session pointer for HoloLens.
#else
    throw new NotSupportedException("The platform is not supported.");
#endif

    this.cloudSession.Start();

Fornire fotogrammi alla sessione

Durante la sessione di ancoraggio nello spazio viene eseguito il mapping dello spazio intorno all'utente. Questa operazione consente di determinare dove si trovano gli ancoraggi. Le piattaforme per dispositivi mobili (iOS e Android) richiedono una chiamata nativa al feed della fotocamera per ottenere i fotogrammi dalla libreria AR della piattaforma. Al contrario, HoloLens analizza continuamente l'ambiente e, di conseguenza, non è necessario eseguire una chiamata specifica come avviene nelle piattaforme per dispositivi mobili.

Altre informazioni sul metodo ProcessFrame.

#if UNITY_ANDROID || UNITY_IOS
    XRCameraFrame xRCameraFrame;
    if (aRCameraManager.subsystem.TryGetLatestFrame(cameraParams, out xRCameraFrame))
    {
        long latestFrameTimeStamp = xRCameraFrame.timestampNs;

        bool newFrameToProcess = latestFrameTimeStamp > lastFrameProcessedTimeStamp;

        if (newFrameToProcess)
        {
            session.ProcessFrame(xRCameraFrame.nativePtr.GetPlatformPointer());
            lastFrameProcessedTimeStamp = latestFrameTimeStamp;
        }
    }
#endif

Fornire feedback all'utente

È possibile scrivere codice per gestire l'evento di aggiornamento della sessione. Questo evento viene generato ogni volta che la sessione migliora il riconoscimento dell'ambiente circostante. In questo modo è possibile:

  • Usare la classe UserFeedback per fornire feedback all'utente quando il dispositivo viene spostato e la sessione aggiorna il riconoscimento dell'ambiente. A tale scopo, seguire questa procedura:
  • Determinare in quale punto sono disponibili dati spaziali rilevati sufficienti per creare ancoraggi nello spazio. Per questa operazione si usa ReadyForCreateProgress o RecommendedForCreateProgress. Quando il valore di ReadyForCreateProgress è maggiore di 1, i dati disponibili sono sufficienti per salvare un ancoraggio nello spazio cloud, anche se è consigliabile attendere fino a quando il valore di RecommendedForCreateProgress non diventa maggiore di 1.

Altre informazioni sul delegato SessionUpdatedDelegate.

    this.cloudSession.SessionUpdated += (object sender, SessionUpdatedEventArgs args) =>
    {
        var status = args.Status;
        if (status.UserFeedback == SessionUserFeedback.None) return;
        this.feedback = $"Feedback: {Enum.GetName(typeof(SessionUserFeedback), status.UserFeedback)} -" +
            $" Recommend Create={status.RecommendedForCreateProgress: 0.#%}";
    };

Creare un ancoraggio nello spazio cloud

Per creare un ancoraggio nello spazio cloud, creare prima un ancoraggio nel sistema AR della piattaforma e quindi una controparte cloud. A questo scopo, usare il metodo CreateAnchorAsync().

Altre informazioni sulla classe CloudSpatialAnchor.

    // Create a local anchor, perhaps by hit-testing and spawning an object within the scene
    Vector3 hitPosition = new Vector3();
#if UNITY_ANDROID || UNITY_IOS
    Vector2 screenCenter = new Vector2(0.5f, 0.5f);
    List<ARRaycastHit> aRRaycastHits = new List<ARRaycastHit>();
    if(arRaycastManager.Raycast(screenCenter, aRRaycastHits) && aRRaycastHits.Count > 0)
    {
        ARRaycastHit hit = aRRaycastHits[0];
        hitPosition = hit.pose.position;
    }
#elif WINDOWS_UWP || UNITY_WSA
    RaycastHit hit;
    if (this.TryGazeHitTest(out hit))
    {
        hitPosition = hit.point;
    }
#endif

    Quaternion rotation = Quaternion.AngleAxis(0, Vector3.up);
    this.localAnchor = GameObject.Instantiate(/* some prefab */, hitPosition, rotation);
    this.localAnchor.AddComponent<CloudNativeAnchor>();

    // If the user is placing some application content in their environment,
    // you might show content at this anchor for a while, then save when
    // the user confirms placement.
    CloudNativeAnchor cloudNativeAnchor = this.localAnchor.GetComponent<CloudNativeAnchor>();
    if (cloudNativeAnchor.CloudAnchor == null) { await cloudNativeAnchor.NativeToCloud(); }  
    CloudSpatialAnchor cloudAnchor = cloudNativeAnchor.CloudAnchor;
    await this.cloudSession.CreateAnchorAsync(cloudAnchor);
    this.feedback = $"Created a cloud anchor with ID={cloudAnchor.Identifier}");

Come descritto in precedenza, è necessario acquisire dati di ambiente sufficienti prima di provare a creare un nuovo ancoraggio nello spazio cloud. Questo significa che il valore di ReadyForCreateProgress deve essere maggiore di 1, anche se è consigliabile attendere fino a quando il valore di RecommendedForCreateProgress non diventa maggiore di 1.

Altre informazioni sul metodo GetSessionStatusAsync.

    SessionStatus value = await this.cloudSession.GetSessionStatusAsync();
    if (value.RecommendedForCreateProgress < 1.0f) return;
    // Issue the creation request ...

Impostare le proprietà

Quando si salvano gli ancoraggi nello spazio cloud, è possibile scegliere di aggiungere alcune proprietà, ad esempio il tipo di oggetto da salvare oppure proprietà di base relative all'abilitazione per l'interazione. Questa operazione può essere utile al momento dell'individuazione. È infatti possibile eseguire immediatamente il rendering dell'oggetto per l'utente, ad esempio un fotogramma immagine con contenuto vuoto. Con un download diverso in background si ottengono quindi altri dettagli sullo stato, ad esempio l'immagine da visualizzare nel fotogramma.

Altre informazioni sulla proprietà appProperties.

    CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor() { LocalAnchor = localAnchor };
    cloudAnchor.AppProperties[@"model-type"] = @"frame";
    cloudAnchor.AppProperties[@"label"] = @"my latest picture";
    await this.cloudSession.CreateAnchorAsync(cloudAnchor);

Aggiornare le proprietà

Per aggiornare le proprietà di un ancoraggio, si usa il metodo UpdateAnchorProperties(). Se due o più dispositivi provano ad aggiornare le proprietà per lo stesso ancoraggio nello stesso momento, viene usato un modello di concorrenza ottimistica, in base al quale prevale la prima operazione di scrittura eseguita. Per tutte le altre operazioni di scrittura verrà restituito un errore di "concorrenza" e sarà necessario aggiornare le proprietà prima di riprovare.

Altre informazioni sul metodo UpdateAnchorPropertiesAsync.

    CloudSpatialAnchor anchor = /* locate your anchor */;
    anchor.AppProperties[@"last-user-access"] = @"just now";
    await this.cloudSession.UpdateAnchorPropertiesAsync(anchor);

Non è possibile aggiornare la posizione di un ancoraggio dopo che è stata creato nel servizio, ma è necessario creare un nuovo ancoraggio ed eliminare quello precedente per tenere traccia di una nuova posizione.

Se non è necessario individuare un ancoraggio per aggiornarne le proprietà, è possibile usare il metodo GetAnchorPropertiesAsync(), che restituisce un oggetto CloudSpatialAnchor con le proprietà.

Altre informazioni sul metodo GetAnchorPropertiesAsync.

    var anchor = await cloudSession.GetAnchorPropertiesAsync(@"anchorId");
    if (anchor != null)
    {
        anchor.AppProperties[@"last-user-access"] = @"just now";
        await this.cloudSession.UpdateAnchorPropertiesAsync(anchor);
    }

Imposta scadenza

È anche possibile configurare l'ancoraggio in modo che scada automaticamente in una data specifica in futuro. Un ancoraggio scaduto non viene più individuato né aggiornato. La scadenza può essere impostata solo quando viene creato l'ancoraggio, prima di salvarlo nel cloud. e non può essere aggiornata in un secondo momento. Se non viene impostata alcuna scadenza durante la creazione dell'ancoraggio, l'ancoraggio scadrà solo quando viene eliminato manualmente.

Altre informazioni sulla proprietà Expiration.

    cloudAnchor.Expiration = DateTimeOffset.Now.AddDays(7);

Individuare un ancoraggio nello spazio cloud

La possibilità di individuare un ancoraggio nello spazio cloud salvato in precedenza è uno dei motivi principali per usare gli ancoraggi nello spazio di Azure. Per questo motivo, usiamo "Watchers". È possibile usare un solo Watcher alla volta; più watcher non sono supportati. Esistono diversi modi (noti anche come strategie di individuazione ancoraggio) che un Watcher può individuare un ancoraggio nello spazio cloud. È possibile usare una strategia in un watcher alla volta.

  • Individuare gli ancoraggi in base all'identificatore.
  • Individuare gli ancoraggi connessi a un ancoraggio individuato in precedenza. Per altre informazioni sulle relazioni tra ancoraggi, vedere qui.
  • Individuare un ancoraggio tramite la rilocalizzazione grossolana.

Nota

Ogni volta che si individua un ancoraggio, Ancoraggi nello spazio di Azure proverà a usare i dati dell'ambiente raccolti per incrementare le informazioni che visualizza. Se si verificano problemi durante l'individuazione di un ancoraggio, può essere utile creare un ancoraggio, quindi individuarlo più volte da varie angolazioni e con condizioni di illuminazione diverse.

Se si individuano ancoraggi nello spazio cloud in base all'identificatore, è possibile archiviare l'identificatore di ancoraggio nello spazio cloud nel servizio back-end dell'applicazione e renderlo accessibile a tutti i dispositivi che possono eseguire correttamente l'autenticazione. Per un esempio, vedere Esercitazione: Condividere ancoraggi nello spazio tra dispositivi.

Creare un'istanza dell'oggetto AnchorLocateCriteria, impostare gli identificatori da cercare e richiamare il metodo CreateWatcher nella sessione specificando AnchorLocateCriteria.

Altre informazioni sul metodo CreateWatcher.

    AnchorLocateCriteria criteria = new AnchorLocateCriteria();
    criteria.Identifiers = new string[] { @"id1", @"id2", @"id3" };
    this.cloudSession.CreateWatcher(criteria);

Dopo la creazione del Watcher, l'evento AnchorLocated viene attivato per ogni ancoraggio richiesto. Questo evento viene generato quando viene individuato un ancoraggio o se non è possibile individuarlo. Se si verifica questa situazione, il motivo verrà indicato nello stato. Dopo che tutti gli ancoraggi per un Watcher vengono elaborati, che siano stati trovati o no, viene generato l'evento LocateAnchorsCompleted. È previsto un limite di 35 identificatori per Watcher.

Altre informazioni sul metodo AnchorLocatedDelegate.

    this.cloudSession.AnchorLocated += (object sender, AnchorLocatedEventArgs args) =>
    {
        switch (args.Status)
        {
            case LocateAnchorStatus.Located:
                CloudSpatialAnchor foundAnchor = args.Anchor;
                // Go add your anchor to the scene...
                break;
            case LocateAnchorStatus.AlreadyTracked:
                // This anchor has already been reported and is being tracked
                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
                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
                break;
        }
    }

Eliminare gli ancoraggi

L'eliminazione di ancoraggi quando non sono più in uso è una prassi valida da includere nelle prime fasi del processo e delle procedure di sviluppo, per mantenere pulite le risorse di Azure.

Altre informazioni sul metodo DeleteAnchorAsync.

    await this.cloudSession.DeleteAnchorAsync(cloudAnchor);
    // Perform any processing you may want when delete finishes

Eliminare l'ancoraggio senza individuare

Se non si riesce a individuare un ancoraggio ma si vuole comunque eliminarlo, è possibile usare l'API GetAnchorPropertiesAsync che accetta un anchorId come input per ottenere l'oggetto CloudSpatialAnchor . È quindi possibile passare questo oggetto a DeleteAnchorAsync per eliminarlo.

var anchor = await cloudSession.GetAnchorPropertiesAsync(@"anchorId");
await this.cloudSession.DeleteAnchorAsync(anchor);

Sospendere, reimpostare o arrestare la sessione

Per arrestare temporaneamente la sessione, è possibile richiamare Stop(). In questo modo verranno arrestati tutti i watcher oltre all'elaborazione dell'ambiente, anche se si richiama ProcessFrame(). È quindi possibile richiamare Start() per riprendere l'elaborazione. Quando si riprende l'elaborazione, i dati dell'ambiente già acquisiti nella sessione vengono mantenuti.

Altre informazioni sul metodo Stop.

    this.cloudSession.Stop();

Per reimpostare i dati dell'ambiente acquisiti nella sessione, è possibile richiamare Reset().

Altre informazioni sul metodo Reset.

    this.cloudSession.Reset();

Per eseguire correttamente la pulizia dopo una sessione, richiamare Dispose().

Altre informazioni sul metodo Dispose.

    this.cloudSession.Dispose();

Passaggi successivi

In questa guida si è appreso come creare e individuare ancoraggi usando Azure Spatial Anchors SDK. Per altre informazioni sulle relazioni tra ancoraggi, passare alla guida successiva.