Seguimiento de manos: MRTK3

Información general

Los datos procedentes de las articulaciones de las manos son uno de los únicos tipos de datos de entrada que el sistema de entrada de Unity aún no controla de forma nativa, así que nuestros subsistemas son quienes se encargan de controlarlos.

Nota

Si no está familiarizado con los subsistemas MRTK3 y sus diferencias con respecto a los servicios de MRTK 2.x, consulte la documentación de arquitectura de subsistemas de MRTK3 para profundizar en nuestra filosofía y diseño.

Nuestros subsistemas ingieren datos de las articulaciones de manos procedentes de varios orígenes y los agregan a una API central, que funciona en distintos dispositivos y contextos de simulación. Los subsistemas siguientes son implementaciones de HandsSubsystem:

  • El subsistema OpenXRHandsSubsystem recibe datos procedentes de las manos directamente del complemento OpenXR.
  • El subsistema XRSDKHandsSubsystem recibe datos procedentes de manos de la capa de abstracción del SDK de XR de Unity (que, a su vez, puede obtener sus datos de OpenXR o de algún otro origen).
  • El subsistema SyntheticHandsSubsystem sintetiza articulaciones de manos falsas basadas en las acciones de entrada procedentes del sistema (como pueden ser devicePosition, deviceRotation, etc.). Este es el subsistema que proporciona las articulaciones que se ven al usar la simulación de entrada en el editor.

Estos subsistemas se consultan mediante el subsistema HandsAggregatorSubsystem, que combina todos los orígenes de datos procedentes de manos en una API central.

Importante

Siempre que se consulte directamente en búsqueda de datos de las articulaciones de manos, siempre es preferible consultar desde el agregador y no desde los subsistemas individuales. De este modo, el código funcionará para cualquier origen de datos procedentes de manos, incluidos los datos simulados.

El agregador y los subsistemas de manos evalúan las solicitudes entrantes de datos procedentes de manos de forma diferida. Es decir, los datos procedentes de manos no se consultarán hasta que un script "cliente" lo solicite. Si la aplicación solo solicita datos de una articulación determinada, los subsistemas de manos evaluarán de forma diferida y se limitarán a consultar una sola articulación en las API subyacentes. Además, si un "cliente" solicita los datos de todas las articulaciones de una mano, todas las llamadas posteriores dentro del mismo marco reutilizarán los mismos datos. Esto reducirá el costo de consultar varias articulaciones dentro del mismo marco. En cada nuevo marco, la memoria caché se llenará y se vaciará, y las llamadas posteriores comenzarán a llenarla de nuevo.

Como resultado, al generar perfiles de la aplicación, podría notar que la primera consulta de datos de articulaciones de un marco tarda más tiempo que las consultas posteriores. Esto se debe al costo amortizado asociado con la primera consulta, así como al rendimiento relativo de los siguientes "aciertos de caché".

Características del gesto de reducir

El agregador calcula varias medidas con respecto al gesto de reducir en función de los datos de las articulaciones que se consultan en cada subsistema de manos específico. Estas medidas se configuran en la configuración del subsistema de agregador.

Hands Aggregator subsystem configuration

El umbral de inicio del gesto de reducir y el umbral de finalización del gesto de reducir controlan la distancia absoluta del mundo entre el pulgar y el dedo que se use para normalizar el progreso del gesto. Cuando la distancia sea equivalente al umbral de inicio, el valor del progreso de la reducción será de 1.0. A su vez, cuando la distancia equivalga al umbral de finalización, este será de 0.0. (Actualmente, estos umbrales se encuentran en unidades de Unity, pero pronto se normalizarán con el tamaño de la mano del usuario).

El campo de visión de la cámara de elevación de la mano controla cómo de cerca debe estar la mano, en relación con el centro de la vista del usuario, para considerarse que puede realizar el gesto de reducir. La tolerancia de la mano volteada controla la tolerancia con la que se mide la rotación de la mano del usuario, para determinar el momento en el que el usuario está orientando su mano hacia fuera.

Ejemplos

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