Engenheiro de software sênior
Descubra como fixar e manter experiências em 3D no mundo real usando o Unity e o Android XR. Esta sessão aborda o framework de entidades espaciais, as Cloud Anchors e as APIs Geospatial, demonstrando como criar apps que reconhecem o contexto, lembram posicionamentos físicos e sincronizam dados espaciais multiusuário entre sessões.
Vamos analisar a arquitetura por trás das entidades espaciais e entender como ancorar ativos digitais a objetos físicos, superfícies e localizações geográficas. Você vai aprender fluxos de trabalho práticos do Unity para mapear espaços, manter conteúdo em várias sessões e criar experiências de RA/XR compartilhadas e com reconhecimento de local.
TrySaveAnchorAsync e recarregá-los usando GUIDs serializados.Transcrição
Certo.
Olá, pessoal!
Este é o curso "Como arquitetar conteúdo espacial no Android XR com o Unity".
Meu nome é Jennifer Stanton.
Trabalho na Unity como engenheiro de software sênior.
Trabalho na equipe de recursos de XR, especificamente na AR Foundation e nos pacotes relacionados que levam a realidade aumentada e mista ao Unity.
Sou Levana Chen, da equipe de mecanismos de jogos XR do Google.
Nossas equipes se concentraram em fornecer plug-ins e pacotes que oferecem funcionalidade de XR aprimorada e integrações perfeitas com mecanismos de jogo.
Um dos maiores desafios que vocês nos relatam é que oferecer suporte a várias plataformas de XR com a mesma base de código dá muito trabalho.
O AR Foundation é a camada de API de realidade estendida de alto nível do Unity.
Você pode segmentar várias plataformas de XR sem grandes reescritas de código, sem precisar gerenciar várias bases de código, e tem uma API de script para recursos de RA em qualquer plataforma.
Assim, você pode se concentrar em criar seu app, jogo ou experiência, e o Unity cuida dos detalhes da plataforma para você.
Uma maneira de fazer isso é com as extensões do OpenXR.
Elas são um conjunto de APIs abertas e padrão do setor definidas pelo Khronos Group.
O OpenXR também criou entidades espaciais.
É um framework para que o conteúdo digital represente e interaja com o mundo físico.
As entidades espaciais fornecem um modelo unificado para representar elementos do mundo real como objetos digitais.
É um prazer compartilhar com você algumas das informações mais recentes sobre a AR Foundation para que você possa começar sua jornada para criar experiências para XR.
Em seguida, vou falar sobre os recursos do AR Foundation para que seu conteúdo digital possa interagir com o mundo real.
Em seguida, vou falar sobre a configuração do projeto, incluindo pacotes e outras dependências, para que você possa implementar isso nos seus projetos.
Por fim, vou falar sobre alguns recursos exclusivos do Android XR.
Algumas das maneiras como a AR Foundation representa o mundo real digitalmente são os planos.
São superfícies planas no ambiente físico, como pisos, paredes, tetos e até mesas e sofás.
As malhas são estruturas 3D que representam a geometria do mundo físico.
E também temos formas de interagir com o mundo real, os raycasts.
Eles determinam onde um raio se cruza com o conteúdo digital.
Pense nele como um apontador laser, e você recebe informações sobre onde ele está apontando.
Também temos âncoras, que ajudam a estabilizar e realocar um ponto no espaço.
Vou falar mais sobre as âncoras mais adiante nesta apresentação.
Portanto, todos esses quatro são considerados recursos do AR Foundation.
Há também alguns outros recursos que não são mencionados neste slide.
Planos e âncoras, especificamente, são considerados rastreáveis porque estendem a classe ARTrackable, e os gerenciadores deles rastreiam atualizações do ambiente de execução.
Vamos falar sobre planos.
Planes, temos o componente ARPlane, que identifica superfícies planas em tempo real.
Eles têm rótulos semânticos que você pode consultar para saber se o plano é um chão, uma mesa, uma parede etc.
Os planos também têm limites dinâmicos. Assim, conforme o usuário se move pelo mundo real e consegue ver mais superfícies, os limites do plano se expandem, se fundem e se refinam em tempo real.
Também podemos anexar um colisor de malha ao plano para lidar com a física.
Aqui você pode ver um exemplo de detecção de plano.
Esta é a cena de raycast dos exemplos do AR Foundation em execução em um dispositivo Android XR.
Ele detecta polígonos 2D dinâmicos em tempo real.
Para criar um app com essa funcionalidade, siga nosso guia de configuração do projeto ou use um dos nossos exemplos ou modelos.
Em seguida, temos as malhas.
As malhas são um recurso de RA que fornece malhas 3D do ambiente.
Podemos anexar um colisor de malha a essas malhas geradas, o que permite que seu conteúdo digital interaja com objetos do mundo real.
As malhas permitem uma oclusão de objetos convincente.
Assim, um objeto virtual pode parecer estar atrás de um objeto físico.
Se o objeto digital puder se mover no espaço, use a mesma geometria para encontrar um caminho que evite objetos do mundo real.
Em seguida, temos o ray casting.
O ray casting projeta raios virtuais na sua cena 3D para procurar interseções sem que você precise se preocupar com cálculos matemáticos complexos.
O raio projetado pode cruzar vários objetos 3D no ambiente.
É possível configurar o raycast para atingir apenas determinados tipos de conteúdo digital.
Por exemplo, é possível configurá-lo para não atingir planos e apenas cruzar com malhas.
Agora, vamos analisar os pacotes relevantes.
Todos esses pacotes funcionam juntos para se comunicar e criar uma experiência de XR completa.
Como mencionado, o AR Foundation lida com recursos como planos e âncoras.
O plug-in do OpenXR processa APIs nativas em várias plataformas de XR. Portanto, use esse pacote se o dispositivo usar o OpenXR.
O plug-in do OpenXR pode ser pareado com o pacote de entidades espaciais do OpenXR para acessar extensões de entidades espaciais especificamente, e vamos falar mais sobre isso depois.
Se você sabe que vai segmentar especificamente dispositivos Android XR, como headsets XR e óculos XR com fio, o pacote Unity OpenXR Android XR é necessário.
Como tudo isso segue o padrão de plug-in, o impacto no seu código deve ser mínimo.
Nem todos os recursos estão disponíveis em todos os pacotes do AR Foundation.
Por exemplo, se você olhar para este gráfico, a malha não está disponível no pacote de entidades espaciais do Unity OpenXR.
O XR Plug-in Management permite gerenciar quais recursos do OpenXR estão selecionados no seu projeto.
No editor do Unity, acesse "Edit", "Configurações do Projeto" e, na barra lateral esquerda, "XR Plug-in Management".
Aqui você encontra os recursos e grupos de recursos do OpenXR, para selecionar e desmarcar os que quer incluir no build.
Por exemplo, nesta captura de tela, estamos vendo todas as que vêm com o pacote OpenXR do Android XR.
E você pode misturar e combinar essas entidades com as espaciais, por exemplo, se quiser.
Esta é a janela do Gerenciador de Pacotes.
Destaquei alguns dos pacotes que você pode encontrar em uma configuração típica de projeto de XR.
Como você pode ver, temos o AR Foundation, que já foi mencionado.
Também temos o plug-in do OpenXR.
Temos o pacote do Android XR.
Também destaquei algumas de outras plataformas, porque é possível criar um projeto que seja compilado para várias plataformas.
No canto inferior direito, também temos outros pacotes.
Composition Layers, que funcionam com dispositivos OpenXR; Core Utils, muito útil para tudo relacionado a XR; e XR Hands e XR Interaction Toolkit para receber sua entrada, o que é essencial.
Em seguida, temos a validação do projeto.
Isso faz parte do gerenciamento de plug-ins de XR.
A validação do projeto pode detectar recursos duplicados, além de outros problemas que precisam ser corrigidos para que o projeto seja executado.
Mas nesta captura de tela, destaquei os recursos duplicados.
Isso significa que dois dos mesmos recursos, como âncoras, planos e raycasts,
O usuário selecionou incluir duplicatas desses recursos de vários pacotes, e o sistema está apenas solicitando que ele selecione um ou outro.
Isso nos leva às âncoras locais e à persistência.
As âncoras garantem que o conteúdo digital permaneça nos locais desejados no ambiente, independentemente de mudanças no estado de rastreamento da sessão de RA.
As plataformas de RA atualizam automaticamente as posições das âncoras ao longo do tempo para garantir que elas permaneçam em uma posição consistente. As âncoras são a melhor maneira de garantir que o conteúdo permaneça no lugar se você se afastar e depois voltar para perto dela.
E se o usuário fechar o app, reiniciar mais tarde e voltar em uma sessão separada?
As âncoras persistentes permitem salvar âncoras em uma sessão de RA e carregá-las em sessões subsequentes.
Eles sobrevivem aos ciclos de vida do app e às reinicializações do dispositivo.
Aqui está um exemplo de âncoras persistentes no projeto AR Foundation Samples.
A cena de exemplo tem um menu com todas as funcionalidades compatíveis com essa plataforma, como salvar e carregar âncoras.
Isso nos leva ao ciclo de vida das âncoras persistentes.
Primeiro, você cria uma âncora localmente, que não é salva em nenhum lugar, nem mesmo no armazenamento permanente. É apenas uma âncora local.
Depois, você os persistiria no armazenamento.
Depois disso, você pode reiniciar o app e carregá-lo do armazenamento.
Algumas plataformas, incluindo o Android XR, também permitem apagar ou remover a persistência de âncoras.
O provedor de entidades espaciais permite carregar automaticamente todas as âncoras salvas para que você não precise solicitar manualmente cada âncora pelo ID.
Nas configurações do XR Plug-in Management, você pode selecionar a opção "Automatically Load Saved Anchors" no recurso "Spatial Entities: Anchors".
E salvar uma âncora requer apenas algumas linhas de código.
Primeiro, começamos no editor do Unity e verificamos se a cena está pronta adicionando o componente AR Anchor Manager ao objeto de jogo XR Origin.
O gerenciador mantém a cena atualizada com âncoras rastreadas do ambiente de execução.
Agora, vamos ao código.
Para adicionar uma âncora, basta chamar TryAddAnchorAsync e transmitir a pose de onde você quer colocar a âncora.
async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
var result = await manager.TryAddAnchorAsync(pose);
if (result.status.IsError()) {
// handle error
return;
}
var anchor = result.value;
}Em seguida, temos a remoção de âncoras.
void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
var result = manager.TryRemoveAnchor(anchor.trackableId);
if (result.status.IsError()) {
// handle error
return;
}
}
void DestroyAnchorComponent(ARAnchor anchor) {
Destroy(anchor);
}E, da mesma forma, é praticamente uma linha de código.
Chame TryRemoveAnchor e transmita o ID rastreável da âncora.
Quando a âncora foi criada, ela já recebeu um ID rastreável.
E temos TrySaveAnchorAsync.
async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
var result = await manager.TrySaveAnchorAsync(anchor);
if (result.status.IsError()) {
// handle error
return;
}
// Save this value, then return it as an input parameter
SerializableGuid guid = result.value;
}Você transmite uma âncora de RA como entrada.
Essa função retorna um SerializableGuid que identifica a âncora no armazenamento permanente.
Depois, você pode usar o GUID ao carregar a âncora.
E isso nos leva ao carregamento de âncoras.
async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
var result = await manager.TryLoadAnchorAsync(guid);
if (result.status.IsError()) {
// handle error
return;
}
ARAnchor anchor = result.value;
}A função a ser chamada aqui é TryLoadAnchorAsync, e você transmite o GUID serializado de antes.
Ela vai retornar uma âncora de RA como resultado.
É basicamente isso.
Essas funções permitem gerenciar facilmente as âncoras locais e persistentes.
Portanto, o rastreamento de âncoras é uma tarefa bastante cara na maioria das plataformas de RA.
Ao trabalhar com âncoras, considere as seguintes práticas recomendadas: evite criar várias âncoras muito próximas umas das outras, considere se é possível usar uma âncora próxima em vez de criar outra, remova as âncoras quando não estiver mais usando-as e, por fim, se você ativar outro recurso de RA para ajudar a calcular a pose desejada para uma âncora, considere se é possível desativar esse recurso depois que a âncora for criada.
Agora, vou passar para a Levana.
Obrigada, Jennifer.
Agora, vamos falar sobre a contribuição do Google na jornada do Android XR no Unity.
Além dos plug-ins do Unity OpenXR que a Jennifer apresentou, o Google oferece o SDK do Android XR para Unity com recursos adicionais disponíveis na plataforma Android XR.
Esse SDK contém muitos recursos e pacotes. Nesta palestra, vamos focar no pacote de extensão do Android XR para Unity.
Assim, de forma semelhante ao Android XR e às Entidades Espaciais do OpenXR, o pacote de extensão do Android XR para Unity é, na verdade, um provedor do OpenXR.
A arquitetura desse pacote é assim, e eles podem trabalhar em paralelo ou de forma independente.
Portanto, como todos os outros provedores do OpenXR, o pacote do Google foi criado diretamente na interface padrão do OpenXR.
Aqui, mostramos vários recursos em uma comparação com todos os outros provedores.
Assim, você pode decidir quando e por que escolher uma em vez de outra.
Talvez você tenha uma dúvida sobre o marcador de entidade rastreável e espacial mostrado nesta tabela.
Uma observação: para quem já cria apps e experiências no Android XR, oferecemos esses recursos por meio de extensões rastreáveis que só funcionam no Android XR.
Depois, como a Jennifer mencionou, trabalhamos como um grupo aberto do OpenXR e lançamos a extensão de entidades espaciais no lado direito, oferecendo uma experiência consistente e multiplataforma.
No momento, estamos descontinuando a extensão rastreável em favor do framework de entidades espaciais.
Além de ter um desempenho muito melhor, ele também oferece suporte multiplataforma.
Em seguida, vamos analisar as entidades espaciais.
Além do que a Jennifer mencionou sobre planos, ray casting e âncoras, esse recurso também é compatível com provedores de entidades espaciais, como marcadores, que podem detectar e decodificar códigos de barras 2D padrão e rastrear a posição deles no espaço 3D, e a imagem, que reconhece gráficos 2D conhecidos e os rastreia no espaço 3D.
E, em seguida, a caixa delimitadora, que vai identificar o objeto físico, como teclado, laptop ou mouse, e rastrear a caixa delimitadora em uma pose 3D.
No próximo exemplo, vamos configurar o recurso de caixa delimitadora fornecido pelo pacote de extensões do Google.
Essa visualização é praticamente a mesma para todos os recursos do OpenXR.
Então, basta mudar para a plataforma Android XR, ativar o provedor do OpenXR e selecionar o recurso do OpenXR que você quer usar. Por exemplo, o recurso de caixa delimitadora de entidade espacial foi mostrado aqui. Depois, corrija os problemas de validação do projeto.
Ele ajuda a encontrar todas as dependências exigidas por um determinado recurso e, em seguida, resolver os conflitos causados por vários recursos que contribuem para o mesmo subsistema.
Às vezes, você Na maioria das vezes, só precisa escolher um recurso se quiser usar, por exemplo, âncora, plano ou caixa delimitadora aqui.
Por fim, você pode criar a cena de exemplo ou de teste.
Para acessar o objeto rastreável no momento da execução, basta adicionar o componente AR Bounding Box Manager, que é semelhante ao AR Anchor Manager, e usar a interface do AR Foundation para acessá-lo.
Como alternativa, você também pode importar a amostra de entidade espacial fornecida pelo nosso pacote de extensão como um modelo para começar.
Esta é a principal diferença ao usar o recurso AR Foundation no Android XR.
Para entender o ambiente ao redor do usuário, o app geralmente precisa de acesso aos dados sensíveis do ambiente.
E, para proteger o usuário, o Android XR restringe o sistema, ou seja, o acesso aos dados por trás das permissões.
Talvez você já conheça isso, como a chamada de permissão normal do Android, como o acesso à câmera ou à localização, coisas desse tipo.
A prática recomendada aqui é desativar o componente do gerenciador na inicialização, seja no editor, como você pode ver no lado direito, ou no script, como o evento Awake.
void Awake() {
planeManager = GetComponent<ARPlaneManager>();
planeManager.enabled = false;
boundingBoxManager = GetComponent<ARBoundingBoxManager>();
boundingBoxManager.enabled = false;
permissionUtil = GetComponent<AndroidXRPermissionUtil>();
}
void OnEnable() {
StartCoroutine(WaitForPermissions());
}Depois de conceder todas as permissões necessárias, você pode ativar o gerenciador no script, como o auxiliar WaitForPermissions faz aqui.
IEnumerator WaitForPermissions() {
planeManager.enabled = false;
boundingBoxManager.enabled = false;
yield return new WaitUntil(() =>
permissionUtil.AllPermissionGranted());
// Enable after granted permissions and
// restart subsystems.
planeManager.enabled = true;
boundingBoxManager.enabled = true;
// Save permission status.
permissionGranted = true;
}Ao fazer isso, você evita uma falha de inicialização do subsistema causada por permissões insuficientes.
E este é um recurso especial.
Como a Jennifer explicou sobre a âncora usando o AR Foundation, para expandir a capacidade de âncora no Android XR, nosso pacote também oferece um novo recurso chamado "âncoras compartilháveis".
Esse recurso replica o que o recurso de âncora do AR Foundation oferece atualmente e também vem com algumas funcionalidades adicionais, como âncoras geoespaciais.
E, como você pode imaginar, a âncora é a ponte real que conecta o mundo virtual ao físico.
A Jennifer explicou como criar, salvar e carregar esses dados, mas tudo isso aconteceu em um espaço local, como a sala de estar do usuário.
Mas e o resto do mundo?
E como podemos compartilhar isso uns com os outros?
É aí que entra a API Geospatial.
Ele permite criar uma âncora geoespacial com base em um local do mundo real, como sua livraria favorita ou um ponto de encontro em um grande parque.
Assim, a API Geospatial pode fornecer um rastreador de geoposicionamento preciso usando o VPS, também conhecido como sistema de posicionamento virtual, como um GPS, mas usando os dados do Street View para fornecer resultados de rastreamento muito mais precisos.
Alguns de vocês já devem conhecer essa visualização se tiverem experiência com o recurso geoespacial do ARCore.
Para acessar a API Geospatial no Android XR, primeiro precisamos nos conectar ao back-end hospedado na plataforma do Google Cloud.
Como o back-end geoespacial é alimentado pelo serviço do ARCore no Google Cloud, você pode seguir exatamente as mesmas etapas para configurar seu projeto na nuvem do Google Cloud com acesso à API ARCore.
Tudo isso vai permitir o uso do recurso do Google Cloud para Android XR fornecido pelo nosso pacote de extensão.
Depois de ativar a API Geospatial e pegar a chave de API do projeto do Google Cloud, você pode ativar esse recurso e configurar a autenticação no menu de configurações do OpenXR, como mostrado aqui, ou configurar manualmente usando a API de script chamada TrySetAuthenticationAsync.
async Task TrySetAuthentication() {
googleCloudFeature =
OpenXRSettings.Instance
.GetFeature<XRGoogleCloudFeature>();
var result = await googleCloudFeature
.TrySetAuthenticationAsync(
strategy, credential);
if (result.IsSuccess()) {
// Ready to use for geospatial tracker.
} else if (result.IsUnsupported()) {
// Google Cloud feature is not supported
} else if (result.IsKeylessError()) {
// Confirm if keyless has been set up properly.
} else {
// Handling other common OpenXR errors.
}
}No momento, a plataforma Android XR só aceita autenticação por chave de API, mas vamos oferecer suporte a mais credenciais no futuro.
Depois de autenticar, use um gerenciador geoespacial para acessar os recursos geoespaciais.
É altamente recomendável verificar a cobertura do VPS no Google Maps antes da integração.
Por isso, você também precisa ter acesso à rede ao usar o recurso.
O XR Geospatial Manager funciona de maneira semelhante ao componente AR Session fornecido pela AR Foundation.
Por isso, ela vem com uma propriedade de estado estático para indicar o suporte do sistema e o estado de rastreamento do rastreador geoespacial.
Você pode registrar um evento de mudança de estado por um callback como este.
void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
// Handle cloud authentication issues.
} else if (isInitFailed) {
// Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
} else {
// Iterate runtime state change, and handle accordingly.
}
}
private void OnEnable() {
XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
}Quando o estado geoespacial estiver em execução, você poderá usar essa instância do gerenciador para todas as funcionalidades a seguir.
Primeiro, para verificar a disponibilidade do VPS com a localização de GPS fornecida, usamos a API Location do Unity para receber o valor do GPS e, em seguida, verificar a disponibilidade do VPS.
async Task CheckVPSAvailability(CancellationToken token) {
var location = Input.location.lastData;
try {
var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
location.latitude, location.longitude);
token.ThrowIfCancellationRequested();
if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
// Invalid coordinates, try with another location.
} else if (result.status.IsError()) {
// Handle common OpenXR error: result.status.ToOpenXRStatus()
} else if (result.value == XRVPSAvailability.Available) {
// You may use this pose to attach geospatial anchors.
var currentGeospatialPose = new XRGeospatialPose(location);
}
}
}Portanto, essa é basicamente uma substituição se você não quiser verificar o suporte do VPS pelo mapa, mas precisar sair para verificar o status real do GPS.
Em seguida, você também pode converter a pose do Unity em uma pose geoespacial usando TryLocate.
// Geospatial Pose -> Unity Pose
var geospatialPose =
new XRGeospatialPose(Input.location.lastData);
if (geospatialManager.TryLocate(
geospatialPose, out XRPoseResult result)) {
if (result.IsPositionValid ||
result.IsPositionTracked) {
transform.position = result.Pose.position;
}
if (result.IsRotationValid ||
result.IsRotationTracked) {
transform.rotation = result.Pose.rotation;
}
}// Unity Pose -> Geospatial Pose
Pose pose = new Pose(
transform.position, transform.rotation);
if (geospatialManager.TryLocate(
pose, out XRGeospatialPoseResult result)) {
if (result.IsPositionValid ||
result.IsRotationValid) {
// You may use for anchor attachment.
}
}E, usando o resultado da verificação do VPS ou da conversão de pose, você pode anexar a âncora espacial a uma determinada pose geoespacial ou a um tipo de superfície conhecido, como terreno ou telhado.
async void PlaceAnchor(XRGeospatialPose pose) {
try {
Result<ARShareableAnchor> anchorResult;
XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
if (typeToPlace == XRGeospatialSurfaceType.Default) {
anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
} else {
pose.Altitude = 0;
anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
}
if (anchorResult.status.IsSuccess()) {
// ARShareableAnchorManager will track the anchor and update it.
} else {
// Handle OpenXR failures.
}
}
}E, ao juntar tudo isso, você pode criar uma experiência espacial verdadeiramente mágica com o mundo real em destaque.
Por isso, colocamos uma seta para guiar o público até o local desejado no mundo real.
Ok.
O SDK do Android XR não é o único pacote que oferecemos aos desenvolvedores do Unity.
O SDK do Android XR do Google para Unity agora também inclui o framework de interação do Android XR e o pacote de áudio do Android XR.
Estamos muito felizes em expandir o SDK do Android XR com mais suporte a recursos e mais entidades espaciais.
Certo, chegamos ao fim da sessão.
Você pode acompanhar o roteiro da Unity on-line para saber o que vem a seguir.
Não se esqueça de que o Unity 7, a próxima geração do Unity, será lançado no início do ano que vem.
Enquanto isso, você pode testar essas ferramentas e criar um projeto usando o modelo de realidade mista ou dar uma olhada no projeto de amostras do AR Foundation no nosso GitHub.
Para saber mais sobre a entidade espacial e nosso suporte ao pacote do Unity, acesse a página no site para desenvolvedores Android.
E, por fim, agradeço a todos.
Mal podemos esperar para ver o que você vai criar com o AR Foundation e a entidade espacial no Android XR.
async void CreateAnchorAsync(ARAnchorManager manager, Pose pose) {
var result = await manager.TryAddAnchorAsync(pose);
if (result.status.IsError()) {
// handle error
return;
}
var anchor = result.value;
}void RemoveAnchor(ARAnchorManager manager, ARAnchor anchor) {
var result = manager.TryRemoveAnchor(anchor.trackableId);
if (result.status.IsError()) {
// handle error
return;
}
}
void DestroyAnchorComponent(ARAnchor anchor) {
Destroy(anchor);
}async void SaveAnchorAsync(ARAnchorManager manager, ARAnchor anchor) {
var result = await manager.TrySaveAnchorAsync(anchor);
if (result.status.IsError()) {
// handle error
return;
}
// Save this value, then return it as an input parameter
SerializableGuid guid = result.value;
}async void LoadAnchorAsync(ARAnchorManager manager, SerializableGuid guid) {
var result = await manager.TryLoadAnchorAsync(guid);
if (result.status.IsError()) {
// handle error
return;
}
ARAnchor anchor = result.value;
}void Awake() {
planeManager = GetComponent<ARPlaneManager>();
planeManager.enabled = false;
boundingBoxManager = GetComponent<ARBoundingBoxManager>();
boundingBoxManager.enabled = false;
permissionUtil = GetComponent<AndroidXRPermissionUtil>();
}
void OnEnable() {
StartCoroutine(WaitForPermissions());
}IEnumerator WaitForPermissions() {
planeManager.enabled = false;
boundingBoxManager.enabled = false;
yield return new WaitUntil(() =>
permissionUtil.AllPermissionGranted());
// Enable after granted permissions and
// restart subsystems.
planeManager.enabled = true;
boundingBoxManager.enabled = true;
// Save permission status.
permissionGranted = true;
}async Task TrySetAuthentication() {
googleCloudFeature =
OpenXRSettings.Instance
.GetFeature<XRGoogleCloudFeature>();
var result = await googleCloudFeature
.TrySetAuthenticationAsync(
strategy, credential);
if (result.IsSuccess()) {
// Ready to use for geospatial tracker.
} else if (result.IsUnsupported()) {
// Google Cloud feature is not supported
} else if (result.IsKeylessError()) {
// Confirm if keyless has been set up properly.
} else {
// Handling other common OpenXR errors.
}
}void OnGeospatialStateChanged(XRGeospatialStateChangedEventArgs eventArgs) {
bool isInitFailed = eventArgs.CurrState == XRGeospatialState.InitializationFailed;
if (isInitFailed && XRGeospatialManager.InitializationResult.IsCloudAuthError()) {
// Handle cloud authentication issues.
} else if (isInitFailed) {
// Check XRGeospatialManager.InitializationResult for other common OpenXR errors.
} else {
// Iterate runtime state change, and handle accordingly.
}
}
private void OnEnable() {
XRGeospatialManager.OnStateChanged += OnGeospatialStateChanged;
}async Task CheckVPSAvailability(CancellationToken token) {
var location = Input.location.lastData;
try {
var result = await geospatialManager.TryCheckVPSAvailabilityAsync(
location.latitude, location.longitude);
token.ThrowIfCancellationRequested();
if (result.status.nativeStatusCode == (int)XrResultAndroid.GeospatialCoordinateInvalid) {
// Invalid coordinates, try with another location.
} else if (result.status.IsError()) {
// Handle common OpenXR error: result.status.ToOpenXRStatus()
} else if (result.value == XRVPSAvailability.Available) {
// You may use this pose to attach geospatial anchors.
var currentGeospatialPose = new XRGeospatialPose(location);
}
}
}// Geospatial Pose -> Unity Pose
var geospatialPose =
new XRGeospatialPose(Input.location.lastData);
if (geospatialManager.TryLocate(
geospatialPose, out XRPoseResult result)) {
if (result.IsPositionValid ||
result.IsPositionTracked) {
transform.position = result.Pose.position;
}
if (result.IsRotationValid ||
result.IsRotationTracked) {
transform.rotation = result.Pose.rotation;
}
}// Unity Pose -> Geospatial Pose
Pose pose = new Pose(
transform.position, transform.rotation);
if (geospatialManager.TryLocate(
pose, out XRGeospatialPoseResult result)) {
if (result.IsPositionValid ||
result.IsRotationValid) {
// You may use for anchor attachment.
}
}async void PlaceAnchor(XRGeospatialPose pose) {
try {
Result<ARShareableAnchor> anchorResult;
XRGeospatialSurfaceType typeToPlace = /* Choose your target type */;
if (typeToPlace == XRGeospatialSurfaceType.Default) {
anchorResult = geospatialManager.TryAttachGeospatialAnchor(pose);
} else {
pose.Altitude = 0;
anchorResult = await geospatialManager.TryAttachSurfaceAnchorAsync(typeToPlace, pose);
}
if (anchorResult.status.IsSuccess()) {
// ARShareableAnchorManager will track the anchor and update it.
} else {
// Handle OpenXR failures.
}
}
}