Handverfolgung — MRTK2

Handverfolgungsprofil

Das Handverfolgungsprofil wird unter dem Eingabesystemprofil gefunden. Es enthält Einstellungen zum Anpassen der Handdarstellung.

Handverfolgungsprofil

Gemeinsame Präfabs

Gemeinsame Prefabs werden mithilfe einfacher Prefabs visualisiert. Die Palmen - und Indexfingergelenke sind von besonderer Bedeutung und haben einen eigenen Prefab, während alle anderen Gelenke denselben Prefab teilen.

Standardmäßig sind die Handgelenkvorhänge 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 haben können!

Standarddarstellung der Handgelenke Gemeinsame Bezeichnungen
Gelenke der Hand Eingabehandgelenke

Handgitter prefab

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

Eingabehandgitter

Die Handgitteranzeige kann eine spürbare Leistungsauswirkung haben, aus diesem Grund kann sie vollständig deaktiviert werden, indem Sie die Option " Handgittervisualisierung aktivieren" deaktivieren.

Einstellungen für die Handvisualisierung

Die Handgitter- und Handgelenkvisualisierungen können über die Einstellung " Handgittervisualisierungsmodi " und " Hand-Gelenkvisualisierungsmodi" bzw. "Handgelenkvisualisierungsmodi " deaktiviert oder aktiviert werden. Diese Einstellungen sind anwendungsspezifisch, d. h. es ist möglich, einige Features während des Editors zu aktivieren (um Gelenke mit In-Editor-Simulation anzuzeigen, z. B. dass die gleichen Features deaktiviert sind, wenn sie auf Geräten bereitgestellt werden (in Playerbuilds).

Beachten Sie, dass im Allgemeinen empfohlen wird, die Handgelenkvisualisierung im Editor aktiviert zu haben (sodass die In-Editor-Simulation zeigt, wo sich die Handgelenke befinden), und sowohl die Handgelenkvisualisierung als auch die Handgittervisualisierung im Spieler deaktiviert zu haben (weil sie einen Leistungstreffer verursachen).

Skripterstellung

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

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

Verfügbare Gelenke sind in der TrackedHandJoint Aufzählung aufgeführt.

Hinweis

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

Zugreifen auf einen bestimmten Handcontroller

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

Abfragen gemeinsamer Posen vom Controller

Die TryGetJoint Funktion gibt zurück false , wenn der angeforderte Joint aus irgendeinem Grund nicht verfügbar ist. In diesem Fall wird die resultierende Pose sein MixedRealityPose.ZeroIdentity.

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

Gemeinsame Transformation von Handvisualisierer

Gemeinsame Objekte können vom Controller-Visualizer 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 aus dem ersten verfügbaren Handgerät an, das derzeit nachverfolgt wird.

Polling joint pose from HandJointUtils

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

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

Gemeinsame Transformation vom Handgelenkdienst

IMixedRealityHandJointService hält einen beständigen Satz von GameObjects für die Nachverfolgung von Gelenken.

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

Handverfolgungsereignisse

Das Eingabesystem stellt auch Ereignisse bereit, wenn das Abrufen von Daten aus Controllern direkt wünschenswert ist.

Gemeinsame Veranstaltungen

IMixedRealityHandJointHandler behandelt 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))
            {
                // ...
            }
        }
    }
}

Gitterereignisse

IMixedRealityHandMeshHandler behandelt Änderungen des gestikulierten 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 systemeigen

Es gibt derzeit ein bekanntes Problem mit Master-Builds mit dem .NET-Back-End. In .NET Native IInspectable können Zeiger nicht von systemeigenem zu verwaltetem Code mithilfe Marshal.GetObjectForIUnknownvon verwaltetem Code gemarschiert werden. MRTK verwendet dies, um die SpatialCoordinateSystem Hand- und Augendaten von der Plattform zu erhalten.

Wir haben DLL-Quelle als Problemumgehung für dieses Problem im systemeigenen Mixed Reality Toolkit-Repo bereitgestellt. Befolgen Sie die Anweisungen in der README dort, und kopieren Sie die resultierenden Binärdateien in einen Plugins-Ordner in Ihren Unity-Ressourcen. Danach löst das in MRTK bereitgestellte WindowsMixedRealityUtilities-Skript die Problemumgehung für Sie.

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

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

Und seine 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;
    }
}