Acompanhamento da mão – MRTK3

Visão geral

Os dados conjuntos da articulação manual são uma das únicas partes dos dados de entrada que ainda não foram tratadas nativamente pelo Sistema de Entrada do Unity, eles são tratados pelos nossos subsistemas.

Observação

Se você não estiver familiarizado com os subsistemas do MRTK3 e as diferenças deles em relação aos serviços MRTK 2.x, consulte a documentação de arquitetura de subsistemas do MRTK3 para um aprofundamento em nossa filosofia e design.

Nossos subsistemas ingerem dados de articulação da mão de várias fontes e os agregam em uma API central que funciona entre dispositivos e contextos de simulação. Os subsistemas abaixo são implementações do HandsSubsystem:

  • O OpenXRHandsSubsystem recebe os dados da mão diretamente do plug-in OpenXR.
  • O XRSDKHandsSubsystem recebe os dados da mão da camada de abstração do SDK XR do Unity (que, por sua vez, pode estar fornecendo seus dados do OpenXR ou outra fonte).
  • O SyntheticHandsSubsystem sintetiza articulações da mão falsas com base nas ações de entrada provenientes do sistema (como devicePosition, deviceRotation etc). Esse subsistema fornece as junções que você vê ao usar a simulação de entrada no editor.

Esses subsistemas são consultados por HandsAggregatorSubsystem, que combina todas as fontes dos dados da mão em uma API central.

Importante

Ao consultar diretamente os dados da articulação da mão, sempre prefira consultar do Agregador, não de nenhum subsistema de mão individual. Dessa forma, seu código funcionará para qualquer fonte de dados da mão, incluindo dados simulados.

O agregador e os subsistemas de mãos avaliam lentamente as solicitações de dados da mão. Os dados da mão não serão consultados até que um script "cliente" os solicite. Se o aplicativo solicitar apenas uma articulação individual, os subsistemas de mãos serão avaliados lentamente e só consultarão uma única articulação das APIs subjacentes. Além disso, se um "cliente" solicitar um valor completo de dados conjuntos, as chamadas subsequentes no mesmo quadro reutilizarão os mesmos dados, reduzindo o custo de consultar muitas articulações no mesmo quadro. Em cada novo quadro, o cache será alterado e liberado e as chamadas subsequentes começarão a recarregar o cache.

Como resultado, ao criar o perfil do aplicativo, a primeira consulta conjunta em um quadro pode levar mais tempo do que as consultas subsequentes. Isso ocorre devido ao custo amortizado associado à primeira consulta e ao desempenho relativo dos "acertos de cache" subsequentes.

Características de pinçagem

O Agregador calcula várias medidas relacionadas ao gesto de pinçamento, com base nos dados conjuntos que consulta de cada subsistema de mãos específico. Essas medidas são configuradas na definição do subsistema do Agregador.

Hands Aggregator subsystem configuration

O Limite Aberto de Pinçamento e o Limite Fechado de Pinçamento controlam a distância absoluta entre o polegar e o dedo indicador usada para normalizar o progresso da pinça. Quando a distância for igual ao limite fechado, o progresso da pinça será 1,0 e, quando a distância for igual ao limite aberto, será 0,0. (Esses limites estão atualmente em unidades mundiais, mas em breve serão normalizados para o tamanho da mão do usuário.)

O FOV da Câmera de Aumento de Mão controla o quão perto do centro da exibição do usuário a mão deve ser considerada válida para pinçagem. A Tolerância da Mão para o Lado Oposto controla a tolerância para medir a rotação das mãos do usuário. Ela determina quando a mão do usuário está voltada para o lado oposto.

Exemplos

// Get a reference to the aggregator.
var aggregator = XRSubsystemHelpers.GetFirstRunningSubsystem<HandsAggregatorSubsystem>();
// Wait until an aggregator is available.
IEnumerator EnableWhenSubsystemAvailable()
{
    yield return new WaitUntil(() => XRSubsystemHelpers.GetFirstRunningSubsystem<HandsAggregatorSubsystem>() != null);
    GoAhead();
}
// Get a single joint (Index tip, on left hand, for example)
bool jointIsValid = aggregator.TryGetJoint(TrackedHandJoint.IndexTip, XRNode.LeftHand, out HandJointPose jointPose);
// Get an entire hand's worth of joints from the left hand.
bool allJointsAreValid = aggregator.TryGetEntireHand(XRNode.LeftHand, out IReadOnlyList<HandJointPose> joints)
// Check whether the user's left hand is facing away (commonly used to check "aim" intent)
// This is adjustable with the HandFacingAwayTolerance option in the Aggregator configuration.
// "handIsValid" represents whether there was valid hand data in the first place!
bool handIsValid = aggregator.TryGetPalmFacingAway(XRNode.LeftHand, out bool isLeftPalmFacingAway)
// Query pinch characteristics from the left hand.
// pinchAmount is [0,1], normalized to the open/closed thresholds specified in the Aggregator configuration.
// "isReadyToPinch" is adjusted with the HandRaiseCameraFOV and HandFacingAwayTolerance settings in the configuration.
bool handIsValid = aggregator.TryGetPinchProgress(XRNode.LeftHand, out bool isReadyToPinch, out bool isPinching, out float pinchAmount)