Guide pratique pour créer et localiser des ancres à l’aide d’Azure Spatial Anchors dans Java
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 Java, 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 :
- Lisez la page Vue d’ensemble d’Azure Spatial Anchors.
- Effectuez l’un des guides de démarrage rapide de 5 minutes.
- Vous connaissez les bases de Java.
- Connaissances de base d’ARCore.
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.
private CloudSpatialAnchorSession mCloudSession;
// In your view handler
mCloudSession = new 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.
mCloudSession.getConfiguration().setAccountKey("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.
mCloudSession.getConfiguration().setAccessToken("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 l'interface TokenRequiredListener.
mCloudSession.addTokenRequiredListener(args -> {
args.setAccessToken("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.
mCloudSession.addTokenRequiredListener(args -> {
CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
MyGetTokenAsync(myToken -> {
if (myToken != null) args.setAccessToken(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.
mCloudSession.getConfiguration().setAuthenticationToken("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.
mCloudSession.addTokenRequiredListener(args -> {
args.setAuthenticationToken("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.
mCloudSession.addTokenRequiredListener(args -> {
CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
MyGetTokenAsync(myToken -> {
if (myToken != null) args.setAuthenticationToken(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.
mCloudSession.setSession(mSession);
mCloudSession.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.
mCloudSession.processFrame(mSession.update());
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
ouRecommendedForCreateProgress
. Une fois queReadyForCreateProgress
est supérieur à 1, nous disposons de suffisamment de données pour enregistrer une ancre spatiale cloud. Toutefois, nous vous recommandons d’attendre queRecommendedForCreateProgress
soit supérieur à 1 pour le faire.
En savoir plus sur l'interface SessionUpdatedListener.
mCloudSession.addSessionUpdatedListener(args -> {
auto status = args->Status();
if (status->UserFeedback() == SessionUserFeedback::None) return;
NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(1);
mFeedback = String.format("Feedback: %s - Recommend Create=%s",
FeedbackToString(status.getUserFeedback()),
percentFormat.format(status.getRecommendedForCreateProgress()));
});
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.
// Create a local anchor, perhaps by hit-testing and creating an ARAnchor
Anchor localAnchor = null;
List<HitResult> hitResults = mSession.update().hitTest(0.5f, 0.5f);
for (HitResult hit : hitResults) {
Trackable trackable = hit.getTrackable();
if (trackable instanceof Plane) {
if (((Plane) trackable).isPoseInPolygon(hit.getHitPose())) {
localAnchor = hit.createAnchor();
break;
}
}
}
// 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 = new CloudSpatialAnchor();
cloudAnchor.setLocalAnchor(localAnchor);
Future createAnchorFuture = mCloudSession.createAnchorAsync(cloudAnchor);
CheckForCompletion(createAnchorFuture, cloudAnchor);
// ...
private void CheckForCompletion(Future createAnchorFuture, CloudSpatialAnchor cloudAnchor) {
new android.os.Handler().postDelayed(() -> {
if (createAnchorFuture.isDone()) {
try {
createAnchorFuture.get();
mFeedback = String.format("Created a cloud anchor with ID=%s", cloudAnchor.getIdentifier());
}
catch(InterruptedException e) {
mFeedback = String.format("Save Failed:%s", e.getMessage());
}
catch(ExecutionException e) {
mFeedback = String.format("Save Failed:%s", e.getMessage());
}
}
else {
CheckForCompletion(createAnchorFuture, cloudAnchor);
}
}, 500);
}
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.
Future<SessionStatus> sessionStatusFuture = mCloudSession.getSessionStatusAsync();
CheckForCompletion(sessionStatusFuture);
// ...
private void CheckForCompletion(Future<SessionStatus> sessionStatusFuture) {
new android.os.Handler().postDelayed(() -> {
if (sessionStatusFuture.isDone()) {
try {
SessionStatus value = sessionStatusFuture.get();
if (value.getRecommendedForCreateProgress() < 1.0f) return;
// Issue the creation request...
}
catch(InterruptedException e) {
mFeedback = String.format("Session status error:%s", e.getMessage());
}
catch(ExecutionException e) {
mFeedback = String.format("Session status error:%s", e.getMessage());
}
}
else {
CheckForCompletion(sessionStatusFuture);
}
}, 500);
}
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.
CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor();
cloudAnchor.setLocalAnchor(localAnchor);
Map<String,String> properties = cloudAnchor.getAppProperties();
properties.put("model-type", "frame");
properties.put("label", "my latest picture");
Future createAnchorFuture = mCloudSession.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.
CloudSpatialAnchor anchor = /* locate your anchor */;
anchor.getAppProperties().put("last-user-access", "just now");
Future updateAnchorPropertiesFuture = mCloudSession.updateAnchorPropertiesAsync(anchor);
CheckForCompletion(updateAnchorPropertiesFuture);
// ...
private void CheckForCompletion(Future updateAnchorPropertiesFuture) {
new android.os.Handler().postDelayed(() -> {
if (updateAnchorPropertiesFuture.isDone()) {
try {
updateAnchorPropertiesFuture.get();
}
catch(InterruptedException e) {
mFeedback = String.format("Updating Properties Failed:%s", e.getMessage());
}
catch(ExecutionException e) {
mFeedback = String.format("Updating Properties Failed:%s", e.getMessage());
}
}
else {
CheckForCompletion1(updateAnchorPropertiesFuture);
}
}, 500);
}
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.
Future<CloudSpatialAnchor> getAnchorPropertiesFuture = mCloudSession.getAnchorPropertiesAsync("anchorId");
CheckForCompletion(getAnchorPropertiesFuture);
// ...
private void CheckForCompletion(Future<CloudSpatialAnchor> getAnchorPropertiesFuture) {
new android.os.Handler().postDelayed(() -> {
if (getAnchorPropertiesFuture.isDone()) {
try {
CloudSpatialAnchor anchor = getAnchorPropertiesFuture.get();
if (anchor != null) {
anchor.getAppProperties().put("last-user-access", "just now");
Future updateAnchorPropertiesFuture = mCloudSession.updateAnchorPropertiesAsync(anchor);
// ...
}
} catch (InterruptedException e) {
mFeedback = String.format("Getting Properties Failed:%s", e.getMessage());
} catch (ExecutionException e) {
mFeedback = String.format("Getting Properties Failed:%s", e.getMessage());
}
} else {
CheckForCompletion(getAnchorPropertiesFuture);
}
}, 500);
}
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.
Date now = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(now);
cal.add(Calendar.DATE, 7);
Date oneWeekFromNow = cal.getTime();
cloudAnchor.setExpiration(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
.
AnchorLocateCriteria criteria = new AnchorLocateCriteria();
criteria.setIdentifiers(new String[] { "id1", "id2", "id3" });
mCloudSession.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 l'interface AnchorLocatedListener.
mCloudSession.addAnchorLocatedListener(args -> {
switch (args.getStatus()) {
case Located:
CloudSpatialAnchor foundAnchor = args.getAnchor();
// Go add your anchor to the scene...
break;
case AlreadyTracked:
// This anchor has already been reported and is being tracked
break;
case 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 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.
Future deleteAnchorFuture = mCloudSession.deleteAnchorAsync(cloudAnchor);
// Perform any processing you may want when delete finishes (deleteAnchorFuture is done)
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.
mCloudSession.stop();
Pour réinitialiser les données d’environnement qui ont été capturées dans votre session, vous pouvez appeler Reset()
.
mCloudSession.reset();
Pour nettoyer correctement après une session, appelez close()
.
mCloudSession.close();
É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.