Используйте геопространственные привязки для позиционирования реального контента в Unity

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

AREarthManager.Convert(GeospatialPose) преобразует заданное Землей горизонтальное положение, высоту и вращение кватерниона относительно системы координат восток-вверх-юг в 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.EunRotation извлекает ориентацию из геопространственной позы и выводит кватернион, который представляет матрицу вращения, преобразующую вектор из цели в систему координат восток-север (EUN). X+ указывает на восток, Y+ указывает вверх вдали от гравитации, а Z+ указывает на север.

Якоря 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.

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

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

if (earthTrackingState == TrackingState.Tracking)
{
  var anchor =
      AnchorManager.AddAnchor(
          latitude,
          longitude,
          altitude,
          quaternion);
  var anchoredAsset = Instantiate(GeospatialAssetPrefab, anchor.transform);
}

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

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

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

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

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

Обратите внимание, что на привязки ландшафта влияют параметры Horizontal и Horizontal | Vertical

Используйте раскрывающееся меню «Режим обнаружения» , чтобы установить режим обнаружения:

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

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

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

public GameObject TerrainAnchorPrefab;

public void Update()
{
    ResolveAnchorOnTerrainPromise terrainPromise =
        AnchorManager.ResolveAnchorOnTerrainAsync(
            latitude, longitude, altitudeAboveTerrain, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckTerrainPromise(terrainPromise));
}

private IEnumerator CheckTerrainPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.TerrainAnchorState == TerrainAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(TerrainAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

Проверьте состояние обещания

Промис будет иметь связанный с ним PromiseState .

Состояние Описание
Pending Операция еще предстоит.
Done Операция завершена, результат доступен.
Cancelled Операция отменена.

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

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

switch (result.TerrainAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case TerrainAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case TerrainAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case TerrainAnchorState.ErrorInternal:
        // The Terrain anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

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

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

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

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

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

Чтобы создать и разместить привязку на крыше, вызовите ARAnchorManagerExtensions.resolveAnchorOnRooftopAsync() . Как и в случае с якорями Terrain, вы также получите доступ к PromiseState обещания. Затем вы можете проверить результат Promise, чтобы получить доступ к RooftopAnchorState .

public GameObject RooftopAnchorPrefab;

public void Update()
{
    ResolveAnchorOnRooftopPromise rooftopPromise =
        AnchorManager.ResolveAnchorOnRooftopAsync(
            latitude, longitude, altitudeAboveRooftop, eunRotation);

    // The anchor will need to be resolved.
    StartCoroutine(CheckRooftopPromise(rooftopPromise));
}

private IEnumerator CheckRooftopPromise(ResolveAnchorOnTerrainPromise promise)
{
    yield return promise;

    var result = promise.Result;
    if (result.RooftopAnchorState == RooftopAnchorState.Success &&
        result.Anchor != null)
    {
        // resolving anchor succeeded
        GameObject anchorGO = Instantiate(RooftopAnchorPrefab,
            result.Anchor.gameObject.transform);
        anchorGO.transform.parent = result.Anchor.gameObject.transform;
    }
    else
    {
       // resolving anchor failed
    }

    yield break;
}

Проверьте состояние обещания

Промис будет иметь связанный с ним PromiseState , см. таблицу выше.

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

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

switch (result.RooftopAnchorState)
{
    case TerrainAnchorState.Success:
        // Anchor has successfully resolved
        break;
    case RooftopAnchorState.ErrorUnsupportedLocation:
        // The requested anchor is in a location that isn't supported by the Geospatial API.
        break;
    case RooftopAnchorState.ErrorNotAuthorized:
        // An error occurred while authorizing your app with the ARCore API. See
        // https://developers.google.com/ar/reference/unity-arf/namespace/Google/XR/ARCoreExtensions#terrainanchorstate_errornotauthorized
        // for troubleshooting steps.
        break;
    case RooftopAnchorState.ErrorInternal:
        // The Rooftop anchor could not be resolved due to an internal error.
        break;
    default:
        break;
}

Что дальше