Freigeben über


Handverfolgung — MRTK2

Handverfolgungsprofil

Das Profil "Hand tracking" befindet sich unter dem Profil "Eingabesystem". Sie enthält Einstellungen zum Anpassen der Handdarstellung.

Handverfolgungsprofil

Gemeinsame Prefabs

Gemeinsame Prefabs werden mithilfe einfacher Prefabs visualisiert. Die Handflächen - und Indexfingergelenke sind von besonderer Bedeutung und haben ein eigenes Prefab, während alle anderen Gelenke das gleiche Prefab teilen.

Standardmäßig sind die Handgelenk-Prefabs einfache geometrische Grundtypen. Diese können bei Bedarf ersetzt werden. Wenn überhaupt kein Prefab angegeben ist, werden stattdessen leere GameObjects erstellt.

Warnung

Vermeiden Sie die Verwendung komplexer Skripts oder teurer Renderings in gemeinsamen Prefabs, da gemeinsame Objekte auf jedem Frame transformiert werden und erhebliche Leistungskosten verursachen können!

Standardhandgelenkdarstellung Gemeinsame Etiketten
Gelenke der Hand Eingabehandgelenke

Hand mesh prefab

Das Handgitter wird verwendet, wenn vollständig definierte Gitterdaten vom Handverfolgungsgerät bereitgestellt werden. Das im Prefab renderbare Gitter wird durch Daten vom Gerät ersetzt, sodass ein Dummygitter wie ein Würfel ausreichend ist. Das Material des Prefabs wird für das Handgitter verwendet.

Eingabehandgitter

Die Hand mesh-Anzeige kann eine spürbare Auswirkung auf die Leistung haben. Aus diesem Grund kann sie vollständig deaktiviert werden, indem Sie die Option "Visualisierung von Handgitternetzen aktivieren" deaktivieren.

Handvisualisierungseinstellungen

Die Handgitter- und Handgelenkvisualisierungen können über die Einstellung Hand Mesh Visualisierungsmodi bzw . Handgelenkvisualisierungsmodi deaktiviert oder aktiviert werden. Diese Einstellungen sind anwendungsmodusspezifisch, d. h. es ist möglich, einige Features im Editor zu aktivieren (z. B. um Gelenke mit in-Editor-Simulation zu sehen), während die gleichen Features bei der Bereitstellung auf dem Gerät deaktiviert sind (in Playerbuilds).

Beachten Sie, dass es im Allgemeinen empfohlen wird, die Handgelenkvisualisierung im Editor zu aktivieren (damit die Im Editor-Simulation zeigt, wo sich die Handgelenke befinden), und sowohl die Visualisierung der Handgelenke als auch die Visualisierung der Handgitter im Spieler deaktiviert zu lassen (da sie einen Leistungstreffer verursachen).

Skripterstellung

Position und Drehung können vom Eingabesystem für jedes einzelne Handgelenk als MixedRealityPoseangefordert werden.

Alternativ ermöglicht das System den Zugriff auf GameObjects , die den Gelenken folgen. Dies kann nützlich sein, wenn ein anderes GameObject ein Gelenk kontinuierlich nachverfolgen soll.

Verfügbare Gelenke sind in der TrackedHandJoint Enumeration aufgeführt.

Hinweis

Gemeinsame Objekte werden zerstört, wenn die Handverfolgung verloren geht! Stellen Sie sicher, dass alle Skripts, die das gemeinsame Objekt verwenden, den null Fall ordnungsgemäß behandeln, um Fehler zu vermeiden!

Zugreifen auf einen bestimmten Handcontroller

Ein bestimmter Handcontroller ist häufig verfügbar, z. B. bei der Behandlung von Eingabeereignissen. In diesem Fall können die gemeinsamen Daten über die -Schnittstelle direkt vom Gerät IMixedRealityHand angefordert werden.

Abrufen der gemeinsamen Pose vom Controller

Die TryGetJoint Funktion gibt zurück false , wenn das angeforderte Gelenk aus irgendeinem Grund nicht verfügbar ist. In diesem Fall ist MixedRealityPose.ZeroIdentitydie resultierende Pose .

public void OnSourceDetected(SourceStateEventData eventData)
{
  var hand = eventData.Controller as IMixedRealityHand;
  if (hand != null)
  {
    if (hand.TryGetJoint(TrackedHandJoint.IndexTip, out MixedRealityPose jointPose)
    {
      // ...
    }
  }
}

Gelenktransformation aus Handschnellansicht

Gemeinsame Objekte können über die Controllerschnellansicht angefordert werden.

public void OnSourceDetected(SourceStateEventData eventData)
{
  var handVisualizer = eventData.Controller.Visualizer as IMixedRealityHandVisualizer;
  if (handVisualizer != null)
  {
    if (handVisualizer.TryGetJointTransform(TrackedHandJoint.IndexTip, out Transform jointTransform)
    {
      // ...
    }
  }
}

Vereinfachter gemeinsamer Datenzugriff

Wenn kein bestimmter Controller angegeben wird, werden Hilfsklassen für den bequemen Zugriff auf Handgelenkdaten bereitgestellt. Diese Funktionen fordern gemeinsame Daten vom ersten verfügbaren Handgerät an, das derzeit nachverfolgt wird.

Abfragen der gemeinsamen Pose von HandJointUtils

HandJointUtils ist eine statische Klasse, die das erste aktive Gerät abfragt.

if (HandJointUtils.TryGetJointPose(TrackedHandJoint.IndexTip, Handedness.Right, out MixedRealityPose pose))
{
    // ...
}

Gelenktransformation vom Handgelenkdienst

IMixedRealityHandJointService behält einen persistenten Satz von GameObjects zum Nachverfolgen von Gelenken bei.

var handJointService = CoreServices.GetInputSystemDataProvider<IMixedRealityHandJointService>();
if (handJointService != null)
{
    Transform jointTransform = handJointService.RequestJointTransform(TrackedHandJoint.IndexTip, Handedness.Right);
    // ...
}

Handnachverfolgungsereignisse

Das Eingabesystem stellt auch Ereignisse bereit, wenn das direkte Abrufen von Daten von Controllern nicht erwünscht ist.

Gemeinsame Veranstaltungen

IMixedRealityHandJointHandler verarbeitet Aktualisierungen von gemeinsamen Positionen.

public class MyHandJointEventHandler : IMixedRealityHandJointHandler
{
    public Handedness myHandedness;

    void IMixedRealityHandJointHandler.OnHandJointsUpdated(InputEventData<IDictionary<TrackedHandJoint, MixedRealityPose>> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            if (eventData.InputData.TryGetValue(TrackedHandJoint.IndexTip, out MixedRealityPose pose))
            {
                // ...
            }
        }
    }
}

Mesh-Ereignisse

IMixedRealityHandMeshHandler behandelt Änderungen des artikulierten Handgitters.

Beachten Sie, dass Handgitter standardmäßig nicht aktiviert sind.

public class MyHandMeshEventHandler : IMixedRealityHandMeshHandler
{
    public Handedness myHandedness;
    public Mesh myMesh;

    public void OnHandMeshUpdated(InputEventData<HandMeshInfo> eventData)
    {
        if (eventData.Handedness == myHandedness)
        {
            myMesh.vertices = eventData.InputData.vertices;
            myMesh.normals = eventData.InputData.normals;
            myMesh.triangles = eventData.InputData.triangles;

            if (eventData.InputData.uvs != null && eventData.InputData.uvs.Length > 0)
            {
                myMesh.uv = eventData.InputData.uvs;
            }

            // ...
        }
    }
}

Bekannte Probleme

.NET Native

Es gibt derzeit ein bekanntes Problem bei Masterbuilds, die das .NET-Back-End verwenden. In .NET Native IInspectable können Zeiger nicht mithilfe Marshal.GetObjectForIUnknownvon nativem in verwalteten Code gemarshallt werden. MRTK verwendet diese, um die SpatialCoordinateSystem zu erhalten, um Hand- und Augendaten von der Plattform zu empfangen.

Wir haben eine DLL-Quelle als Problemumgehung für dieses Problem im nativen Mixed Reality Toolkit-Repository bereitgestellt. Befolgen Sie die Anweisungen in der Infodatei, und kopieren Sie die resultierenden Binärdateien in einen Plug-In-Ordner in Ihren Unity-Ressourcen. Danach löst das im MRTK bereitgestellte Skript WindowsMixedRealityUtilities die Problemumgehung für Sie auf.

Wenn Sie Eine eigene DLL erstellen oder diese Problemumgehung in eine vorhandene einschließen möchten, ist der Kern der Problemumgehung:

extern "C" __declspec(dllexport) void __stdcall MarshalIInspectable(IUnknown* nativePtr, IUnknown** inspectable)
{
    *inspectable = nativePtr;
}

Und die Verwendung in Ihrem C#-Unity-Code:

[DllImport("DotNetNativeWorkaround.dll", EntryPoint = "MarshalIInspectable")]
private static extern void GetSpatialCoordinateSystem(IntPtr nativePtr, out SpatialCoordinateSystem coordinateSystem);

private static SpatialCoordinateSystem GetSpatialCoordinateSystem(IntPtr nativePtr)
{
    try
    {
        GetSpatialCoordinateSystem(nativePtr, out SpatialCoordinateSystem coordinateSystem);
        return coordinateSystem;
    }
    catch
    {
        UnityEngine.Debug.LogError("Call to the DotNetNativeWorkaround plug-in failed. The plug-in is required for correct behavior when using .NET Native compilation");
        return Marshal.GetObjectForIUnknown(nativePtr) as SpatialCoordinateSystem;
    }
}