Erstellen von und Suchen nach Ankern mit Azure Spatial Anchors in Unity

Azure Spatial Anchors ermöglicht die weltweite gemeinsame Verwendung von Ankern durch verschiedene Geräte. Der Dienst unterstützt verschiedene Entwicklungsumgebungen. In diesem Artikel wird erläutert, wie das Azure Spatial Anchors SDK in Unity für die folgenden Aufgaben verwendet werden kann:

  • Ordnungsgemäßes Einrichten und Verwalten einer Azure Spatial Anchors-Sitzung.
  • Erstellen und Festlegen von Eigenschaften für lokale Anker.
  • Hochladen von Ankern in die Cloud.
  • Suchen nach und Löschen von räumlichen Cloudankern.

Voraussetzungen

Um diese Anleitung durchzuführen, stellen Sie sicher, dass Folgendes erfüllt ist:

Cross Platform

Initialisieren der Sitzung

Der Haupteinstiegspunkt für das SDK ist die Klasse, die die Sitzung darstellt. In der Regel müssen Sie ein Feld in der Klasse deklarieren, die Ihre Ansicht und die native AR-Sitzung verwaltet.

Erfahren Sie mehr über die CloudSpatialAnchorSession-Klasse.

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

Einrichten der Authentifizierung

Um auf den Dienst zugreifen zu können, müssen Sie einen Kontoschlüssel, ein Zugriffstoken oder ein Microsoft Entra-Authentifizierungstoken angeben. Weitere Informationen hierzu finden Sie auf der Konzeptseite für die Authentifizierung.

Kontoschlüssel

Kontoschlüssel sind eine Anmeldeinformationen, die es Ihrer Anwendung ermöglichen, sich beim Azure Spatial Anchors-Dienst zu authentifizieren. Der Zweck von Kontoschlüsseln besteht darin, Ihnen einen schnellen Einstieg zu ermöglichen. Vor allem während der Entwicklungsphase der Integration Ihrer Anwendung mit Azure Spatial Anchors. Sie können Kontoschlüssel verwenden, indem Sie sie während der Entwicklung in Ihre Clientanwendungen einbetten. Nach Abschluss der Entwicklung wird dringend empfohlen, zu einem Authentifizierungsmechanismus für die Produktionsebene zu wechseln, der von Zugriffstoken oder Microsoft Entra-basierter Benutzerauthentifizierung unterstützt wird. Um einen Kontoschlüssel für die Entwicklung zu erhalten, besuchen Sie Ihr Azure Spatial Anchors-Konto, und navigieren Sie zur Registerkarte „Schlüssel“.

Erfahren Sie mehr über die SessionConfiguration-Klasse.

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

Zugriffstoken

Zugriffstoken sind eine robustere Methode zur Authentifizierung bei Azure Spatial Anchors. Vor allem, wenn Sie Ihre Anwendung für eine Produktionsbereitstellung vorbereiten. Die Zusammenfassung dieses Ansatzes besteht darin, einen Back-End-Dienst einzurichten, bei dem sich Ihre Clientanwendung sicher authentifizieren kann. Ihr Back-End-Dienst kommuniziert zur Runtime mit AAD und mit dem STS-Dienst (Secure Token Service) von Azure Spatial Anchors, um ein Zugriffstoken anzufordern. Dieses Token wird dann der Clientanwendung bereitgestellt und im SDK zur Authentifizierung bei Azure Spatial Anchors verwendet.

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

Wenn ein Zugriffstoken nicht festgelegt ist, müssen Sie das TokenRequired-Ereignis behandeln oder die tokenRequired-Methode im Delegatenprotokoll implementieren.

Sie können das Ereignis synchron behandeln, indem Sie die Eigenschaft für die Ereignisargumente festlegen.

Erfahren Sie mehr über den TokenRequiredDelegate-Delegaten.

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

Wenn Sie in Ihrem Handler asynchrone Arbeit ausführen müssen, können Sie die Einstellung des Token verzögern, indem Sie ein deferral-Objekt anfordern und es dann wie im folgenden Beispiel abschließen.

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

Microsoft Entra-Authentifizierung

Bei Azure Spatial Anchors können Anwendungen sich auch mit Microsoft Entra ID-Benutzertoken (Active Directory) authentifizieren. Sie können beispielsweise Microsoft Entra-Token für die Integration in Azure Spatial Anchors verwenden. Wenn ein Unternehmen Benutzer*innen in Microsoft Entra ID verwaltet, können Sie ein Microsoft Entra-Benutzertoken im Azure Spatial Anchors-SDK bereitstellen. Auf diese Weise ermöglichen Sie für Konten, die zum gleichen Microsoft Entra-Mandanten gehören, eine direkte Authentifizierung beim Azure Spatial Anchors-Dienst.

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

Wenn ein Microsoft Entra-Token nicht festgelegt ist, müssen Sie wie bei Zugriffstoken das TokenRequired-Ereignis behandeln oder die tokenRequired-Methode im Delegatenprotokoll implementieren.

Sie können das Ereignis synchron behandeln, indem Sie die Eigenschaft für die Ereignisargumente festlegen.

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

Wenn Sie in Ihrem Handler asynchrone Arbeit ausführen müssen, können Sie die Einstellung des Token verzögern, indem Sie ein deferral-Objekt anfordern und es dann wie im folgenden Beispiel abschließen.

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

Einrichten der Sitzung

Rufen Sie Start() auf, damit Ihre Sitzung Umgebungsdaten verarbeitet.

Um die von der Sitzung ausgelösten Ereignisse behandeln zu können, fügen Sie einen Ereignishandler an.

Erfahren Sie mehr über die Start-Methode.

#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();

Bereitstellen von Rahmen für die Sitzung

Bei einer Sitzung mit Raumankern wird die Umgebung zugeordnet, in der sich der Benutzer gerade befindet. Auf diese Weise lässt sich ermitteln, wo sich Anker befinden. Mobile Plattformen (iOS und Android) erfordern einen nativen Aufruf des Kamerafeeds, um Rahmen aus der AR-Bibliothek Ihrer Plattform abzurufen. Im Gegensatz dazu scannt HoloLens die Umgebung ständig, sodass kein gesonderter Aufruf wie bei mobilen Plattformen erforderlich ist.

Erfahren Sie mehr über die ProcessFrame-Methode.

#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

Bereitstellen von Feedback für Benutzer

Sie können Code schreiben, um das aktualisierte Sitzungsereignis zu verarbeiten. Dieses Ereignis wird jedes Mal ausgelöst, wenn die Sitzung ihr Verständnis für Ihre Umgebung verbessert. Auf diese Weise können Sie Folgendes erreichen:

  • Verwenden Sie die Klasse UserFeedback, um Feedback für Benutzer bereitzustellen, wenn sich das Gerät bewegt und die Sitzung die Informationen zur Umgebung aktualisiert. Gehen Sie dazu folgendermaßen vor:
  • Bestimmen Sie, an welchem Punkt genügend räumliche Daten erfasst wurden, um Raumanker zu erstellen. Verwenden Sie hierzu ReadyForCreateProgress oder RecommendedForCreateProgress. Sobald ReadyForCreateProgress größer 1 ist, liegen genügend Daten zum Speichern eines cloudbasierten Raumankers vor. Es empfiehlt sich jedoch, damit zu warten, bis RecommendedForCreateProgress größer 1 ist.

Erfahren Sie mehr über den SessionUpdatedDelegate-Delegaten.

    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.#%}";
    };

Erstellen eines cloudbasierten Raumankers

Um einen cloudbasierten Raumanker zu erstellen, erstellen Sie zunächst einen Anker im AR-System Ihrer Plattform und dann ein Cloudgegenstück. Sie verwenden die CreateAnchorAsync()-Methode.

Erfahren Sie mehr über die CloudSpatialAnchor-Klasse.

    // 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}");

Wie bereits erwähnt, benötigen Sie ausreichende Umgebungsdaten, um einen neuen cloudbasierten Raumanker erstellen zu können. Das bedeutet, dass ReadyForCreateProgress größer 1 sein muss. Es empfiehlt sich jedoch, zu warten, bis RecommendedForCreateProgress größer 1 ist.

Erfahren Sie mehr über GetSessionStatusAsync-Methode.

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

Eigenschaften festlegen

Beim Speichern Ihrer cloudbasierten Raumanker können Sie einige Eigenschaften hinzufügen. Beispiele: die Art des gespeicherten Objekts oder grundlegende Eigenschaften wie etwa das Ermöglichen von Interaktion. Solche Eigenschaften können beim Ermitteln nützlich sein: Sie können ein Objekt sofort für den Benutzer rendern – z.B. als Bildrahmen mit leerem Inhalt. Ein anderer Download im Hintergrund stellt dann zusätzliche Statusdetails bereit, beispielsweise das Bild, das im Rahmen angezeigt werden soll.

Erfahren Sie mehr über die AppProperties-Eigenschaft.

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

Aktualisieren von Eigenschaften

Um die Eigenschaften eines Ankers zu aktualisieren, verwenden Sie die UpdateAnchorProperties()-Methode. Wenn zwei oder mehr Geräte gleichzeitig versuchen, die Eigenschaften für den gleichen Anker zu aktualisieren, verwenden wir ein Modell der optimistischen Nebenläufigkeit. Das bedeutet, dass der erste Schreibvorgang gewinnt. Bei allen anderen Schreibvorgängen tritt ein Parallelitätsfehler auf: Vor einem erneuten Versuch müssen die Eigenschaften aktualisiert werden.

Erfahren Sie mehr über die UpdateAnchorPropertiesAsync-Methode.

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

Sie können den Speicherort eines Ankers nicht aktualisieren, nachdem er für den Dienst erstellt wurde – Sie müssen einen neuen Anker erstellen und den alten löschen, um eine neue Position zu verfolgen.

Wenn Sie einen Anker nicht suchen müssen, um seine Eigenschaften zu aktualisieren, können Sie die GetAnchorPropertiesAsync()-Methode verwenden, die ein CloudSpatialAnchor-Objekt mit Eigenschaften zurückgibt.

Erfahren Sie mehr über die GetAnchorPropertiesAsync-Methode.

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

Ablaufdatum festlegen

Sie können Ihren Anker auch so konfigurieren, dass er an einem bestimmten Datum automatisch abläuft. Wenn ein Anker abläuft, wird er nicht mehr lokalisiert oder aktualisiert. Ein Ablauf kann nur beim Erstellen des Ankers festgelegt werden, bevor er in der Cloud gespeichert wird. Eine nachträgliche Aktualisierung des Ablaufdatums ist nicht möglich. Wenn während der Erstellung des Ankers kein Ablauf festgelegt wird, läuft der Anker nur ab, wenn er manuell gelöscht wird.

Erfahren Sie mehr über die Expiration-Eigenschaft.

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

Lokalisieren eines cloudbasierten Raumankers

Die Möglichkeit, einen zuvor gespeicherten cloudbasierten Raumanker zu lokalisieren, ist einer der Hauptgründe für die Nutzung von Azure Spatial Anchors. Dazu verwenden wir "Watchers". Sie können jeweils nur einen Watcher verwenden. Mehrere Watchers werden nicht unterstützt. Es gibt verschiedene Möglichkeiten (auch bekannt als Anchor Locate Strategies) ein Watcher kann einen Cloudraumanker finden. Sie können jeweils eine Strategie pro Watcher verwenden.

  • Lokalisieren von Ankern anhand des Bezeichners
  • Lokalisieren von Ankern, die mit einem zuvor lokalisierten Anker verbunden sind. Informationen zu Ankerbeziehungen finden Sie hier.
  • Lokalisieren eines Ankers unter Verwendung der ungefähren Standortbestimmung

Hinweis

Bei jeder Lokalisierung eines Ankers wird von Azure Spatial Anchors versucht, die erfassten Umgebungsdaten zu verwenden, um die visuellen Informationen des Ankers zu erweitern. Falls Sie beim Lokalisieren eines Ankers Probleme haben, kann es hilfreich sein, einen Anker zu erstellen und diesen dann mehrfach aus unterschiedlichen Winkeln und bei unterschiedlichen Lichtverhältnissen zu lokalisieren.

Wenn Sie cloudbasierte Raumanker anhand des Bezeichners lokalisieren, sollten Sie den Bezeichner des cloudbasierten Raumankers im Back-End-Dienst Ihrer Anwendung speichern und für alle Geräte verfügbar machen, die sich ordnungsgemäß authentifizieren können. Ein entsprechendes Beispiel finden Sie unter Tutorial: Freigeben von Raumankern für Geräte.

Instanziieren Sie ein AnchorLocateCriteria-Objekt, legen Sie die zu suchenden IDs fest, und rufen Sie die CreateWatcher-Methode für die Sitzung auf, indem Sie Ihr AnchorLocateCriteria-Objekt angeben.

Erfahren Sie mehr über die CreateWatcher-Methode.

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

Nachdem Ihr Watcher erstellt wurde, wird das AnchorLocated-Ereignis für jeden angeforderten Anker ausgelöst. Dieses Ereignis wird sogar dann ausgelöst, wenn ein Anker gefunden wird, oder der Anker nicht gefunden werden kann. Wenn dies geschieht, wird die Ursache im Status angegeben. Nachdem alle Anker für einen Watcher – ob gefunden oder nicht gefunden – verarbeitet wurden, wird das LocateAnchorsCompleted-Ereignis ausgelöst. Es besteht eine Beschränkung von 35 Bezeichner pro Watcher.

Erfahren Sie mehr über den AnchorLocatedDelegate-Delegaten.

    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;
        }
    }

Löschen von Ankern

Das Löschen von Ankern, die nicht mehr verwendet werden, ist eine bewährte Methode, die Sie frühzeitig in Ihren Entwicklungsprozess und Ihre Praktiken einbeziehen sollten, damit Ihre Azure-Ressourcen bereinigt werden.

Erfahren Sie mehr über die DeleteAnchorAsync-Methode.

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

Löschen des Ankers ohne Ortung

Wenn Sie einen Anker nicht ausfindig machen können, ihn aber dennoch löschen möchten, können Sie die GetAnchorPropertiesAsync-API verwenden, die eine Anker-ID (anchorId) als Eingabe erfordert, um das CloudSpatialAnchor-Objekt abzurufen. Anschließend können Sie dieses Objekt an DeleteAnchorAsync übergeben, um es zu löschen.

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

Anhalten, Zurücksetzen oder Beenden einer Sitzung

Um eine Sitzung vorübergehend anzuhalten, können Sie Stop() aufrufen. Damit werden alle Überwachungskomponenten und sämtliche Prozesse der Umgebungsverarbeitung angehalten, auch wenn Sie ProcessFrame() aufrufen. Danach können Sie Start() aufrufen, um die Verarbeitung fortzusetzen. Beim Fortsetzen werden alle in der Sitzung bereits erfassten Umgebungsdaten beibehalten.

Erfahren Sie mehr über die Stop-Methode.

    this.cloudSession.Stop();

Um die Umgebungsdaten zurückzusetzen, die in der Sitzung erfasst wurden, können Sie Reset() aufrufen.

Erfahren Sie mehr über die Reset-Methode.

    this.cloudSession.Reset();

Zur ordnungsgemäßen Bereinigung nach einer Sitzung rufen Sie Dispose() auf.

Erfahren Sie mehr über die Dispose-Methode.

    this.cloudSession.Dispose();

Nächste Schritte

In dieser Anleitung haben Sie gelernt, wie Sie mit dem Azure Spatial Anchors SDK Anker erstellen und lokalisieren. Weitere Informationen zu Ankerbeziehungen finden Sie in der nächsten Anleitung.