Создание и поиск привязок с помощью Пространственных привязок Azure в Unity

Пространственные привязки Azure позволяют вам совместно использовать привязки на различных устройствах. Служба поддерживает несколько сред разработки. Из этой статьи вы узнаете, как использовать пакет SDK Пространственных привязок Azure в Unity, чтобы выполнять следующие действия:

  • правильно настраивать сеанс Пространственных привязок Azure и управлять им;
  • создавать и настраивать свойства в локальных привязках;
  • передавать их в облако;
  • обнаруживать и удалять пространственные привязки в облаке.

Необходимые компоненты

Для работы с руководством вам потребуется следующее:

Cross Platform

Инициализация сеанса

Основной точкой входа для пакета SDK является класс, представляющий ваш сеанс. Обычно нужно объявить поле в классе, который управляет представлением и нативным сеансом AR.

Дополнительные сведения см. в статье о классе CloudSpatialAnchorSession.

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

Настройка проверки подлинности

Чтобы получить доступ к службе, необходимо предоставить ключ учетной записи, маркер доступа или маркер проверки подлинности Microsoft Entra. Дополнительные сведения об этом можно также получить на странице с описанием концепции проверки подлинности.

Ключи учетных записей

Ключи учетных записей — это учетные данные, позволяющие приложению проходить проверку подлинности в службе "Пространственные привязки Azure". Назначение ключей учетных записей — помочь быстро приступить к работе. Это важно на этапе разработки интеграции приложения с Пространственными привязками Azure. Таким образом, вы можете использовать ключи учетной записи, внедряя их в клиентские приложения во время разработки. По мере развития настоятельно рекомендуется перейти к механизму проверки подлинности, который является рабочим уровнем, поддерживаемым маркерами доступа или проверкой подлинности пользователя Microsoft Entra. Чтобы получить ключ учетной записи для разработки, откройте учетную запись Пространственных привязок Azure и перейдите на вкладку "Ключи".

Дополнительные сведения см. в статье о классе SessionConfiguration.

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

Маркеры доступа

Маркеры доступа — это более надежный метод проверки подлинности с помощью Пространственных привязок Azure. Такой метод наиболее актуален при подготовке приложения к рабочему развертыванию. Краткое изложение этого подхода заключается в настройке внутренней службы, с помощью которой клиентское приложение может безопасно выполнять проверку подлинности. Внутренняя служба взаимодействует с AAD во время выполнения и со службой маркера безопасности Пространственных привязок Azure для запроса маркера доступа. Затем этот маркер доставляется клиентскому приложению и используется в пакете SDK для проверки подлинности с помощью Пространственных привязок Azure.

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

Если маркер доступа не задан, необходимо выполнить обработку события TokenRequired или реализовать метод tokenRequired для протокола делегирования.

Событие можно обрабатывать синхронно, задав свойство аргументов события.

Дополнительные сведения см. в статье о делегате TokenRequiredDelegate.

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

Если нужно выполнить асинхронные операции в обработчике, можете отложить установку маркера, запросив объект deferral, а затем завершить установку, как показано в следующем примере.

    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

Пространственные привязки Azure также позволяют приложениям проходить проверку подлинности с помощью маркеров Microsoft Entra ID (Active Directory). Например, можно использовать маркеры Microsoft Entra для интеграции с пространственными привязками Azure. Если корпоративный поддерживает пользователей в идентификаторе Microsoft Entra, вы можете предоставить маркер Microsoft Entra в пакете SDK для пространственных привязок Azure. Это позволяет выполнять проверку подлинности непосредственно в службе пространственных привязок Azure для учетной записи, которая входит в тот же клиент Microsoft Entra.

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

Как и с маркерами доступа, если маркер Microsoft Entra не задан, необходимо обработать событие TokenRequired или реализовать метод tokenRequired в протоколе делегата.

Событие можно обрабатывать синхронно, задав свойство аргументов события.

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

Если нужно выполнить асинхронные операции в обработчике, можете отложить установку маркера, запросив объект deferral, а затем завершить установку, как показано в следующем примере.

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

Настройка сеанса

Вызовите Start(), чтобы разрешить обработку данных среды в сеансе.

Для обработки событий, вызванных сеансом, подключите обработчик событий.

Дополнительные сведения см. в статье о методе 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();

Предоставление кадров для сеанса

Сеанс пространственной привязки работает путем сопоставления пространства вокруг пользователя. Это помогает определить, где находятся привязки. Для мобильных платформ (iOS или Android) требуется собственный вызов канала камеры для получения кадров из библиотеки AR вашей платформы. HoloLens, напротив, постоянно сканирует среду, поэтому нет необходимости в конкретном вызове, например на мобильных платформах.

Дополнительные сведения см. в статье о методе 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

Предоставление отзыва пользователю

Вы можете написать код для управления событием обновления сеанса. Это событие срабатывает каждый раз, когда сеанс улучшает распознавание окружающей среды. Это позволит вам:

  • использовать класс UserFeedback для формирования обратной связи с пользователем при перемещении устройства и обновлении сеансом его распознавания среды. Для этого сделайте следующее.
  • Определите, на каком этапе отслеживаемых пространственных данных достаточно для создания пространственных привязок. Это можно определить с помощью ReadyForCreateProgress или RecommendedForCreateProgress. Когда ReadyForCreateProgress больше 1, у нас достаточно данных для сохранения облачной пространственной привязки, но мы рекомендуем подождать, пока 1 не превысит RecommendedForCreateProgress.

Дополнительные сведения см. в статье о делегате 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.#%}";
    };

Создание облачной пространственной привязки

Чтобы создать облачную пространственную привязку, сначала создайте привязку в системе AR на своей платформе, а затем создайте прототип облака. Воспользуйтесь методом CreateAnchorAsync().

Дополнительные сведения см. в статье о классе 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}");

Как было сказано ранее, прежде чем создавать новую пространственную привязку в облаке необходимо получить достаточное количество данных об окружающей среде. Это означает, что ReadyForCreateProgress должен быть больше 1, поэтому мы рекомендуем подождать, пока RecommendedForCreateProgress превысит 1.

Дополнительные сведения см. в статье о методе GetSessionStatusAsync.

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

Задание свойств

Вы можете добавить некоторые свойства при сохранении пространственных привязок облака. Это может быть тип сохраняемого объекта или основные свойства, например, следует ли их включать для взаимодействия. Это может быть полезно при обнаружении: можно сразу же отобразить объект для пользователя, например, кадр с пустым содержимым. Затем в фоновом режиме загружается дополнительная информация о состоянии, например изображение, отображаемое в кадре.

Дополнительные сведения см. в статье о свойстве AppProperties.

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

Обновление свойств

Обновить свойства привязки можно с помощью метода UpdateAnchorProperties(). Если два или более устройств пытаются одновременно обновить свойства одной и той же привязки, мы используем модель оптимистической блокировки. Это означает, что преимущество отдается первой операции записи. Для всех остальных операций записи поступит сообщение об ошибке параллелизма. Прежде чем повторять попытку, нужно будет обновить свойства.

Дополнительные сведения см. в статье о методе UpdateAnchorPropertiesAsync.

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

Невозможно обновить расположение привязки после ее создания в службе. Чтобы отслеживать новое расположение, создайте новую привязку и удалите старую.

Если вам не нужно искать привязку для обновления ее свойств, вы можете использовать метод GetAnchorPropertiesAsync(), который возвращает объект CloudSpatialAnchor со свойствами.

Дополнительные сведения см. в статье о методе GetAnchorPropertiesAsync.

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

Срок действия

Можно также настроить для привязки автоматическое истечение срока действия в определенный момент времени в будущем. После истечения срока действия привязку больше нельзя будет найти или обновить. Срок действия можно задать только при создании привязки и перед ее сохранением в облаке. После этого изменить срок действия нельзя. Если во время создания привязки не задать срок ее действия, то она продолжит действовать, пока не будетудалена вручную.

Дополнительные сведения см. в статье о свойстве Expiration.

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

Поиск облачной пространственной привязки

Одна из основных причин использования Пространственных привязок Azure — возможность искать ранее сохраненную облачную пространственную привязку. Для этого мы используем "Наблюдатели". Одновременно можно использовать только один наблюдатель; Несколько наблюдателей не поддерживаются. Существует несколько различных способов (также известных как стратегии поиска привязки) наблюдатель может найти облачную пространственную привязку. За один раз можно использовать одну стратегию для наблюдателя.

  • Нахождение привязок по идентификатору.
  • Нахождение привязок, подключенных к ранее найденной привязке. Больше узнать о связях привязок можно здесь.
  • Нахождение привязки, используя Простое уточнение расположения.

Примечание.

Каждый раз при обнаружении привязки Пространственные привязки Azure попытаются использовать собранные данные среды, чтобы расширить визуальные сведения о привязке. Если у вас возникли проблемы с нахождением привязки, можно создать привязку, а затем определить ее несколько раз, используя разные углы и условия освещения.

При поиске пространственных привязок облака по идентификатору можно сохранить идентификатор пространственной привязки облака в серверной службе приложения и сделать его доступным для всех устройств, которые могут правильно пройти проверку подлинности. Пример этого см. в руководстве по совместному использованию пространственных привязок на устройствах.

Создайте экземпляр объекта AnchorLocateCriteria, задайте идентификаторы, которые вы ищете, и в сеансе вызовите метод CreateWatcher, предоставив AnchorLocateCriteria.

Дополнительные сведения см. в статье о методе CreateWatcher.

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

Когда вы создадите наблюдатель, для каждой запрошенной привязки будет срабатывать событие AnchorLocated. Это событие срабатывает, если привязка обнаружена или если ее не удалось найти. В последнем случае причина будет указана в области состояния. Когда для наблюдателя будут обработаны, найдены или не найдены все привязки, сработает событие LocateAnchorsCompleted. Максимальное количество идентификаторов на наблюдателя — 35.

Дополнительные сведения см. в статье о делегате 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;
        }
    }

Удаление привязок

Мы рекомендуем удалять неиспользуемые привязки в ходе разработки. Так ваши ресурсы Azure будут очищенными.

Дополнительные сведения см. в статье о методе DeleteAnchorAsync.

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

Удаление привязки без поиска

Если вы не можете найти привязку, но по-прежнему хотите удалить ее, можно использовать GetAnchorPropertiesAsync API, который принимает привязку в качестве входных данных для получения CloudSpatialAnchor объекта. Затем этот объект можно передать в DeleteAnchorAsync удаление.

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

Приостановка, сброс или остановка сеанса

Чтобы временно остановить сеанс, можно вызвать Stop(). Это приведет к прерыванию обработки наблюдателей и среды даже при вызове ProcessFrame(). Затем можно вызвать Start(), чтобы возобновить обработку. При возобновлении обработанные в сеансе данные сохраняются.

Дополнительные сведения см. в статье о методе Stop.

    this.cloudSession.Stop();

Чтобы очистить данные среды, записанные в сеансе, можете вызвать функцию Reset().

Дополнительные сведения см. в статье о методе Reset.

    this.cloudSession.Reset();

Чтобы правильно выполнить очистку после выхода из сеанса, вызовите Dispose().

Дополнительные сведения см. в статье о методе Dispose.

    this.cloudSession.Dispose();

Следующие шаги

Из этого руководства вы узнали о том, как создавать и находить привязки с использованием пакета SDK для службы "Пространственные привязки Azure". Чтобы узнать больше о связях между привязками, перейдите к следующему руководству.