Guide pratique pour créer et localiser des ancres à l’aide d’Azure Spatial Anchors dans C++/WinRT

Azure Spatial Anchors vous permet de partager des ancres dans le monde entre différents appareils. Il prend en charge plusieurs environnements de développement différents. Dans cet article, nous allons découvrir comment utiliser le kit de développement logiciel (SDK) Azure Spatial Anchors, dans C++/WinRT, pour :

  • Configurer et gérer correctement une session Azure Spatial Anchors.
  • Créer et définir des propriétés sur les ancres locales.
  • Les charger dans le cloud.
  • Rechercher et supprimer les ancres spatiales de cloud.

Prérequis

Pour suivre ce guide, vous devez avoir :

Cross Platform

Initialiser la session

Le point d’entrée principal du kit de développement logiciel (SDK) est la classe qui représente votre session. En règle générale, vous déclarez un champ dans la classe qui gère votre vue et la session AR native.

En savoir plus sur la classe CloudSpatialAnchorSession.

    CloudSpatialAnchorSession m_cloudSession{ nullptr };

    m_cloudSession = CloudSpatialAnchorSession();

Configurer l’authentification

Pour accéder au service, vous devez fournir une clé de compte, un jeton d’accès ou un jeton d’authentification Microsoft Entra. Pour plus d’informations, consultez la page sur les concepts relatifs à l’authentification.

Clés de compte

Les clés de compte sont une information d’identification qui permet à votre application de s’authentifier auprès du service Azure Spatial Anchors. La finalité des clés de compte est de vous aider à démarrer rapidement, notamment lors de la phase de développement de l’intégration de votre application avec Azure Spatial Anchors. Ainsi, vous pouvez utiliser des clés de compte en les incorporant dans vos applications clientes lors du développement. Au fur et à mesure que vous dépassez le stade du développement, il est fortement recommandé de passer à un mécanisme d’authentification de niveau production, pris en charge par les jetons d’accès, ou à une authentification utilisateur Microsoft Entra. Pour obtenir une clé de compte pour le développement, consultez votre compte Azure Spatial Anchors et accédez à l’onglet relatif aux clés.

En savoir plus sur la classe SessionConfiguration.

    auto configuration = m_cloudSession.Configuration();
    configuration.AccountKey(LR"(MyAccountKey)");

Jetons d’accès

Les jetons d’accès sont une méthode plus robuste pour vous authentifier à Azure Spatial Anchors. Plus particulièrement lorsque vous préparez votre application à un déploiement de production. En résumé, cette approche consiste à configurer un service back-end auquel votre application cliente peut s’authentifier en toute sécurité. Vos interfaces de service back-end avec AAD lors de l’exécution et le service de jeton de sécurité Azure Spatial Anchors demande un jeton d’accès. Ce jeton est ensuite remis à l’application cliente et utilisé dans le Kit de développement logiciel pour s’authentifier auprès Azure Spatial Anchors.

    auto configuration = m_cloudSession.Configuration();
    configuration.AccessToken(LR"(MyAccessToken)");

Si un jeton d’accès n’est pas défini, vous devez gérer l’événement TokenRequired, ou implémentez la méthode tokenRequired sur le protocole délégué.

Vous pouvez gérer l’événement de façon synchrone en définissant la propriété sur les arguments d’événement.

En savoir plus sur le délégué TokenRequiredDelegate.

    m_accessTokenRequiredToken = m_cloudSession.TokenRequired(winrt::auto_revoke, [](auto&&, auto&& args) {
        args.AccessToken(LR"(MyAccessToken)");
    });

Si vous avez besoin d’exécuter des tâches asynchrones dans votre gestionnaire, vous pouvez remettre à plus tard la définition du jeton en demandant un objet deferral, puis en le terminant comme indiqué dans l’exemple suivant.

    m_accessTokenRequiredToken = m_cloudSession.TokenRequired(winrt::auto_revoke, [this](auto&&, auto&& args) {
        auto deferral = args.GetDeferral();
        MyGetTokenAsync([&deferral, &args](winrt::hstring const& myToken) {
            if (!myToken.empty()) args.AccessToken(myToken);
            deferral.Complete();
        });
    });

Authentification Microsoft Entra

Azure Spatial Anchors permet également aux applications de s’authentifier à l’aide des jetons utilisateur Microsoft Entra ID (Active Directory). Par exemple, vous pouvez utiliser des jetons Microsoft Entra pour une intégration à Azure Spatial Anchors. Si une entreprise gère des utilisateurs dans Microsoft Entra ID, vous pouvez fournir un jeton utilisateur Microsoft Entra dans le kit de développement logiciel (SDK) Azure Spatial Anchors. Cela vous permet de vous authentifier directement auprès du service Azure Spatial Anchors, pour un compte faisant partie du même locataire Microsoft Entra.

    auto configuration = m_cloudSession.Configuration();
    configuration.AuthenticationToken(LR"(MyAuthenticationToken)");

Comme pour les jetons d’accès, si aucun jeton Microsoft Entra n’est défini, vous devez gérer l’événement TokenRequired ou implémenter la méthode tokenRequired sur le protocole délégué.

Vous pouvez gérer l’événement de façon synchrone en définissant la propriété sur les arguments d’événement.

    m_accessTokenRequiredToken = m_cloudSession.TokenRequired(winrt::auto_revoke, [](auto&&, auto&& args) {
        args.AuthenticationToken(LR"(MyAuthenticationToken)");
    });

Si vous avez besoin d’exécuter des tâches asynchrones dans votre gestionnaire, vous pouvez remettre à plus tard la définition du jeton en demandant un objet deferral, puis en le terminant comme indiqué dans l’exemple suivant.

    m_accessTokenRequiredToken = m_cloudSession.TokenRequired(winrt::auto_revoke, [this](auto&&, auto&& args) {
        auto deferral = args.GetDeferral();
        MyGetTokenAsync([&deferral, &args](winrt::hstring const& myToken) {
            if (!myToken.empty()) args.AuthenticationToken(myToken);
            deferral.Complete();
        });
    });

Configuration d’une session

Appelez Start() pour activer votre session pour traiter les données de l’environnement.

Pour gérer les événements déclenchés par votre session, attachez un gestionnaire d’événements.

En savoir plus sur la méthode Start.

    m_cloudSession.Start();

Fournir des images à la session

La session d’ancrage spatial fonctionne en mappant l’espace autour de l’utilisateur. Cela aide à déterminer l’emplacement des points d’ancrage. Les plateformes mobiles (iOS et Android) nécessitent un appel natif à l’appareil photo pour obtenir des images à partir de la bibliothèque AR de votre plateforme. En revanche, HoloLens analyse constamment l’environnement. Il n’est donc pas nécessaire d’effectuer un appel, comme avec les plateformes mobiles.

En savoir plus sur la méthode ProcessFrame.

    m_cloudSession->ProcessFrame(ar_frame_);

Envoyer vos commentaires à l’utilisateur

Vous pouvez écrire du code pour gérer l’événement de session de mise à jour. Cet événement se déclenche chaque fois que la session améliore sa compréhension de votre environnement. Vous pouvez ainsi :

  • Utilisez la classe UserFeedback pour apporter vos commentaires à l’utilisateur pendant que l’appareil est déplacé et que la session met à jour sa compréhension de l’environnement. Pour ce faire, effectuez la procédure suivante :
  • Déterminez s’il y a suffisamment de données spatiales suivies pour créer ou localiser des ancres spatiales. Vous pouvez le déterminer avec ReadyForCreateProgress ou RecommendedForCreateProgress. Une fois que ReadyForCreateProgress est supérieur à 1, nous disposons de suffisamment de données pour enregistrer une ancre spatiale cloud. Toutefois, nous vous recommandons d’attendre que RecommendedForCreateProgress soit supérieur à 1 pour le faire.

En savoir plus sur la méthode SessionUpdatedDelegate.

    m_sessionUpdatedToken = m_cloudSession.SessionUpdated(winrt::auto_revoke, [this](auto&&, auto&& args)
    {
        auto status = args.Status();
        if (status.UserFeedback() == SessionUserFeedback::None) return;
        m_feedback = LR"(Feedback: )" + FeedbackToString(status.UserFeedback()) + LR"( -)" +
            LR"( Recommend Create=)" + FormatPercent(status.RecommendedForCreateProgress() * 100.f);
    });

Créer une ancre spatiale cloud

Pour créer une ancre spatiale cloud, vous devez d’abord créer une ancre dans le système AR de votre plateforme, puis créer un équivalent cloud. Vous utilisez la méthode CreateAnchorAsync().

En savoir plus sur la classe CloudSpatialAnchor.

    // Initialization
    SpatialStationaryFrameOfReference m_stationaryReferenceFrame = nullptr;
    HolographicDisplay defaultHolographicDisplay = HolographicDisplay::GetDefault();
    SpatialLocator spatialLocator = defaultHolographicDisplay.SpatialLocator();
    m_stationaryReferenceFrame = spatialLocator.CreateStationaryFrameOfReferenceAtCurrentLocation();

    // Create a local anchor, perhaps by positioning a SpatialAnchor a few meters in front of the user
    SpatialAnchor localAnchor{ nullptr };
    PerceptionTimestamp timestamp = PerceptionTimestampHelper::FromHistoricalTargetTime(DateTime::clock::now());
    SpatialCoordinateSystem currentCoordinateSystem = m_attachedReferenceFrame.GetStationaryCoordinateSystemAtTimestamp(timestamp);
    SpatialPointerPose pose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, timestamp);

    // Get the gaze direction relative to the given coordinate system.
    const float3 headPosition = pose.Head().Position();
    const float3 headDirection = pose.Head().ForwardDirection();

    // The anchor is positioned two meter(s) along the user's gaze direction.
    constexpr float distanceFromUser = 2.0f; // meters
    const float3 gazeAtTwoMeters = headPosition + (distanceFromUser * headDirection);

    localAnchor = SpatialAnchor::TryCreateRelativeTo(currentCoordinateSystem, gazeAtTwoMeters);

    // 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.
    CloudSpatialAnchor cloudAnchor = CloudSpatialAnchor();
    cloudAnchor.LocalAnchor(localAnchor);
    co_await m_cloudSession.CreateAnchorAsync(cloudAnchor);
    m_feedback = LR"(Created a cloud anchor with ID=)" + cloudAnchor.Identifier();

Comme nous l’avons dit précédemment, vous devez capturer suffisamment de données d’environnement avant d’essayer de créer une ancre spatiale cloud. Cela signifie que ReadyForCreateProgress doit être supérieur à 1, même si nous vous recommandons d’attendre que RecommendedForCreateProgress soit supérieur à 1 pour le faire.

En savoir plus sur la méthode GetSessionStatusAsync.

    SessionStatus status = co_await m_cloudSession.GetSessionStatusAsync();
    if (value.RecommendedForCreateProgress() < 1.0f) return;
    // Issue the creation request ...

Définir des propriétés

Vous pouvez choisir d’ajouter certaines propriétés lors de l’enregistrement de vos ancres spatiales cloud. Vous pouvez notamment ajouter le type d’objet enregistré ou des propriétés de base comme l’activation pour l’interaction. Cela peut être utile à la suite d’une détection : vous pouvez immédiatement afficher l’objet pour l’utilisateur, par exemple un cadre d’image ne présentant aucun contenu. Ensuite, un autre téléchargement en arrière-plan obtient des détails supplémentaires sur l’état, comme l’image à afficher dans le cadre.

En savoir plus sur la méthode AppProperties.

    CloudSpatialAnchor cloudAnchor = CloudSpatialAnchor();
    cloudAnchor.LocalAnchor(localAnchor);
    auto properties = m_cloudAnchor.AppProperties();
    properties.Insert(LR"(model-type)", LR"(frame)");
    properties.Insert(LR"(label)", LR"(my latest picture)");
    co_await m_cloudSession.CreateAnchorAsync(cloudAnchor);

Mettre à jour des propriétés

Pour mettre à jour les propriétés d’une ancre, vous utilisez la méthode UpdateAnchorProperties(). Si deux ou plusieurs appareils essaient de mettre à jour simultanément des propriétés pour la même ancre, nous utilisons un modèle d’accès concurrentiel optimiste. Ce qui signifie que la première écriture gagne. Toutes les autres écritures obtiendront une erreur « Accès concurrentiel » indiquant qu’une mise à jour des propriétés est nécessaire avant de réessayer.

En savoir plus sur la méthode UpdateAnchorPropertiesAsync.

    CloudSpatialAnchor anchor = /* locate your anchor */;
    anchor.AppProperties().Insert(LR"(last-user-access)", LR"(just now)");
    co_await m_cloudSession.UpdateAnchorPropertiesAsync(anchor);

Vous ne pouvez pas mettre à jour l’emplacement d’une ancre une fois qu’elle a été créée sur le service, vous devez créer une nouvelle ancre et supprimer l’ancienne pour effectuer le suivi d’une nouvelle position.

Si vous n’avez pas besoin de localiser une ancre pour mettre à jour ses propriétés, vous pouvez utiliser la méthode GetAnchorPropertiesAsync(), qui renvoie un objet CloudSpatialAnchor avec des propriétés.

En savoir plus sur la méthode GetAnchorPropertiesAsync.

    CloudSpatialAnchor anchor = co_await m_cloudSession.GetAnchorPropertiesAsync(LR"(anchorId)");
    if (anchor != nullptr)
    {
        anchor.AppProperties().Insert(LR"(last-user-access)", LR"(just now)");
        co_await m_cloudSession.UpdateAnchorPropertiesAsync(anchor);
    }

Définir une expiration

Il est également possible de configurer votre ancre pour qu’elle expire automatiquement à une date future définie. Lorsqu’une ancre expire, elle ne sera plus localisée, ni mise à jour. L’expiration peut uniquement être définie lors de la création de l’ancre, avant son enregistrement dans le cloud. La mise à jour de l’expiration par la suite n’est pas possible. Si aucune expiration n’est définie lors de la création de l’ancre, l’ancre expire seulement quand elle est supprimée manuellement.

En savoir plus sur la méthode Expiration.

    const int64_t oneWeekFromNowInHours = 7 * 24;
    const DateTime oneWeekFromNow = DateTime::clock::now() + std::chrono::hours(oneWeekFromNowInHours);
    cloudAnchor.Expiration(oneWeekFromNow);

Localiser une ancre spatiale cloud

La capacité à localiser une ancre spatiale cloud enregistrée précédemment constitue l’un des principaux avantages d’Azure Spatial Anchors. Pour cela, nous utilisons des « Watchers ». Vous ne pouvez utiliser qu’un Watcher à la fois. Les Watchers multiples ne sont pas pris en charge. Un Watcher peut localiser une ancre spatiale cloud de différentes façons (également connues sous le nom de stratégies de localisation d’ancre). Vous ne pouvez utiliser une stratégie que sur un seul observateur à la fois.

  • Localisez les ancres à l’aide de leur identificateur.
  • Localisez les ancres qui sont connectées à une ancre précédemment localisée. Pour plus d’informations sur les relations entre les ancres, cliquez ici.
  • Localisez l’ancre à l’aide de l’option Relocalisation grossière.

Notes

Chaque fois que vous localisez une ancre, les ancres spatiales Azure essaient d’utiliser les données d’environnement collectées pour compléter les informations visuelles sur l’ancre. Si vous rencontrez des difficultés pour localiser une ancre, il peut être utile de créer une ancre, puis de la localiser plusieurs fois à partir de différents angles et conditions d’éclairage.

Si vous localisez des ancres spatiales cloud à l’aide de leur identificateur, vous pouvez stocker celui-ci dans le service back-end de votre application et le rendre accessible à tous les appareils qui peuvent s’authentifier correctement auprès de lui. Pour obtenir un exemple, consultez Tutoriel : Partager des ancres spatiales sur des appareils.

Instanciez un objet AnchorLocateCriteria, définissez les identificateurs que vous recherchez, et invoquez la méthode CreateWatcher sur la session en fournissant votre AnchorLocateCriteria.

En savoir plus sur la méthode CreateWatcher.

    AnchorLocateCriteria criteria = AnchorLocateCriteria();
    criteria.Identifiers({ LR"(id1)", LR"(id2)", LR"(id3)" });
    auto cloudSpatialAnchorWatcher = m_cloudSession.CreateWatcher(criteria);

Une fois votre ressource Watcher créée, l’événement AnchorLocated se déclenche pour chaque ancre demandée. Cet événement se déclenche lorsqu’une ancre est localisée, ou si l’ancre ne peut pas être localisée. Si cette situation se produit, la raison est indiquée dans l’état. Après le traitement de toutes les ancres d’une ressource Watcher, trouvées ou non, l’événement LocateAnchorsCompleted se déclenche. Il y a une limite de 35 identificateurs par ressource Watcher.

En savoir plus sur le délégué AnchorLocatedDelegate.

    m_anchorLocatedToken = m_cloudSession.AnchorLocated(winrt::auto_revoke, [this](auto&&, auto&& args)
    {
        switch (args.Status())
        {
            case LocateAnchorStatus::Located:
            {
                CloudSpatialAnchor foundAnchor = args.Anchor();
            }
                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;
        }
    });

Supprimer les points d’ancrage

La suppression des ancres lorsqu’elles ne sont plus utilisées est un bon réflexe à adopter tôt dans votre processus et vos méthodes de développement pour optimiser vos ressources Azure.

En savoir plus sur la méthode DeleteAnchorAsync.

    co_await m_cloudSession.DeleteAnchorAsync(cloudAnchor);
    // Perform any processing you may want when delete finishes

Suspendre, réinitialiser ou arrêter la session

Pour arrêter la session temporairement, vous pouvez appeler Stop(). Ainsi, le traitement de tous les observateurs et environnements s’arrête, même si vous appelez ProcessFrame(). Vous pouvez ensuite appeler Start() pour reprendre le traitement. Lors de la reprise, les données d’environnement déjà capturées dans la session sont conservées.

En savoir plus sur la méthode Stop.

    m_cloudSession.Stop();

Pour réinitialiser les données d’environnement qui ont été capturées dans votre session, vous pouvez appeler Reset().

En savoir plus sur la méthode Reset.

    m_cloudSession.Reset();

Pour nettoyer correctement après une session, libérez toutes les références.

    m_cloudSession = nullptr;

Étapes suivantes

Dans ce guide, vous avez appris comment créer et localiser des ancres à l’aide du Kit de développement logiciel (SDK) Spatial Anchors. Pour en savoir plus sur les relations entre les ancres, passez au guide suivant.