Используйте геопространственные привязки для позиционирования реального контента в Android SDK (Kotlin/Java)

Геопространственные привязки — это тип привязки , позволяющий размещать 3D-контент в реальном мире.

Типы геопространственных привязок

Существует три типа геопространственных привязок, каждый из которых по-разному обрабатывает высоту:

  1. Якоря WGS84 :
    Якоря WGS84 позволяют размещать 3D-контент на любой заданной широте, долготе и высоте.

  2. Местные якоря :
    Привязки к местности позволяют размещать контент, используя только широту и долготу, а также высоту относительно местности в этой позиции. Высота определяется относительно земли или пола, как известно VPS .

  3. Анкеры на крыше :
    Привязки на крыше позволяют размещать контент, используя только широту и долготу, а также высоту относительно крыши здания в этом положении. Высота определяется относительно вершины здания, известной как Streetscape Geometry . По умолчанию используется высота местности, если она не размещена на здании.

WGS84 Местность Крыша
Горизонтальное положение Широта, Долгота Широта, Долгота Широта, Долгота
Вертикальное положение Относительно высоты WGS84 Относительно уровня местности, определенного Google Maps Относительно уровня крыши, определенного с помощью Google Maps.
Требуется разрешение на сервере? Нет Да Да

Предварительные условия

Прежде чем продолжить, убедитесь, что вы включили Geospatial API .

Разместите геопространственные привязки

У каждого типа привязки есть специальные API для их создания; дополнительную информацию см. в разделе «Типы геопространственных привязок» .

Создайте якорь на основе хит-теста

Вы также можете создать геопространственную привязку на основе результатов проверки попадания . Используйте Pose из теста попадания и преобразуйте его в GeospatialPose . Используйте его для размещения любого из трех описанных типов якорей.

Получите геопространственную позу из позы AR

Earth.getGeospatialPose() предоставляет дополнительный способ определения широты и долготы путем преобразования позы AR в геопространственную позу.

Получите позу AR из геопространственной позы

Earth.getPose() преобразует заданное Землей горизонтальное положение, высоту и вращение кватерниона относительно системы координат восток-в-юг в AR-позу относительно мировой координаты GL.

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

Каждый метод создания якоря имеет связанные с ним компромиссы, о которых следует помнить:

  • При использовании Streetscape Geometry используйте проверку попадания, чтобы прикрепить контент к зданию.
  • Предпочитайте якоря Terrain или Rooftop якорям WGS84, поскольку они используют значения высоты, определенные Google Maps.

Определить широту и долготу места

Вычислить широту и долготу местоположения можно тремя способами:

  • Используйте Geospatial Creator , чтобы просматривать и дополнять мир трехмерным контентом без необходимости физически отправляться в определенное место. Это позволяет визуально размещать иммерсивный 3D-контент с помощью карт Google в редакторе Unity. Широта, долгота, поворот и высота контента будут рассчитаны автоматически.
  • Используйте Карты Google
  • Используйте Google Планета Земля. Обратите внимание, что получение этих координат с помощью Google Earth, в отличие от Google Maps, даст вам погрешность до нескольких метров.
  • Перейти к физическому местоположению

Используйте Карты Google

Чтобы получить широту и долготу местоположения с помощью Google Maps:

  1. Откройте Карты Google на настольном компьютере.

  2. Перейдите в «Слои» > «Еще» .

  3. Измените тип карты на «Спутник» и снимите флажок «Вид глобуса» в левом нижнем углу экрана.

    Это позволит использовать 2D-перспективу и устранить возможные ошибки, которые могут возникнуть при просмотре в 3D-виде под углом.

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

Используйте Google Планета Земля

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

Чтобы получить широту и долготу местоположения с помощью Google Earth:

  1. Откройте Google Планета Земля на настольном компьютере.

  2. Перейдите в гамбургер-меню и выберите Стиль карты .

  3. Выключите переключатель «3D-здания» .

  4. Когда переключатель «3D-здания» выключен, щелкните значок булавки. чтобы добавить метку в выбранном месте.

  5. Укажите проект, в котором будет храниться метка, и нажмите « Сохранить» .

  6. В поле Название метки введите имя метки.

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

  8. В меню выберите «Экспортировать как файл KML» .

Файл KLM сообщает широту, долготу и высоту метки в теге <coordinates> , разделенные запятыми, следующим образом:

<coordinates>-122.0755182435043,37.41347299422944,7.420342565583832</coordinates>

Не используйте широту и долготу из тегов <LookAt> , которые определяют положение камеры, а не местоположение.

Перейти к физическому местоположению

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

Получить кватернион вращения

GeospatialPose.getEastUpSouthQuaternion() извлекает ориентацию из геопространственной позы и выводит кватернион, который представляет матрицу вращения, преобразующую вектор из цели в систему координат восток-вверх-юг (EUS). X+ указывает на восток, Y+ указывает вверх, а Z+ указывает на юг. Значения записываются в порядке {x, y, z, w} .

Якоря WGS84

Якорь WGS84 — это тип якоря , который позволяет размещать 3D-контент на любой заданной широте, долготе и высоте. Он опирается на позу и ориентацию для размещения в реальном мире. Позиция состоит из широты, долготы и высоты, которые указаны в системе координат WGS84 . Ориентация состоит из вращения кватернионов.

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

Разместите якорь WGS84 в реальном мире.

Определить высоту места

Есть несколько способов определить высоту места для установки якорей:

  • Если привязка физически находится рядом с пользователем, вы можете использовать высоту, аналогичную высоте устройства пользователя.
  • Получив широту и долготу, используйте Elevation API , чтобы получить высоту на основе спецификации EGM96 . Необходимо преобразовать высоту Maps API EGM96 в WGS84 для сравнения с высотой GeospatialPose . См. GeoidEval , который имеет как командную строку, так и интерфейс HTML. API Карт сообщает широту и долготу в соответствии со спецификацией WGS84.
  • Вы можете получить широту, долготу и высоту местоположения из Google Earth . Это даст вам погрешность до нескольких метров. Используйте широту, долготу и высоту из тегов <coordinates> , а не тегов <LookAt> в файле KML.
  • Если существующая якорь находится рядом и вы не находитесь на крутом склоне, вы можете использовать высоту из GeospatialPose камеры, не используя другой источник, например Maps API.

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

Получив кватернион широты, долготы, высоты и вращения, используйте Earth.createAnchor() , чтобы привязать контент к указанным вами географическим координатам.

Ява

if (earth != null && earth.getTrackingState() == TrackingState.TRACKING) {
  Anchor anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw);

  // Attach content to the anchor specified by geodetic location and pose.
}

Котлин

if (earth.trackingState == TrackingState.TRACKING) {
  val anchor =
    earth.createAnchor(
      /* Location values */
      latitude,
      longitude,
      altitude,
      /* Rotational pose values */
      qx,
      qy,
      qz,
      qw
    )

  // Attach content to the anchor specified by geodetic location and pose.
}

Якоря местности

Якорь местности — это тип якоря , который позволяет размещать объекты AR, используя только широту и долготу, используя информацию от VPS для определения точной высоты над землей.

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

Установить режим поиска плоскости

Поиск плоскости не является обязательным и не требует использования якорей. Обратите внимание, что используются только горизонтальные плоскости. Горизонтальные плоскости помогут динамическому выравниванию якорей местности на земле.

Используйте Config.PlaneFindingMode , чтобы выбрать, как ваше приложение будет обнаруживать самолеты.

Создайте привязку Terrain с помощью нового API Async.

Чтобы создать и разместить привязку Terrain, вызовите Earth.resolveAnchorOnTerrainAsync() .

Якорь не будет готов сразу и его необходимо разрешить. Как только проблема будет решена, она будет доступна в ResolveAnchorOnTerrainFuture .

Ява

final ResolveAnchorOnTerrainFuture future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    /* altitudeAboveTerrain= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Котлин

var future =
  earth.resolveAnchorOnTerrainAsync(
    latitude,
    longitude,
    altitudeAboveTerrain,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == TerrainAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

Проверьте состояние будущего

Future будет иметь связанный FutureState .

Состояние Описание
FutureState.PENDING Операция еще предстоит.
FutureState.DONE Операция завершена, результат доступен.
FutureState.CANCELLED Операция отменена.

Проверьте состояние привязки Terrain в результате Future.

Anchor.TerrainAnchorState принадлежит асинхронной операции и является частью конечного результата Future.

Ява

switch (terrainAnchorState) {
  case SUCCESS:
    // A resolving task for this Terrain anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Котлин

when (state) {
  TerrainAnchorState.SUCCESS -> {
    // A resolving task for this Terrain anchor has finished successfully.
  }
  TerrainAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  TerrainAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.TerrainAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  TerrainAnchorState.ERROR_INTERNAL -> {
    // The Terrain anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

Анкеры на крыше

Анкеры для крыши Hero

Якоря на крыше представляют собой разновидность якоря и очень похожи на якоря Terrain, описанные выше. Разница в том, что вы указываете высоту над крышей, а не над местностью.

Создайте якорь на крыше с помощью нового API Async.

Якорь не будет готов сразу и его необходимо разрешить.

Чтобы создать и разместить якорь на крыше, вызовите Earth.resolveAnchorOnRooftopAsync() . Как и в случае с якорями Terrain, вы также получите доступ к FutureState of the Future. Затем вы можете проверить результат Future, чтобы получить доступ к Anchor.RooftopAnchorState .

Ява

final ResolveAnchorOnRooftopFuture future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    /* altitudeAboveRooftop= */ 0.0f,
    qx,
    qy,
    qz,
    qw,
    (anchor, state) -> {
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    });

Котлин

var future =
  earth.resolveAnchorOnRooftopAsync(
    latitude,
    longitude,
    altitudeAboveRooftop,
    qx,
    qy,
    qz,
    qw,
    { anchor, state ->
      if (state == RooftopAnchorState.SUCCESS) {
        // do something with the anchor here
      } else {
        // the anchor failed to resolve
      }
    }
  )

Проверьте состояние будущего

Future будет иметь связанный FutureState , см. таблицу выше.

Проверьте состояние привязки на крыше результата Future.

Anchor.RooftopAnchorState принадлежит асинхронной операции и является частью конечного результата Future.

Ява

switch (rooftopAnchorState) {
  case SUCCESS:
    // A resolving task for this Rooftop anchor has finished successfully.
    break;
  case ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the Geospatial API.
    break;
  case ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API.
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
    break;
  case ERROR_INTERNAL:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    // not reachable
    break;
}

Котлин

when (state) {
  RooftopAnchorState.SUCCESS -> {
    // A resolving task for this Rooftop anchor has finished successfully.
  }
  RooftopAnchorState.ERROR_UNSUPPORTED_LOCATION -> {
    // The requested anchor is in a location that isn't supported by the Geospatial API.
  }
  RooftopAnchorState.ERROR_NOT_AUTHORIZED -> {
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/java/com/google/ar/core/Anchor.RooftopAnchorState#error_not_authorized
    // for troubleshooting steps.
  }
  RooftopAnchorState.ERROR_INTERNAL -> {
    // The Rooftop anchor could not be resolved due to an internal error.
  }
  else -> {
    // Default.
  }
}

Что дальше