Usar âncoras geoespaciais para posicionar conteúdo real no SDK do Android (Kotlin/Java)

As âncoras geoespaciais são um tipo de âncora que permite colocar conteúdo 3D no mundo real.

Tipos de âncoras geoespaciais

Existem três tipos de âncoras geoespaciais, que processam a altitude de maneira diferente:

  1. Âncoras WGS84:
    As âncoras WGS84 permitem colocar conteúdo 3D em qualquer latitude, longitude e altitude.

  2. Âncoras de terreno:
    As âncoras de terreno permitem posicionar conteúdo usando somente latitude e longitude com uma altura relativa ao terreno naquela posição. A altitude é determinada em relação ao solo ou ao andar, como conhecido pelo VPS.

  3. Fixos de telhado:
    As âncoras no telhado permitem que você posicione conteúdo usando somente latitude e longitude com uma altura relativa ao telhado de um edifício naquela posição. A altitude é determinada em relação ao topo de um edifício, como conhecido da Streetscape Geometry. Por padrão, a altitude do terreno será definida quando não estiver em uma construção.

WGS84 Relevo Telhado
Posição horizontal Latitude, longitude Latitude, longitude Latitude, longitude
Posição vertical Relativa à altitude do WGS84 Relativa ao nível do terreno determinado pelo Google Maps Relativa ao nível do telhado determinado pelo Google Maps
Precisa ser resolvido pelo servidor? Não Sim Sim

Pré-requisitos

Ative a API Geospatial antes de continuar.

Posicionar âncoras geoespaciais

Cada tipo de âncora possui APIs dedicadas para criá-las; consulte Tipos de âncoras geoespaciais para mais informações.

Criar uma âncora a partir de um teste de hit

Você também pode criar uma âncora geoespacial com um resultado de teste de hit. Use a pose do teste de hit e converta-a em um GeospatialPose. Use-o para posicionar qualquer um dos três tipos de âncora descritos.

Fazer uma pose geoespacial com uma pose de RA

O Earth.getGeospatialPose() oferece outra maneira de determinar a latitude e a longitude convertendo uma pose de RA em uma geoespacial.

Fazer uma pose de RA de uma pose geoespacial

Earth.getPose() converte uma posição horizontal, altitude e rotação de quatérnio especificadas pela Terra em relação a um frame de coordenadas leste-sul em uma pose de AR em relação à coordenada mundial GL.

Escolha o método ideal para seu caso de uso

Cada método de criação de uma âncora apresenta compensações associadas que devem ser lembradas:

  • Ao usar o Streetscape Geometry, usar um teste de hit para anexar conteúdo a um edifício.
  • Prefira âncoras de terreno ou telhado em vez de âncoras WGS84 porque elas usam valores de altitude determinados pelo Google Maps.

Determinar a latitude e a longitude de um local

Há três maneiras de calcular a latitude e a longitude de um local:

  • Use o Geospatial Creator para ver e ampliar o mundo com conteúdo em 3D sem precisar ir fisicamente a um local. Isso permite posicionar visualmente o conteúdo imersivo em 3D usando o Google Maps no Unity Editor. A latitude, longitude, rotação e altitude do conteúdo serão calculadas automaticamente.
  • Usar o Google Maps
  • Usar o Google Earth. Observe que a obtenção dessas coordenadas usando o Google Earth, e não o Google Maps, lhe dará uma margem de erro de até vários metros.
  • Ir para o local físico

Usar o Google Maps

Para conferir a latitude e a longitude de um local usando o Google Maps, faça o seguinte:

  1. Acesse o Google Maps no seu computador desktop.

  2. Navegue até Camadas > Mais.

  3. Mude a opção Tipo de mapa para Satélite e desmarque a caixa de seleção Visualização de globo no canto inferior esquerdo da tela.

    Isso forçará uma perspectiva 2D e eliminará possíveis erros que podem vir de uma visualização 3D inclinada.

  4. No mapa, clique com o botão direito do mouse no local e selecione a longitude/latitude para copiá-lo para a área de transferência.

Usar o Google Earth

Para calcular a latitude e a longitude de um local no Google Earth, clique em um local na interface e leia os dados dos detalhes do marcador.

Para conferir a latitude e a longitude de um local usando o Google Earth:

  1. Acesse o Google Earth em um computador desktop.

  2. Navegue até o menu de navegação e selecione Estilo do mapa.

  3. Desative a opção Construções em 3D.

  4. Depois que a opção Construções em 3D for desativada, clique no ícone de fixação para adicionar um marcador de local no local selecionado.

  5. Especifique um projeto que contenha seu marcador de local e clique em Salvar.

  6. No campo Título do marcador de local, insira um nome para ele.

  7. Clique na seta para voltar no painel do projeto e selecione o menu Mais ações.

  8. Escolha Exportar como arquivo KML no menu.

O arquivo KLM informa a latitude, longitude e altitude de um marcador na tag <coordinates> separados por vírgulas, da seguinte forma:

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

Não use a latitude e a longitude das tags <LookAt>, que especificam a posição da câmera, não o local.

Ir para o local físico

Você pode calcular a altitude de um local indo até lá fisicamente e fazendo uma observação local.

Acessar o quatérnio de rotação

GeospatialPose.getEastUpSouthQuaternion() extrai a orientação de uma pose geoespacial e gera um quatérnio que representa a matriz de rotação que transforma um vetor do alvo para o sistema de coordenadas leste-para-sul (EUS). X+ pontos para leste, Y+ pontos para cima e Z+ pontos para sul. Os valores são gravados na ordem {x, y, z, w}.

Âncoras WGS84

Uma âncora WGS84 é um tipo de âncora que permite posicionar conteúdo 3D em qualquer latitude, longitude e altitude. Ele depende de uma postura e de uma orientação para ser colocado no mundo real. A posição consiste em latitude, longitude e altitude, que são especificadas no sistema de coordenadas WGS84. A orientação consiste em uma rotação de quatérnio.

A altitude é informada em metros acima do elipsoide de referência WGS84, de modo que o nível do solo não seja zero. Seu aplicativo é responsável por fornecer essas coordenadas para cada âncora criada.

Coloque uma âncora WGS84 no mundo real

Determinar a altitude de um local

Existem algumas maneiras de determinar a altitude de um local para colocar âncoras:

  • Se o local da âncora estiver fisicamente perto do usuário, você poderá usar uma altitude semelhante à do dispositivo do usuário.
  • Quando você tiver a latitude e a longitude, use a API Elevation para conferir uma elevação com base na especificação EGM96. Você precisa converter a elevação EGM96 da API Maps em WGS84 para comparação com a altitude de GeospatialPose. Veja o GeoidEval, que tem uma interface de linha de comando e uma HTML. A API do Google Maps informa a latitude e longitude de acordo com a especificação WGS84 pronta para uso.
  • Você pode obter a latitude, longitude e altitude de um local no Google Earth. Isso lhe dará uma margem de erro de até vários metros. Use a latitude, a longitude e a altitude das tags <coordinates>, não das tags <LookAt>, no arquivo KML.
  • Se um ponto âncora estiver próximo e você não estiver em uma subida íngreme, poderá usar a altitude do GeospatialPose da câmera sem outra fonte, como a API Maps.

Criar a âncora

Depois de ter a latitude, a longitude, a altitude e o quatérnio da rotação, use Earth.createAnchor(). para fixar o conteúdo nas coordenadas geográficas especificadas.

Java

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.
}

Kotlin

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.
}

Âncoras para terrenos

Uma âncora de terreno é um tipo de âncora que permite posicionar objetos de RA usando somente latitude e longitude, aproveitando informações do VPS para encontrar a altitude precisa acima do solo.

Em vez de inserir a altitude desejada, você fornece a altitude acima do terreno. Quando esse valor é zero, a âncora fica nivelada com o terreno.

Definir o modo de descoberta de avião

A localização de planos é opcional e não é obrigatória para o uso de âncoras. Somente planos horizontais são usados. Planos horizontais ajudam no alinhamento dinâmico das âncoras de terreno no solo.

Use Config.PlaneFindingMode para selecionar como o app detecta planos.

Criar uma âncora de terreno usando a nova API assíncrona

Para criar e posicionar uma âncora de terreno, chame Earth.resolveAnchorOnTerrainAsync().

O anúncio âncora não estará pronto imediatamente e precisa ser resolvido. Após a resolução, ela vai estar disponível no ResolveAnchorOnTerrainFuture.

Java

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
      }
    });

Kotlin

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
      }
    }
  )

Confira o estado do futuro

O Future terá um FutureState associado.

Estado Descrição
FutureState.PENDING A operação ainda está pendente.
FutureState.DONE A operação foi concluída e o resultado está disponível.
FutureState.CANCELLED A operação foi cancelada.

Verificar o estado da âncora do terreno do resultado Futuro

O Anchor.TerrainAnchorState pertence à operação assíncrona e faz parte do resultado final do Future.

Java

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;
}

Kotlin

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.
  }
}

Âncoras para telhados

Imagem principal das âncoras no telhado

As âncoras de telhado são um tipo de âncora e são muito semelhantes às Âncoras de terreno acima. A diferença é que você fornecerá a altitude acima do telhado em vez de fornecer a altitude acima do terreno.

Criar uma âncora Rooftop usando a nova API Async

O anúncio âncora não estará pronto imediatamente e precisa ser resolvido.

Para criar e posicionar uma âncora no telhado, chame Earth.resolveAnchorOnRooftopAsync(). Assim como nas âncoras de terreno, você também acessa o FutureState do futuro. Em seguida, marque o resultado futuro para acessar o Anchor.RooftopAnchorState.

Java

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
      }
    });

Kotlin

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
      }
    }
  )

Confira o estado do futuro

A classe Future terá um FutureState associado. Consulte a tabela acima.

Verificar o estado da âncora no telhado do resultado Future

O Anchor.RooftopAnchorState pertence à operação assíncrona e faz parte do resultado final do Future.

Java

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;
}

Kotlin

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.
  }
}

A seguir