Как создавать и искать привязки с помощью Пространственных привязок Azure в Java
Пространственные привязки Azure позволяют вам совместно использовать привязки на различных устройствах. Служба поддерживает несколько сред разработки. Из этой статьи вы узнаете, как использовать пакет SDK Пространственных привязок Azure в Java, чтобы выполнять следующие действия:
- правильно настраивать сеанс Пространственных привязок Azure и управлять им;
- создавать и настраивать свойства в локальных привязках;
- передавать их в облако;
- обнаруживать и удалять пространственные привязки в облаке.
Необходимые компоненты
Для работы с руководством вам потребуется следующее:
- Прочесть статью Описание службы "Пространственные привязки Azure".
- Выполнить одно из 5-минутных руководств.
- Базовые знания Java.
- Базовые знания ARCore.
Инициализация сеанса
Основной точкой входа для пакета SDK является класс, представляющий ваш сеанс. Обычно нужно объявить поле в классе, который управляет представлением и нативным сеансом AR.
Дополнительные сведения см. в статье о классе CloudSpatialAnchorSession.
private CloudSpatialAnchorSession mCloudSession;
// In your view handler
mCloudSession = new CloudSpatialAnchorSession();
Настройка проверки подлинности
Чтобы получить доступ к службе, необходимо предоставить ключ учетной записи, маркер доступа или маркер проверки подлинности Microsoft Entra. Дополнительные сведения об этом можно также получить на странице с описанием концепции проверки подлинности.
Ключи учетных записей
Ключи учетных записей — это учетные данные, позволяющие приложению проходить проверку подлинности в службе "Пространственные привязки Azure". Назначение ключей учетных записей — помочь быстро приступить к работе. Это важно на этапе разработки интеграции приложения с Пространственными привязками Azure. Таким образом, вы можете использовать ключи учетной записи, внедряя их в клиентские приложения во время разработки. По мере развития настоятельно рекомендуется перейти к механизму проверки подлинности, который является рабочим уровнем, поддерживаемым маркерами доступа или проверкой подлинности пользователя Microsoft Entra. Чтобы получить ключ учетной записи для разработки, откройте учетную запись Пространственных привязок Azure и перейдите на вкладку "Ключи".
Дополнительные сведения см. в статье о классе SessionConfiguration.
mCloudSession.getConfiguration().setAccountKey("MyAccountKey");
Маркеры доступа
Маркеры доступа — это более надежный метод проверки подлинности с помощью Пространственных привязок Azure. Такой метод наиболее актуален при подготовке приложения к рабочему развертыванию. Краткое изложение этого подхода заключается в настройке внутренней службы, с помощью которой клиентское приложение может безопасно выполнять проверку подлинности. Внутренняя служба взаимодействует с AAD во время выполнения и со службой маркера безопасности Пространственных привязок Azure для запроса маркера доступа. Затем этот маркер доставляется клиентскому приложению и используется в пакете SDK для проверки подлинности с помощью Пространственных привязок Azure.
mCloudSession.getConfiguration().setAccessToken("MyAccessToken");
Если маркер доступа не задан, необходимо выполнить обработку события TokenRequired
или реализовать метод tokenRequired
для протокола делегирования.
Событие можно обрабатывать синхронно, задав свойство аргументов события.
Дополнительные сведения см. в статье об интерфейсе TokenRequiredListener.
mCloudSession.addTokenRequiredListener(args -> {
args.setAccessToken("MyAccessToken");
});
Если нужно выполнить асинхронные операции в обработчике, можете отложить установку маркера, запросив объект deferral
, а затем завершить установку, как показано в следующем примере.
mCloudSession.addTokenRequiredListener(args -> {
CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
MyGetTokenAsync(myToken -> {
if (myToken != null) args.setAccessToken(myToken);
deferral.complete();
});
});
Проверка подлинности Microsoft Entra
Пространственные привязки Azure также позволяют приложениям проходить проверку подлинности с помощью маркеров Microsoft Entra ID (Active Directory). Например, можно использовать маркеры Microsoft Entra для интеграции с пространственными привязками Azure. Если корпоративный поддерживает пользователей в идентификаторе Microsoft Entra, вы можете предоставить маркер Microsoft Entra в пакете SDK для пространственных привязок Azure. Это позволяет выполнять проверку подлинности непосредственно в службе пространственных привязок Azure для учетной записи, которая входит в тот же клиент Microsoft Entra.
mCloudSession.getConfiguration().setAuthenticationToken("MyAuthenticationToken");
Как и с маркерами доступа, если маркер Microsoft Entra не задан, необходимо обработать событие TokenRequired или реализовать метод tokenRequired в протоколе делегата.
Событие можно обрабатывать синхронно, задав свойство аргументов события.
mCloudSession.addTokenRequiredListener(args -> {
args.setAuthenticationToken("MyAuthenticationToken");
});
Если нужно выполнить асинхронные операции в обработчике, можете отложить установку маркера, запросив объект deferral
, а затем завершить установку, как показано в следующем примере.
mCloudSession.addTokenRequiredListener(args -> {
CloudSpatialAnchorSessionDeferral deferral = args.getDeferral();
MyGetTokenAsync(myToken -> {
if (myToken != null) args.setAuthenticationToken(myToken);
deferral.complete();
});
});
Настройка сеанса
Вызовите Start()
, чтобы разрешить обработку данных среды в сеансе.
Для обработки событий, вызванных сеансом, подключите обработчик событий.
mCloudSession.setSession(mSession);
mCloudSession.start();
Предоставление кадров для сеанса
Сеанс пространственной привязки работает путем сопоставления пространства вокруг пользователя. Это помогает определить, где находятся привязки. Для мобильных платформ (iOS или Android) требуется собственный вызов канала камеры для получения кадров из библиотеки AR вашей платформы. HoloLens, напротив, постоянно сканирует среду, поэтому нет необходимости в конкретном вызове, например на мобильных платформах.
mCloudSession.processFrame(mSession.update());
Предоставление отзыва пользователю
Вы можете написать код для управления событием обновления сеанса. Это событие срабатывает каждый раз, когда сеанс улучшает распознавание окружающей среды. Это позволит вам:
- использовать класс
UserFeedback
для формирования обратной связи с пользователем при перемещении устройства и обновлении сеансом его распознавания среды. Для этого сделайте следующее. - Определите, на каком этапе отслеживаемых пространственных данных достаточно для создания пространственных привязок. Это можно определить с помощью
ReadyForCreateProgress
илиRecommendedForCreateProgress
. КогдаReadyForCreateProgress
больше 1, у нас достаточно данных для сохранения облачной пространственной привязки, но мы рекомендуем подождать, пока 1 не превыситRecommendedForCreateProgress
.
Дополнительные сведения см. в статье об интерфейсе 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()));
});
Создание облачной пространственной привязки
Чтобы создать облачную пространственную привязку, сначала создайте привязку в системе AR на своей платформе, а затем создайте прототип облака. Воспользуйтесь методом CreateAnchorAsync()
.
Дополнительные сведения см. в статье о классе 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);
}
Как было сказано ранее, прежде чем создавать новую пространственную привязку в облаке необходимо получить достаточное количество данных об окружающей среде. Это означает, что ReadyForCreateProgress
должен быть больше 1, поэтому мы рекомендуем подождать, пока RecommendedForCreateProgress
превысит 1.
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);
}
Задание свойств
Вы можете добавить некоторые свойства при сохранении пространственных привязок облака. Это может быть тип сохраняемого объекта или основные свойства, например, следует ли их включать для взаимодействия. Это может быть полезно при обнаружении: можно сразу же отобразить объект для пользователя, например, кадр с пустым содержимым. Затем в фоновом режиме загружается дополнительная информация о состоянии, например изображение, отображаемое в кадре.
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);
// ...
Обновление свойств
Обновить свойства привязки можно с помощью метода UpdateAnchorProperties()
. Если два или более устройств пытаются одновременно обновить свойства одной и той же привязки, мы используем модель оптимистической блокировки. Это означает, что преимущество отдается первой операции записи. Для всех остальных операций записи поступит сообщение об ошибке параллелизма. Прежде чем повторять попытку, нужно будет обновить свойства.
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);
}
Невозможно обновить расположение привязки после ее создания в службе. Чтобы отслеживать новое расположение, создайте новую привязку и удалите старую.
Если вам не нужно искать привязку для обновления ее свойств, вы можете использовать метод GetAnchorPropertiesAsync()
, который возвращает объект CloudSpatialAnchor
со свойствами.
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);
}
Срок действия
Можно также настроить для привязки автоматическое истечение срока действия в определенный момент времени в будущем. После истечения срока действия привязку больше нельзя будет найти или обновить. Срок действия можно задать только при создании привязки и перед ее сохранением в облаке. После этого изменить срок действия нельзя. Если во время создания привязки не задать срок ее действия, то она продолжит действовать, пока не будетудалена вручную.
Date now = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(now);
cal.add(Calendar.DATE, 7);
Date oneWeekFromNow = cal.getTime();
cloudAnchor.setExpiration(oneWeekFromNow);
Поиск облачной пространственной привязки
Одна из основных причин использования Пространственных привязок Azure — возможность искать ранее сохраненную облачную пространственную привязку. Для этого мы используем "Наблюдатели". Одновременно можно использовать только один наблюдатель; Несколько наблюдателей не поддерживаются. Существует несколько различных способов (также известных как стратегии поиска привязки) наблюдатель может найти облачную пространственную привязку. За один раз можно использовать одну стратегию для наблюдателя.
- Нахождение привязок по идентификатору.
- Нахождение привязок, подключенных к ранее найденной привязке. Больше узнать о связях привязок можно здесь.
- Нахождение привязки, используя Простое уточнение расположения.
Примечание.
Каждый раз при обнаружении привязки Пространственные привязки Azure попытаются использовать собранные данные среды, чтобы расширить визуальные сведения о привязке. Если у вас возникли проблемы с нахождением привязки, можно создать привязку, а затем определить ее несколько раз, используя разные углы и условия освещения.
При поиске пространственных привязок облака по идентификатору можно сохранить идентификатор пространственной привязки облака в серверной службе приложения и сделать его доступным для всех устройств, которые могут правильно пройти проверку подлинности. Пример этого см. в руководстве по совместному использованию пространственных привязок на устройствах.
Создайте экземпляр объекта AnchorLocateCriteria
, задайте идентификаторы, которые вы ищете, и в сеансе вызовите метод CreateWatcher
, предоставив AnchorLocateCriteria
.
AnchorLocateCriteria criteria = new AnchorLocateCriteria();
criteria.setIdentifiers(new String[] { "id1", "id2", "id3" });
mCloudSession.createWatcher(criteria);
Когда вы создадите наблюдатель, для каждой запрошенной привязки будет срабатывать событие AnchorLocated
. Это событие срабатывает, если привязка обнаружена или если ее не удалось найти. В последнем случае причина будет указана в области состояния. Когда для наблюдателя будут обработаны, найдены или не найдены все привязки, сработает событие LocateAnchorsCompleted
. Максимальное количество идентификаторов на наблюдателя — 35.
Дополнительные сведения см. в статье об интерфейсе 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;
}
});
Удаление привязок
Мы рекомендуем удалять неиспользуемые привязки в ходе разработки. Так ваши ресурсы Azure будут очищенными.
Future deleteAnchorFuture = mCloudSession.deleteAnchorAsync(cloudAnchor);
// Perform any processing you may want when delete finishes (deleteAnchorFuture is done)
Приостановка, сброс или остановка сеанса
Чтобы временно остановить сеанс, можно вызвать Stop()
. Это приведет к прерыванию обработки наблюдателей и среды даже при вызове ProcessFrame()
. Затем можно вызвать Start()
, чтобы возобновить обработку. При возобновлении обработанные в сеансе данные сохраняются.
mCloudSession.stop();
Чтобы очистить данные среды, записанные в сеансе, можете вызвать функцию Reset()
.
mCloudSession.reset();
Чтобы правильно выполнить очистку после выхода из сеанса, вызовите close()
.
mCloudSession.close();
Следующие шаги
Из этого руководства вы узнали о том, как создавать и находить привязки с использованием пакета SDK для службы "Пространственные привязки Azure". Чтобы узнать больше о связях между привязками, перейдите к следующему руководству.