Облачные якоря ARCore с постоянными облачными якорями

1. Обзор

ARCore — это платформа для создания приложений дополненной реальности на мобильных устройствах. API Cloud Anchors дает вам возможность создавать приложения AR, которые используют общую систему координат, позволяя нескольким пользователям размещать виртуальный контент в одном и том же реальном месте.

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

Якоря ARCore и постоянные облачные якоря

Фундаментальной концепцией ARCore является концепция Anchor , которая описывает фиксированную позицию в реальном мире. ARCore автоматически регулирует значение позы якоря по мере того, как его отслеживание движения со временем улучшается.

Облачные якоря — это якоря, размещенные в облаке. Их могут решать несколько пользователей, чтобы установить общую систему координат для пользователей и их устройств.

Хостинг якоря

Когда якорь размещен, происходят следующие вещи:

  1. Поза якоря относительно мира загружается в облако и получается идентификатор облачного якоря.
    Идентификатор облачной привязки — это строка, которую необходимо отправить всем, кто хочет разрешить эту привязку.
  2. Набор данных, содержащий визуальные данные для якоря, загружается на серверы Google.
    Этот набор данных содержит визуальные данные, недавно просмотренные устройством. Небольшое перемещение устройства, чтобы захватить область вокруг привязки с разных точек зрения перед размещением, приведет к лучшей локализации.

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

В этой лаборатории кода вы будете передавать идентификаторы Cloud Anchor с помощью Firebase . Вы можете свободно передавать идентификаторы Cloud Anchor другими способами.

Разрешение якоря

Вы можете использовать API Cloud Anchor для разрешения привязки, используя ее идентификатор Cloud Anchor. При этом создается новая привязка в том же физическом месте, что и исходная размещенная привязка. При разрешении устройство должно использовать ту же физическую среду, что и исходная размещенная привязка.

Постоянные облачные якоря

До версии 1.20 облачные привязки можно было разрешить только в течение 24 часов после их размещения. С помощью API Persistent Cloud Anchors вы можете создать облачную привязку, которая может быть разрешена в течение периода от 1 до 365 дней после создания.

Что вы построите

В этой лаборатории кода вы собираетесь использовать уже существующее приложение ARCore. К концу работы над кодом ваше приложение будет:

  • Иметь возможность размещать постоянные облачные привязки и получать идентификаторы облачных привязок.
  • Сохраните идентификаторы Cloud Anchor на устройстве, чтобы их можно было легко найти с помощью Android SharedPreferences .
  • Используйте сохраненные идентификаторы облачных привязок для разрешения ранее размещенных привязок. Это позволяет нам легко моделировать работу нескольких пользователей с одним устройством для целей этой лаборатории.
  • Поделитесь идентификаторами Cloud Anchor с другим устройством, на котором установлено то же приложение, чтобы несколько пользователей видели статую Android в одном и том же положении.

Статуя Android отображается в позиции облачного якоря:

Что вы узнаете

  • Как разместить якоря с помощью ARCore SDK и получить идентификатор облачного якоря.
  • Как использовать идентификаторы облачных привязок для разрешения привязок.
  • Как хранить и передавать идентификаторы Cloud Anchor ID между разными сеансами AR на одном и том же устройстве или на разных устройствах.

Что вам понадобится

2. Настройте среду разработки

Настройка машины разработки

Подключите устройство ARCore к компьютеру через USB-кабель. Убедитесь, что ваше устройство поддерживает отладку по USB .

Откройте терминал и запустите adb devices , как показано ниже:

adb devices

List of devices attached
<DEVICE_SERIAL_NUMBER>    device

<DEVICE_SERIAL_NUMBER> будет строкой, уникальной для вашего устройства. Прежде чем продолжить, убедитесь, что вы видите ровно одно устройство .

Загрузка и установка кода

Вы можете клонировать репозиторий:

git clone https://github.com/googlecodelabs/arcore-cloud-anchors.git

Или загрузите ZIP-файл и распакуйте его:

Запустите Android-студию. Нажмите «Открыть существующий проект Android Studio» . Затем перейдите в каталог, в который вы распаковали загруженный выше zip-файл, и дважды щелкните каталог arcore-cloud-anchors .

Это один проект Gradle с несколькими модулями. Если панель «Проект» в левом верхнем углу Android Studio еще не отображается на панели «Проект», нажмите «Проекты» в раскрывающемся меню. Результат должен быть таким:

52282f0415fdbdcb.png

Вы будете работать преимущественно в work модуле. Другие модули включают helpers модуль, который содержит набор полезных классов-оболочек, которые вы будете использовать. Существуют также полные решения для каждой части лаборатории кода. За исключением модуля helpers , каждый модуль представляет собой сборное приложение.

Если вы увидите диалоговое окно с предложением обновить плагин Android Gradle, нажмите «Больше не напоминать мне для этого проекта» :

31a93c7e9cc58b53.png

Нажмите «Выполнить» > «Выполнить...» > «работа» . В открывшемся диалоговом окне «Выбор цели развертывания» ваше устройство должно быть указано в разделе «Подключенные устройства» . Выберите свое устройство и нажмите «ОК» . Android Studio создаст исходное приложение и запустит его на вашем устройстве.

Когда вы запускаете приложение в первый раз, оно запросит разрешение CAMERA . Нажмите РАЗРЕШИТЬ , чтобы продолжить.

f7ea81f71a4b969e.png

Как использовать приложение

  1. Перемещайте устройство, чтобы помочь приложению найти самолет . Плоскость будет показана в виде пунктирной поверхности, когда она будет найдена.
  2. Нажмите где-нибудь в самолете, чтобы разместить якорь . Фигура Android будет нарисована там, где был размещен якорь. Это приложение позволяет размещать только один якорь за раз.
  3. Перемещайте устройство . Фигура должна оставаться на том же месте, даже если устройство перемещается.
  4. Нажмите кнопку CLEAR, чтобы удалить якорь . Это позволит вам разместить еще один якорь.

На данный момент это приложение использует только отслеживание движения, предоставляемое ARCore, для отслеживания привязки за один запуск приложения. Если вы решите выйти, закрыть и перезапустить приложение, ранее размещенная привязка и любая связанная с ней информация, включая ее позу, будут потеряны.

В следующих нескольких разделах вы будете использовать это приложение, чтобы увидеть, как можно использовать якоря в сеансах AR.

3. Организуйте якорь

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

Объявить разрешения ИНТЕРНЕТА

Поскольку Cloud Anchor требует связи со службой API ARCore Cloud Anchor, у вашего приложения должно быть разрешение на доступ к Интернету.

В файл AndroidManifest.xml добавьте следующую строку чуть ниже объявления разрешения android.permission.CAMERA :

<!-- Find this line... -->
<uses-permission android:name="android.permission.CAMERA"/>

<!-- Add the line right below -->
<uses-permission android:name="android.permission.INTERNET"/>

Включите API ARCore

  1. Перейдите на страницу сервиса API ARCore .
  2. В списке проектов выберите проект или создайте новый.
  3. Нажмите Включить .

Настройте бесключевую аутентификацию

Чтобы использовать постоянные облачные привязки, вам потребуется использовать аутентификацию без ключа для аутентификации с помощью API ARCore.

  1. Перейдите в консоль Google Cloud Platform .
  2. В списке проектов выберите проект.
  3. Если страница API и сервисы еще не открыта, откройте меню слева консоли и выберите API и сервисы .
  4. Слева нажмите «Учетные данные» .
  5. Нажмите «Создать учетные данные» , затем выберите идентификатор клиента OAuth .
  6. Заполните следующие значения:
    • Тип приложения : Android
    • Имя пакета : com.google.ar.core.codelab.cloudanchor
  7. Получите отпечаток сертификата подписи отладки:
    1. В проекте Android Studio откройте панель инструментов Gradle .
    2. В Cloud-Anchors > Work > Tasks > android запустите задачу SigningReport .
    3. Скопируйте отпечаток SHA-1 в поле отпечатка сертификата SHA-1 в Google Cloud.

Настроить ARCore

Далее вы измените приложение, чтобы оно размещало привязку при нажатии пользователя вместо обычного. Для этого вам необходимо настроить сеанс ARCore для включения облачных привязок.

В файл CloudAnchorFragment.java добавьте следующий код:

// Find this line...
session = new Session(requireActivity());

// Add these lines right below:
// Configure the session.
Config config = new Config(session);
config.setCloudAnchorMode(CloudAnchorMode.ENABLED);
session.configure(config);

Прежде чем продолжить, создайте и запустите свое приложение. Обязательно создайте только work модуль. Ваше приложение должно быть успешно создано и работать так же, как и раньше.

Разместите якорь

Пришло время разместить якорь, который будет загружен в API ARCore.

Добавьте следующее новое поле в свой класс CloudAnchorFragment :

// Find this line...
private Anchor currentAnchor = null;

// Add these lines right below.
@Nullable
private Future future = null;

Не забудьте добавить импорт для com.google.ar.core.Future .

Измените метод onClearButtonPressed следующим образом:

private void onClearButtonPressed() {
  // Clear the anchor from the scene.
  if (currentAnchor != null) {
    currentAnchor.detach();
    currentAnchor = null;
  }

  // The next part is the new addition.
  // Cancel any ongoing asynchronous operations.
  if (future != null) {
    future.cancel();
    future = null;
  }
}

Затем добавьте следующий метод в свой класс CloudAnchorFragment :

private void onHostComplete(String cloudAnchorId, CloudAnchorState cloudState) {
  if (cloudState == CloudAnchorState.SUCCESS) {
    messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Hosted. ID: " + cloudAnchorId);
  } else {
    messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
  }
}

Найдите метод handleTap в классе CloudAnchorFragment и добавьте следующие строки:

// Find this line...
currentAnchor = hit.createAnchor();

// Add these lines right below:
messageSnackbarHelper.showMessage(getActivity(), "Now hosting anchor...");
future = session.hostCloudAnchorAsync(currentAnchor, 300, this::onHostComplete);

Снова запустите приложение из Android Studio. Когда вы размещаете якорь, вы должны увидеть сообщение « Сейчас размещается якорь... ». Вы должны увидеть еще одно сообщение, когда хостинг завершится успешно. Если вы видите сообщение « Ошибка привязки хостинга: ERROR_NOT_AUTHORIZED », убедитесь, что ваш клиент OAuth настроен правильно.

Любой, кто знает идентификатор якоря и находится в том же физическом пространстве, что и якорь, может использовать идентификатор якоря для создания якоря в точно такой же позе (положении и ориентации) относительно окружающей среды.

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

4. Идентификаторы магазинов и привязки разрешения

В этой части вы назначите короткие коды длинным идентификаторам привязки к облаку, чтобы другому пользователю было легче вводить их вручную. Вы будете использовать API общих настроек для хранения идентификаторов облачной привязки в виде значений в таблице «ключ-значение». Эта таблица сохранится, даже если приложение будет закрыто и перезапущено.

Вам уже предоставлен вспомогательный класс под названием StorageManager . Это оболочка API SharedPreferences , в которой есть методы для создания новых уникальных коротких кодов и чтения/записи идентификаторов привязки к облаку.

Используйте диспетчер хранилища

Измените CloudAnchorFragment , чтобы использовать StorageManager для хранения идентификаторов Cloud Anchor с короткими кодами, чтобы их можно было легко получить.

Создайте следующее новое поле в CloudAnchorFragment :

// Find this line...
private TapHelper tapHelper;

// And add the storageManager.
private final StorageManager storageManager = new StorageManager();

Затем измените метод onHostComplete :

private void onHostComplete(String cloudAnchorId, CloudAnchorState cloudState) {
  if (cloudState == CloudAnchorState.SUCCESS) {
    int shortCode = storageManager.nextShortCode(getActivity());
    storageManager.storeUsingShortCode(getActivity(), shortCode, anchor.getCloudAnchorId());
    messageSnackbarHelper.showMessage(
        getActivity(), "Cloud Anchor Hosted. Short code: " + shortCode);
  } else {
    messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
  }
}

Теперь создайте и запустите приложение из Android Studio. При создании и размещении привязки вместо длинных идентификаторов облачной привязки должны отображаться короткие коды.

Сразу после установки якоря

Подождав немного

Обратите внимание, что короткие коды, генерируемые StorageManager , в настоящее время всегда назначаются в порядке возрастания.

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

Добавьте кнопку «Разрешить»

Вы добавите еще одну кнопку рядом с кнопкой CLEAR . Это будет кнопка РЕШИТЬ . Нажатие кнопки «РАЗРЕШИТЬ» откроет диалоговое окно, в котором пользователю будет предложено ввести короткий код. Короткий код используется для получения идентификатора облачной привязки из StorageManager и разрешения привязки.

Чтобы добавить кнопку, вам нужно будет изменить файл res/layout/cloud_anchor_fragment.xml . В Android Studio дважды щелкните файл, затем нажмите вкладку «Текст» внизу, чтобы отобразить необработанный XML. Внесите следующие изменения:

<!-- Find this element. -->
<Button
    android:text="CLEAR"
    android:id="@+id/clear_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

<!-- Add this element right below. -->
<Button
    android:text="RESOLVE"
    android:id="@+id/resolve_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

Теперь добавьте новое поле в CloudAnchorFragment :

private Button resolveButton;

Добавьте новый метод:

private void onResolveButtonPressed() {
  ResolveDialogFragment dialog = new ResolveDialogFragment();
  dialog.show(getFragmentMagetActivity().getSupportFragmentManagernager(), "Resolve");
}

resolveButton в методе onCreateView следующим образом:

// Find these lines...
Button clearButton = rootView.findViewById(R.id.clear_button);
clearButton.setOnClickListener(v -> onClearButtonPressed());

// Add these lines right below.
resolveButton = rootView.findViewById(R.id.resolve_button);
resolveButton.setOnClickListener(v -> onResolveButtonPressed());

Найдите метод handleTap и измените его:

private void handleTap(Frame frame, Camera camera) {
  // ...

  // Find this line.
  currentAnchor = hit.createAnchor();

  // Add this line right below.
  getActivity().runOnUiThread(() -> resolveButton.setEnabled(false)); 
}

Добавьте строку в метод onClearButtonPressed :

private void onClearButtonPressed() {
  // Clear the anchor from the scene.
    if (currentAnchor != null) {
      currentAnchor.detach();
      currentAnchor = null;
    }

    // Cancel any ongoing async operations.
    if (future != null) {
      future.cancel();
      future = null;
    }

  // The next line is the new addition.
  resolveButton.setEnabled(true);
}

Создайте и запустите приложение из Android Studio. Рядом с кнопкой ОЧИСТИТЬ вы должны увидеть кнопку РАЗРЕШИТЬ . Нажатие кнопки «РЕШИТЬ» должно привести к появлению диалогового окна, как показано ниже.

Кнопка РЕШИТЬ теперь видна.

Нажатие кнопки вызывает появление этого диалогового окна.

Нажатие на плоскость и размещение привязки должно отключить кнопку РАЗРЕШИТЬ , но нажатие на кнопку ОЧИСТИТЬ должно включить ее снова. Это сделано специально, чтобы в сцене одновременно находился только один якорь.

Диалоговое окно «Разрешить привязку» ничего не делает, но сейчас вы это измените.

Разрешить якоря

Добавьте следующие методы в класс CloudAnchorFragment :

private void onShortCodeEntered(int shortCode) {
  String cloudAnchorId = storageManager.getCloudAnchorId(getActivity(), shortCode);
  if (cloudAnchorId == null || cloudAnchorId.isEmpty()) {
    messageSnackbarHelper.showMessage(
        getActivity(),
        "A Cloud Anchor ID for the short code " + shortCode + " was not found.");
    return;
  }
  resolveButton.setEnabled(false);
  future = session.resolveCloudAnchorAsync(
      cloudAnchorId, (anchor, cloudState) -> onResolveComplete(anchor, cloudState, shortCode));
}

private void onResolveComplete(Anchor anchor, CloudAnchorState cloudState, int shortCode) {
  if (cloudState == CloudAnchorState.SUCCESS) {
    messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Resolved. Short code: " + shortCode);
    currentAnchor = anchor;
  } else {
    messageSnackbarHelper.showMessage(
        getActivity(),
        "Error while resolving anchor with short code "
            + shortCode
            + ". Error: "
            + cloudState.toString());
    resolveButton.setEnabled(true);
  }
}

Затем измените метод onResolveButtonPressed :

private void onResolveButtonPressed() {
  ResolveDialogFragment dialog = ResolveDialogFragment.createWithOkListener(
      this::onShortCodeEntered);
  dialog.show(getActivity().getSupportFragmentManager(), "Resolve");
}

Создайте и запустите приложение из Android Studio и выполните следующие шаги:

  1. Создайте якорь на плоскости и подождите, пока якорь будет размещен.
    Запомните короткий код.
  2. Нажмите кнопку CLEAR , чтобы удалить якорь.
  3. Нажмите кнопку РЕШИТЬ . Введите короткий код из шага 1.
  4. Вы должны увидеть якорь в том же положении относительно окружающей среды, в каком вы его первоначально разместили.
  5. Закройте и закройте приложение, а затем откройте его снова.
  6. Повторите шаги (3) и (4). Вы должны увидеть новый якорь, снова в том же положении.

Ввод короткого кода

Якорь успешно решен

5. Обмен между устройствами

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

Как ваше приложение будет использовать идентификаторы Cloud Anchor ID, зависит от вас. Для передачи строки с одного устройства на другое можно использовать что угодно. В этой лаборатории кода вы будете использовать базу данных Firebase Realtime для передачи идентификаторов Cloud Anchor между экземплярами приложения.

Настройка Firebase

Вам необходимо настроить базу данных Firebase Realtime с вашей учетной записью Google, чтобы использовать ее с этим приложением. Это легко сделать с помощью Firebase Assistant в Android Studio.

В Android Studio нажмите «Инструменты» > «Firebase» . На всплывающей панели «Ассистент» нажмите «База данных реального времени» , затем нажмите «Сохранить и получить данные» :

68e927cbf324a3b2.png

Нажмите кнопку «Подключиться к Firebase» , чтобы подключить проект Android Studio к новому или существующему проекту Firebase.

63f3b1ffd6bd263e.png

Это предложит вам выбрать модуль. Выберите work модуль:

be737c689ad6dd78.png

Откроется диалоговое окно «Начало подключения». Это может занять некоторое время.

b48626f8672551ee.png

Войдите в свою учетную запись Google и выполните рабочий процесс в Интернете для создания проекта Firebase для вашего приложения, пока не вернетесь в Android Studio.

Затем на панели «Ассистент» нажмите «Добавить базу данных реального времени в ваше приложение» :

68e0843fa2531c4c.png

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

155fd89533c02671.png

Это будет:

  1. Добавьте файл google-services.json в свой work каталог.
  2. Добавьте пару строк в файл build.gradle в том же каталоге.
  3. Создайте и запустите приложение (и вы можете увидеть ошибку разрешения, связанную с номером версии базы данных Firebase).

В файле build.gradle work модуля найдите и удалите следующую строку ( xxxx — это заполнитель для номера последней версии).

dependencies {
  ...
  implementation 'com.google.firebase:firebase-database:xxxx'

Затем просмотрите (но пока не следуйте) инструкции, связанные со страницей настройки правил для публичного доступа, чтобы настроить базу данных Firebase Realtime для записи во всем мире. Это помогает упростить тестирование в этой лаборатории кода:

666ebefd39019c05.png

В консоли Firebase выберите проект, к которому вы подключили проект Android Studio, затем выберите «СОЗДАТЬ» > «База данных реального времени» .

Расположение базы данных Firebase Realtime

Нажмите «Создать базу данных» , чтобы настроить базу данных реального времени :

Создать базу данных

Выберите любое расположение базы данных.

На следующем шаге выберите правила безопасности тестового режима и нажмите «Включить» :

Безопасность базы данных

Теперь ваше приложение настроено для использования базы данных Firebase.

Использование FirebaseManager

Теперь вы замените StorageManager на FirebaseManager .

В Android Studio найдите класс CloudAnchorFragment в work каталоге. Замените StorageManager на FirebaseManager :

// Find this line.
private final StorageManager storageManager = new StorageManager();

// And replace it with this line.
private FirebaseManager firebaseManager;

Инициализируйте firebaseManager в методе onAttach :

public void onAttach(@NonNull Context context) {
  super.onAttach(context);
  tapHelper = new TapHelper(context);
  trackingStateHelper = new TrackingStateHelper(requireActivity());

  // The next line is the new addition.
  firebaseManager = new FirebaseManager(context);
}

Измените метод onShortCodeEntered следующим образом:

private void onShortCodeEntered(int shortCode) {
  firebaseManager.getCloudAnchorId(shortCode, cloudAnchorId -> {
    if (cloudAnchorId == null || cloudAnchorId.isEmpty()) {
      messageSnackbarHelper.showMessage(
          getActivity(),
          "A Cloud Anchor ID for the short code " + shortCode + " was not found.");
      return;
    }
    resolveButton.setEnabled(false);
    future = session.resolveCloudAnchorAsync(
        cloudAnchorId, (anchor, cloudState) -> onResolveComplete(anchor, cloudState, shortCode));
  });
}

Затем измените метод onHostComplete следующим образом:

private void onHostComplete(String cloudAnchorId, CloudAnchorState cloudState) {
  if (cloudState == CloudAnchorState.SUCCESS) {
    firebaseManager.nextShortCode(shortCode -> {
      if (shortCode != null) {
        firebaseManager.storeUsingShortCode(shortCode, cloudAnchorId);
        messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Hosted. Short code: " + shortCode);
      } else {
        // Firebase could not provide a short code.
        messageSnackbarHelper.showMessage(getActivity(), "Cloud Anchor Hosted, but could not "
            + "get a short code from Firebase.");
      }
    });
  } else {
    messageSnackbarHelper.showMessage(getActivity(), "Error while hosting: " + cloudState.toString());
  }
}

Создайте и запустите свое приложение . Вы должны увидеть тот же поток пользовательского интерфейса, что и в предыдущем разделе, за исключением того, что теперь онлайн-база данных Firebase используется для хранения идентификаторов Cloud Anchor ID и коротких кодов вместо локального хранилища устройства.

Многопользовательское тестирование

Чтобы протестировать многопользовательский режим, используйте два разных телефона:

  1. Установите приложение на два устройства.
  2. Используйте одно устройство для размещения привязки и создания короткого кода.
  3. Используйте другое устройство для разрешения привязки, используя этот короткий код.

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

6. Подведение итогов

Поздравляем! Вы достигли конца этой лаборатории кода!

Что мы рассмотрели

  • Как разместить якоря с помощью ARCore SDK и получить идентификатор облачного якоря.
  • Как использовать идентификаторы облачных привязок для разрешения привязок.
  • Как хранить и обмениваться идентификаторами Cloud Anchor ID между разными сеансами AR на одном и том же устройстве или на разных устройствах.

Узнать больше