Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Rastreamento de mãos OpenXR

Introdução

Nota

Esta página foca especificamente no conjunto de recursos expostos através do OpenXR. Partes da funcionalidade apresentada aqui também se aplicam ao WebXR e podem ser fornecidas por outras interfaces XR.

Ao discutir o rastreamento de mãos (hand tracking), é importante saber que existem divergências de opinião sobre onde as linhas são traçadas. O resultado prático disso é que existem diferenças de implementação entre os diferentes runtimes do OpenXR. Você pode se encontrar em uma situação em que o hardware escolhido não suporta uma peça do quebra-cabeça ou faz as coisas de forma sutilmente diferente das outras plataformas, exigindo trabalho extra.

Dito isso, melhorias recentes na especificação do OpenXR estão fechando essas lacunas e, à medida que as plataformas implementam essas melhorias, estamos nos aproximando de um futuro onde teremos portabilidade total entre as plataformas ou, pelo menos, uma maneira clara de detectar as capacidades de uma plataforma.

Quando olhamos para os primórdios da VR, o foco das principais plataformas estava na entrada baseada em controladores rastreados. Aqui, estamos rastreando um dispositivo físico que também possui botões para entradas adicionais. A partir dos dados de rastreamento, podemos inferir a localização das mãos do jogador, mas nenhuma informação adicional é conhecida; tradicionalmente, cabia ao jogo implementar um mecanismo para exibir a mão do jogador e animar os dedos com base em entradas adicionais do controlador, seja por botões sendo pressionados ou por sensores de proximidade. Muitas vezes, os dedos também são posicionados com base no contexto, no que o usuário está segurando e em qual ação o usuário está realizando.

Mais recentemente, o rastreamento óptico de mãos tornou-se uma solução popular, onde câmeras rastreiam as mãos do usuário e dados de rastreamento completos para as posições das mãos e dos dedos ficam disponíveis. Muitos fornecedores viram isso como algo completamente separado do rastreamento de controladores e introduziram APIs independentes para acessar os dados de posição e orientação das mãos e dos dedos. Ao lidar com a entrada, cabia ao desenvolvedor do jogo implementar um mecanismo de detecção de gestos.

Essa divisão também existe no OpenXR, onde o rastreamento de controladores é gerenciado principalmente pelo sistema de mapa de ações (action map), enquanto o rastreamento óptico de mãos é gerenciado principalmente pela extensão da API de rastreamento de mãos.

No entanto, o mundo não é tão preto no branco e estamos vendo uma série de cenários onde cruzamos a linha:

  • Dispositivos que se encaixam em ambas as categorias, como luvas rastreadas e controladores como o controlador do Index que também realizam o rastreamento de dedos.

  • Runtimes de XR que implementam rastreamento de mãos inferido a partir de dados do controlador como um meio de resolver o posicionamento adequado dos dedos para múltiplos controladores.

  • Aplicativos de XR que desejam alternar perfeitamente entre o rastreamento de controlador e de mãos, oferecendo a mesma experiência de usuário independentemente da abordagem utilizada.

O OpenXR está respondendo a essa demanda introduzindo novas extensões que nos permitem consultar as capacidades do runtime/hardware de XR ou que adicionam funcionalidades adicionais através dessa divisão. O problema que atualmente permanece é que existem lacunas na adoção dessas extensões, fazendo com que algumas plataformas não relatem suas capacidades em sua totalidade. Sendo assim, você pode precisar testar os recursos disponíveis em Hardwares específicos e ajustar sua abordagem de acordo.

Projeto de demonstração

As informações apresentadas nesta página foram usadas para criar um projeto de demonstração que pode ser encontrado aqui.

A API de Rastreamento de Mãos

Como mencionado em nossa introdução, a API de rastreamento de mãos é usada principalmente com o rastreamento óptico de mãos e, em muitas plataformas, funciona apenas quando o usuário não está segurando um controlador. Algumas plataformas suportam o rastreamento de mãos inferido pelo controlador, o que significa que você obterá dados de rastreamento de mãos mesmo se o usuário estiver segurando um controlador. Isso inclui o SteamVR, Meta Quest (atualmente apenas nativo, mas o suporte ao Meta Link provavelmente está chegando) e, esperamos que em breve, outros também.

A implementação de rastreamento de mãos no Godot foi padronizada em torno do Godot Humanoid Skeleton e funciona tanto no OpenXR quanto no WebXR. As instruções abaixo funcionarão, portanto, em ambos os ambientes.

Para usar a API de rastreamento de mãos com o OpenXR, você primeiro precisa ativá-la. Isso pode ser feito nas configurações do projeto:

../../_images/xr_enable_handtracking.webp

Para alguns dispositivos XR independentes (standalone), você também precisa configurar a extensão de rastreamento de mãos nas configurações de exportação, por exemplo, para o Meta Quest:

../../_images/openxr_enable_hand_tracking_meta.webp

Agora você precisa adicionar 3 componentes na sua cena para cada mão:

  • Um nó rastreado para posicionar a mão.

  • Uma malha de mão (hand mesh) devidamente texturizada (skinned) com esqueleto.

  • Um modificador de esqueleto que aplica os dados de rastreamento de dedos ao esqueleto.

../../_images/openxr_hand_tracking_nodes.webp

Nó de rastreamento de mãos

O sistema de rastreamento de mãos usa rastreadores de mão (hand trackers) separados para rastrear a posição das mãos do jogador dentro do nosso espaço de rastreamento.

Esta informação foi separada para os seguintes casos de uso:

  • Tracking happens in the local space of the XROrigin3D node. This node must be a child of the XROrigin3D node in order to be correctly placed.

  • Este nó pode ser usado como um alvo de IK (Cinemática Inversa) quando uma malha de corpo superior com braços é usada em vez de malhas de mão separadas.

  • O posicionamento real das mãos pode estar vagamente vinculado ao rastreamento em cenários como interfaces de criação de avatar, espelhos falsos ou situações semelhantes que resultem na malha da mão e no rastreamento de dedos sendo localizados em outro lugar.

Vamos nos concentrar apenas no primeiro caso de uso.

Para isso, você precisa adicionar um nó XRNode3D ao seu nó XROrigin3D.

  • Neste nó, o tracker deve ser definido como /user/hand_tracker/left ou /user/hand_tracker/right para a mão esquerda ou direita, respectivamente.

  • A pose deve permanecer definida como default, nenhuma outra opção funcionará aqui.

  • A caixa de seleção Show When Tracked esconderá automaticamente este nó se nenhum dado de rastreamento estiver disponível, ou tornará este nó visível se os dados de rastreamento estiverem disponíveis.

Malha de mão preparada (Rigged)

Para exibir nossa mão, precisamos de uma malha de mão que esteja devidamente estruturada (rigged) e texturizada (skinned). Para isso, o Godot usa a estrutura de ossos da mão conforme definida para o Godot Humanoid, mas opcionalmente suportando um osso de ponta (tip bone) extra para cada dedo.

O demo de rastreamento de mãos OpenXR contém arquivos glTF de exemplo de mãos devidamente preparadas.

Estaremos usando esses aqui e os adicionaremos como filhos ao nosso nó XRNode3D. Também precisamos habilitar os filhos editáveis (editable children) para ganhar acesso ao nosso nó Skeleton3D.

O modificador de esqueleto de mão

Finalmente, precisamos adicionar um nó XRHandModifier3D como filho do nosso nó Skeleton3D. Este nó obterá os dados de rastreamento de dedos do OpenXR e os aplicará ao modelo de mão.

Você precisa definir a propriedade Hand Tracker para /user/hand_tracker/left ou /user/hand_tracker/right dependendo se estamos aplicando os dados de rastreamento da mão esquerda ou direita, respectivamente.

Você também pode definir o modo Bone Update neste nó.

  • Full aplica os dados de rastreamento de mão totalmente. Isso significa que o posicionamento do esqueleto refletirá potencialmente o tamanho da mão real do usuário. Isso pode levar a um efeito de enrugamento (scrunching) se as malhas não forem pesadas (weighted) adequadamente para explicar isso. Certifique-se de testar seu jogo com jogadores de todos os tamanhos quando o rastreamento óptico de mãos for usado!

  • Rotation Only aplicará apenas rotação aos ossos das mãos e manterá o comprimento dos ossos como está. Neste modo, o tamanho da malha da mão não muda.

Com isso adicionado, quando executarmos o projeto, deveremos ver a mão exibida corretamente se o rastreamento de mãos for suportado.

A fonte de dados de rastreamento de mãos

Esta é uma extensão do OpenXR que fornece informações sobre a origem dos dados de rastreamento de mãos. Neste momento, apenas alguns runtimes a implementam, mas se estiver disponível, o Godot a ativará.

Se esta extensão não for suportada e, portanto, um valor desconhecido (unknown) for retornado, você pode fazer as seguintes suposições:

  • Se você estiver usando o SteamVR (incluindo o Steam Link), apenas o rastreamento de mãos baseado em controlador é suportado.

  • Para qualquer outro runtime, se o rastreamento de mãos for suportado, apenas o rastreamento óptico de mãos é suportado (Nota: o Meta Link atualmente se enquadra nesta categoria).

  • Em todos os outros casos, nenhum tipo de rastreamento de mãos é suportado.

Você pode acessar essa informação através de código:

var hand_tracker : XRHandTracker = XRServer.get_tracker('/user/hand_tracker/left')
if hand_tracker:
    if hand_tracker.has_tracking_data:
        if hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNKNOWN:
            print("Hand tracking source unknown")
        elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_UNOBSTRUCTED:
            print("Hand tracking source is optical hand tracking")
        elif hand_tracker.hand_tracking_source == XRHandTracker.HAND_TRACKING_SOURCE_CONTROLLER:
            print("Hand tracking data is inferred from controller data")
        else:
            print("Unknown hand tracking source ", hand_tracker.hand_tracking_source)
    else:
        print("Hand is currently not being tracked")
else:
    print("No hand tracker registered")

Este exemplo registra o estado da mão esquerda.

Se, neste exemplo, nenhum rastreador de mão for retornado por get_tracker, isso significa que a API de rastreamento de mãos não é suportada de forma alguma no runtime de XR.

If there is a tracker but has_tracking_data is false, the user's hand is currently not being tracked. This is likely caused by one of the following reasons:

  • A mão do jogador não está visível por nenhuma das câmeras de rastreamento do headset

  • O jogador está usando um controlador no momento e o headset suporta apenas o rastreamento óptico de mãos

  • O controlador está desligado e apenas o rastreamento de mãos por controlador é suportado.

Manipulando a entrada do usuário

A reação às ações realizadas pelo usuário é gerenciada através do O mapa de ações XR se controladores forem usados. No mapa de ações, você pode mapear várias entradas, como o gatilho (trigger) ou o joystick do controlador, para uma ação. Isso pode então guiar a lógica do seu jogo.

Quando o rastreamento de mãos é usado, originalmente não tínhamos tais entradas; as entradas são guiadas por gestos feitos pelo usuário, como fazer um punho para agarrar ou pinçar o polegar e o dedo indicador juntos para selecionar algo. Cabia ao desenvolvedor do jogo implementar isso.

Reconhecendo que há uma demanda crescente por aplicativos que possam alternar perfeitamente entre o rastreamento por controlador e por mãos, e a necessidade de alguma forma de capacidade básica de entrada, uma série de extensões foram adicionadas à especificação que fornecem algum reconhecimento básico de gestos e podem ser usadas com o mapa de ações.

O perfil de interação de mãos

A extensão de perfil de interação de mão é uma nova extensão principal que suporta gestos de pinça (pinch), agarrar (grasp) e apontar/cutucar (poke), além de poses relacionadas. Ainda há suporte limitado para esta extensão, mas ela deve se tornar disponível em mais runtimes em um futuro próximo.

../../_images/openxr_hand_interaction_profile.webp

O gesto de pinça é acionado ao juntar as pontas do polegar e do indicador. Isso é frequentemente usado como um gesto de seleção para sistemas de menu, semelhante a usar seu controlador para apontar para um objeto e pressionar o gatilho para selecionar, sendo frequentemente mapeado dessa forma.

  • A pinch pose é uma pose posicionada no meio entre a ponta do polegar e a ponta do dedo indicador e orientada de forma que um lançamento de raio (ray cast) possa ser usado para identificar um alvo.

  • A entrada flutuante (float) pinch é um valor entre 0.0 (a ponta do polegar e do indicador estão afastadas) e 1.0 (a ponta do polegar e do indicador estão se tocando).

  • A entrada pinch ready é verdadeira (true) quando as pontas dos dedos estão se tocando (ou próximas disso).

O gesto de agarrar é acionado ao fazer um punho e é frequentemente usado para pegar itens, semelhante a acionar a entrada de aperto (squeeze) nos controladores.

  • A entrada flutuante (float) grasp é um valor entre 0.0 (mão aberta) e 1.0 (punho fechado).

  • A entrada grasp ready é verdadeira quando o usuário fecha o punho.

O gesto de cutucar é acionado ao estender o dedo indicador; este é um pouco uma exceção, pois a pose na ponta do seu dedo indicador é frequentemente usada para cutucar um objeto interagível. A poke pose é uma pose posicionada na ponta do dedo indicador.

Finalmente, a entrada aim activate (ready) é definida como uma entrada que é 1.0/verdadeira quando o dedo indicador está estendido e apontando para um alvo que pode ser ativado. Como os runtimes interpretam isso não está claro.

Com essa configuração, os rastreadores normais de left_hand e right_hand são usados e você pode, portanto, alternar perfeitamente entre a entrada de controlador e a entrada de rastreamento de mãos.

Nota

Você precisa ativar a extensão de perfil de interação de mão nas configurações de projeto do OpenXR.

Perfil de interação de mão da Microsoft

A extensão de perfil de interação de mão da Microsoft foi introduzida pela Microsoft e imita vagamente o perfil de controlador simples (simple controller profile). A Meta também adicionou suporte para esta extensão, mas apenas em seu cliente OpenXR nativo; atualmente ela não está disponível através do Meta Link.

../../_images/openxr_msft_hand_interaction_profile.webp

O suporte a pinça é exposto através da entrada select, cujo valor é 0.0 quando a ponta do polegar e do indicador estão afastadas e 1.0 quando estão juntas.

Note que neste perfil a aim pose é redefinida como uma pose entre o polegar e o dedo indicador, orientada para que um lançamento de raio possa ser usado para identificar um alvo.

O suporte a agarrar é exposto através da entrada squeeze, cujo valor é 0.0 quando a mão está aberta e 1.0 quando um punho é feito.

Com essa configuração, os rastreadores normais de left_hand e right_hand são usados e você pode, portanto, alternar perfeitamente entre a entrada de controlador e a entrada de rastreamento de mãos.

Perfil de interação de mãos HTC

A extensão de perfil de interação de mão da HTC foi introduzida pela HTC e é definida de forma semelhante à extensão da Microsoft. Ela é suportada apenas pela HTC para os headsets Focus 3 e Elite XR.

../../_images/openxr_htc_hand_interaction_profile.webp

Consulte o perfil de interação de mão da Microsoft para o suporte a gestos.

A diferença marcante é que esta extensão introduz dois novos rastreadores, /user/hand_htc/left e /user/hand_htc/right. Isso significa que uma lógica extra precisa ser implementada para alternar entre os rastreadores padrão e os rastreadores específicos da HTC quando o usuário solta ou pega seu controlador.

Perfil de controlador simples

O perfil de controlador simples é um perfil principal padrão definido como um perfil de fallback quando um controlador é usado e para o qual não existe nenhum perfil específico.

Há uma série de runtimes de OpenXR que imitam controladores através do perfil de controlador simples quando o rastreamento de mãos é usado.

Infelizmente, não há uma maneira segura de determinar se um controlador desconhecido está sendo usado ou se o rastreamento de mãos está emulando um controlador através deste perfil.

../../_images/openxr_simple_controller_hand.webp

Os runtimes de XR são livres para definir como o perfil de controlador simples opera, portanto, também não há certeza de como este perfil é mapeado para gestos.

O mapeamento mais comum parece ser que select click é verdadeiro quando a ponta do polegar e do indicador estão se tocando enquanto a palma da mão do usuário está voltada para o lado oposto ao usuário. menu click será verdadeiro quando a ponta do polegar e do indicador estão se tocando enquanto a palma da mão do usuário está voltada para o próprio usuário.

Com essa configuração, os rastreadores normais de left_hand e right_hand são usados e você pode, portanto, alternar perfeitamente entre a entrada de controlador e a entrada de rastreamento de mãos.

Nota

Como alguns desses perfis de interação têm sobreposição, é importante saber que você pode adicionar cada perfil ao seu mapa de ações e o runtime de XR escolherá o perfil mais adequado.

Por exemplo, um Meta Quest suporta tanto o perfil de interação de mão da Microsoft quanto o perfil de controlador simples. Se ambos forem especificados, o perfil de interação de mão da Microsoft terá precedência e será usado.

A expectativa é que, uma vez que a Meta suporte a extensão principal do perfil de interação de mão, esse perfil terá precedência sobre os perfis da Microsoft e de controlador simples.

Entrada baseada em gestos

Se a plataforma não suportar nenhum perfil de interação quando o rastreamento de mãos for usado, ou se você estiver construindo um aplicativo onde precisa de um suporte a gestos mais complicado, você precisará construir seu próprio sistema de reconhecimento de gestos.

Você pode obter os dados completos de rastreamento de mãos através do recurso XRHandTracker para cada mão. Você pode obter o rastreador de mão chamando XRServer.get_tracker e usando /user/hand_tracker/left ou /user/hand_tracker/left como o rastreador. Este recurso fornece acesso a todas as informações de articulação (joints) para a mão fornecida.

Detalhar um algoritmo completo de reconhecimento de gestos vai além do escopo deste manual, no entanto, há uma série de projetos comunitários que você pode consultar: