Работа с ARCore для Jetpack XR

ARCore для Jetpack XR позволяет приложениям работать с базовыми концепциями дополненной реальности (AR), используя низкоуровневые примитивы понимания сцены и отслеживание движения. Используйте ARCore для Jetpack XR при создании AR-приложений, и вам необходимо использовать плоские данные или привязывать контент к фиксированному местоположению в пространстве.

Понимание жизненного цикла сеанса

Доступ ко всем объектам, отслеживаемым ARCore для Jetpack XR, должен осуществляться через сеанс . Подобно жизненному циклу Activity , объекты Session также имеют жизненный цикл, который должен поддерживаться в соответствии с использованием вашим приложением функций объекта Session. Если ваше приложение содержит одно действие с поддержкой XR, рассмотрите возможность управления жизненным циклом сеанса с помощью компонента, поддерживающего жизненный цикл .

Создать сеанс

Прежде чем использовать сеанс, его необходимо создать. Для создания сеанса пользователю необходимо предоставить разрешение android.permission.SCENE_UNDERSTANDING вашему приложению .

Чтобы создать сеанс:

when (val result = Session.create(owner)) {
  is SessionCreateSuccess -> {
    session = result.session
  }
  is SessionCreatePermissionsNotGranted -> {
   // Request android.permission.SCENE_UNDERSTANDING.
  }
}

См. SessionCreateResult чтобы узнать, почему сеанс не может быть создан.

Возобновить сеанс

Возобновление сеанса следует выполнять, когда ваше приложение готово обрабатывать изменения состояния из ARCore для Jetpack XR. Во многих случаях это делается в обратном вызове onResume() вашего Activity, но ваше приложение может захотеть отложить обработку до взаимодействия с пользователем.

В следующем фрагменте кода показан пример возобновления сеанса.

when (val result = session.resume()) {
  is SessionResumeSuccess -> {
    // Session has been created successfully.
    // Attach any successful handlers here.
  }
  is SessionResumePermissionsNotGranted -> {
    // Request android.permission.SCENE_UNDERSTANDING.
}

См. SessionResumeResult , чтобы узнать, почему сеанс может не возобновиться.

Приостановить сеанс

Когда ваша активность переходит в фоновый режим, приостановите сеанс с помощью Session.pause() . Приостановка сеанса временно прекращает отслеживание до возобновления сеанса, сохраняя состояние системы восприятия.

Уничтожить сеанс

Чтобы навсегда удалить сеанс, используйте Session.destroy() . Это освобождает ресурсы, используемые сеансом, и уничтожает все состояния сеанса.

Получить состояние воспринимаемых плоскостей

ARCore для Jetpack XR предоставляет состояние самолетов через StateFlow , который генерирует состояние самолетов. Подписка на самолеты в сеансе уведомляет ваше приложение о добавлении, обновлении или удалении самолетов.

Plane.subscribe(session).collect { planes ->
 // Planes have changed; update plane rendering
}

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

  • label : семантическое описание данного Plane . Это может быть Wall , Floor , Ceiling или Table .
  • centerPose : Поза центра обнаруженной плоскости.
  • extents : Размеры обнаруженной плоскости в метрах.
  • vertices : список вершин выпуклого многоугольника, аппроксимирующего плоскость.

Проведите тест на попадание в самолеты

Хит-тест — метод расчета пересечения луча с объектами, отслеживаемыми сеансом. Обычное применение проверки нажатия — указать на стол и разместить в этом месте объект. Результатом проверки попадания является список объектов попадания. Другими словами, проверка попадания не останавливается при первом попадании в объект. Однако часто вас может интересовать только первое попадание объекта данного типа.

Чтобы выполнить проверку попадания, используйте Interaction.hitTest() с Ray :

val results = Interaction.hitTest(session, ray)
// When interested in the first Table hit:
val tableHit = results.firstOrNull {
  val trackable = it.trackable
  trackable is Plane && trackable.state.value.label == Plane.Label.Table
}

Привязывайте контент к фиксированному местоположению в пространстве

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

Привязка создается с использованием Pose , которую можно интерпретировать относительно существующего Trackable или нет.

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

Когда привязка создается относительно Trackable , например Plane , которая заставляет привязку следовать за прикрепленным Trackable при его перемещении в пространстве.

val anchor = trackable.createAnchor(pose)

Создайте якорь без Trackable

Чтобы создать привязку, которая не прикреплена к Trackable :

when (val result = Anchor.create(session, pose)) {
  is AnchorCreateSuccess -> // ...
  else -> // handle failure
}

Прикрепите объект к якорю

Чтобы визуализировать модель в этом месте, создайте GltfModel и установите его позу в положение якоря. Убедитесь, что модель скрыта, когда TrackingState Anchor Stopped .

// renderSession is androidx.xr.core.Session
anchor.state.collect { state ->
  if (state.trackingState == TrackingState.Tracking) {
    gltfEntity.setPose(
      renderSession.perceptionSpace.transformPoseTo(state.pose, renderSession.activitySpace)
    )
  } else if (state.trackingState == TrackingState.Stopped) {
    entity.setHidden(true)
  }
}

Понимание состояния отслеживания

Каждый Trackable имеет TrackingState , который следует проверить перед использованием. У Trackable , у которого есть TrackableState Tracking система активно обновляет свою Pose . Trackable , который находится Paused может стать Tracking в будущем, тогда как тот, который Stopped никогда не станет Tracking .

Сохраняйте привязку на протяжении всего сеанса

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

Чтобы сохранить привязку, используйтеnchor.persist anchor.persist() как показано здесь:

val uuid = anchor.persist()

Ваше приложение может получить привязку, используя UUID в будущем сеансе:

when (val result = Anchor.load(session, uuid)) {
  is AnchorCreateSuccess -> // Loading was successful. The anchor is stored in result.anchor.
  else -> // handle failure
}

Если вам больше не нужен якорь, вызовите unpersist() . Это удалит привязку из хранилища вашего приложения и сделает невозможным получение данного UUID для вызовов Anchor.load() .

Anchor.unpersist(session, uuid)

Ваше приложение также может запросить список всех сохраненных привязок, которые все еще присутствуют в хранилище вашего приложения:

val uuids = Anchor.getPersistedAnchorUuids(session)