Tracciamento della mano - MRTK3

Panoramica

I dati delle mani articolati sono uno degli unici dati di input che non sono ancora gestiti in modo nativo dal sistema di input unity, gestiti dai sottosistemi.

Nota

Se non si ha familiarità con i sottosistemi MRTK3 e le differenze rispetto ai servizi MRTK 2.x, vedere la documentazione sull'architettura dei sottosistemi MRTK3 per un approfondimento sulla filosofia e sulla progettazione.

I sottosistemi inseriscono dati comuni mano da diverse origini e li aggregano in un'API centrale che funziona tra dispositivi e contesti di simulazione. I sottosistemi seguenti sono implementazioni di HandsSubsystem:

  • OpenXRHandsSubsystem riceve i dati della mano direttamente dal plug-in OpenXR.
  • XRSDKHandsSubsystem riceve i dati a mano dal livello di astrazione di XR SDK di Unity( che a sua volta può essere l'origine dei dati da OpenXR o da un'altra origine).
  • SyntheticHandsSubsystem sintetizza le articolazioni della mano fittizie in base alle azioni di input provenienti dal sistema (ad esempio devicePosition, deviceRotatione così via). Questo sottosistema fornisce le articolazioni visualizzate quando si usa la simulazione di input nell'editor.

Questi sottosistemi vengono sottoposti a query da HandsAggregatorSubsystem, che combina tutte le origini dei dati di mano in un'API centrale.

Importante

Ogni volta che si esegue una query direttamente per i dati comuni a mano, eseguire sempre query da Aggregator, non da nessuno dei singoli sottosistemi della mano. In questo modo, il codice funzionerà per qualsiasi origine di dati della mano, inclusi i dati simulati.

L'aggregatore e i sottosistemi mani valutano in modo differinte le richieste di dati della mano in ingresso. I dati della mano non verranno sottoposti a query finché non viene richiesto uno script "client". Se l'app richiede solo un singolo giunto, i sottosistemi delle mani valuteranno in modo differito e eseguiranno query su un singolo giunto dalle API sottostanti. Inoltre, se un "client" richiede una mano completa di dati comuni, le chiamate successive all'interno dello stesso frame riutilizzeranno gli stessi dati, riducendo il costo di esecuzione di query su molte articolazioni all'interno dello stesso frame. In ogni nuovo frame, la cache verrà deviata e scaricata e le chiamate successive inizieranno a riempire la cache.

Di conseguenza, quando si esegue la profilatura dell'applicazione, è possibile che la prima query congiunta in un frame richieda più tempo rispetto alle query successive. Ciò è dovuto al costo ammortizzato associato alla prima query e alle prestazioni relative dei successivi riscontri nella cache.

Caratteristiche di avvicinamento delle dita

Aggregator calcola diverse misurazioni relative al movimento di avvicinamento delle dita in base ai dati comuni su cui esegue una query da ogni sottosistema delle mani specifico. Queste misurazioni vengono configurate nella configurazione del sottosistema Aggregator.

Hands Aggregator subsystem configuration

La soglia di avvicinamento delle dita e la soglia chiusa di avvicinamento delle dita controllano la distanza assoluta tra il pollice e l'indicatore di avanzamento delle dita usato per normalizzare lo stato di avanzamento delle dita. Quando la distanza è uguale alla soglia chiusa, lo stato di avvicinamento delle dita sarà 1,0 e quando la distanza è uguale alla soglia di apertura, sarà 0,0. Queste soglie sono attualmente in unità mondiali, ma presto verranno normalizzate in base alle dimensioni della mano dell'utente.

Hand Raise Fotocamera FOV controlla la vicinanza al centro della visualizzazione dell'utente che la mano deve essere considerata valida per l'avvicinamento delle dita. Hand Facing Away Tolerance controlla la tolleranza per misurare la rotazione della mano dell'utente; determina quando la mano dell'utente è rivolta verso l'esterno.

Esempi

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