Śledzenie rąk — MRTK2

Profil śledzenia rąk

Profil śledzenia ręcznego znajduje się w obszarze Profilu systemu wejściowego. Zawiera ustawienia dostosowywania reprezentacji ręcznej.

Profil śledzenia ręcznego

Wspólne prefabryki

Wspólne prefabryki są wizualizowane przy użyciu prostych prefab. Stawy Palm i Index Finger mają szczególne znaczenie i mają własne prefab, podczas gdy wszystkie inne stawy mają ten sam prefab.

Domyślnie wspólne prefabryki ręczne są prostymi geometrycznymi elementami pierwotnymi. W razie potrzeby można je zamienić. Jeśli w ogóle nie określono prefabryk, zamiast tego zostaną utworzone puste obiekty GameObjects .

Ostrzeżenie

Unikaj używania złożonych skryptów lub kosztownego renderowania we wspólnych prefabrykach, ponieważ wspólne obiekty są przekształcane na każdej ramce i mogą mieć znaczny koszt wydajności.

Domyślna reprezentacja wspólnej ręki Wspólne etykiety
Przegubowe stawy ręczne Stawów wejściowych

Prefab siatki ręcznej

Siatka ręczna jest używana, jeśli w pełni zdefiniowane dane siatki są dostarczane przez urządzenie do śledzenia rąk. Siatka renderowana w prefabrykcie jest zastępowana danymi z urządzenia, więc wystarczy fikcyjna siatka, taka jak sześcian. Materiał prefab jest używany do siatki ręcznej.

Siatka rąk wejściowych

Wyświetlanie siatki ręcznej może mieć zauważalny wpływ na wydajność. Z tego powodu można go całkowicie wyłączyć, usuwając zaznaczenie opcji Włącz wizualizację siatki ręcznej .

Ustawienia wizualizacji ręcznej

Siatka ręczna i wspólne wizualizacje ręczne można wyłączyć lub włączyć odpowiednio za pomocą ustawień Tryby wizualizacji siatki ręcznej i Tryby wspólnej wizualizacji. Te ustawienia są specyficzne dla trybu aplikacji, co oznacza, że można włączyć niektóre funkcje w edytorze (aby zobaczyć połączenia z symulacją w edytorze, na przykład), gdy te same funkcje są wyłączone po wdrożeniu na urządzeniu (w kompilacjach odtwarzacza).

Należy pamiętać, że zwykle zaleca się włączenie wspólnej wizualizacji ręcznej w edytorze (tak aby symulacja w edytorze pokazywała, gdzie znajdują się stawy ręczne), oraz aby wizualizacja obu rąk i siatki ręcznej była wyłączona w odtwarzaczu (ponieważ powodują one trafienie wydajności).

Skrypty

W systemie wejściowym można zażądać położenia i obrotu dla każdej jednostki stawu ręcznego MixedRealityPosejako .

Alternatywnie system umożliwia dostęp do obiektów GameObject, które podążają za stawami. Może to być przydatne, jeśli inny obiekt GameObject powinien śledzić wspólne połączenie w sposób ciągły.

Dostępne stawy są wymienione w wyliczenie TrackedHandJoint .

Uwaga

Wspólny obiekt jest niszczony po utracie śledzenia rąk! Upewnij się, że wszystkie skrypty korzystające ze wspólnego obiektu obsługują sprawę null bezpiecznie, aby uniknąć błędów.

Uzyskiwanie dostępu do danego kontrolera ręki

Określony kontroler ręczny jest często dostępny, np. podczas obsługi zdarzeń wejściowych. W takim przypadku wspólne dane mogą być żądane bezpośrednio z urządzenia przy użyciu interfejsu IMixedRealityHand .

Wspólne pozowanie sondowania od kontrolera

Funkcja TryGetJoint zwraca false wartość , jeśli żądany wspólny jest niedostępny z jakiegoś powodu. W takim przypadku wynikowa pozycja będzie mieć MixedRealityPose.ZeroIdentitywartość .

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

Wspólne przekształcanie z wizualizatora ręcznego

Żądania wspólnych obiektów można zażądać z wizualizatora kontrolera.

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

Uproszczony wspólny dostęp do danych

Jeśli nie podano określonego kontrolera, klasy narzędzi są zapewniane w celu wygodnego dostępu do danych wspólnych rąk. Te funkcje żądają wspólnych danych z obecnie śledzonego urządzenia z pierwszej dostępnej ręki.

Wspólne pozowanie sondowania z HandJointUtils

HandJointUtils jest klasą statyczną, która wysyła zapytanie do pierwszego aktywnego urządzenia.

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

Wspólna transformacja z usługi stawów ręcznych

IMixedRealityHandJointService utrzymuje trwały zestaw obiektów GameObject do śledzenia stawów.

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

Zdarzenia śledzenia rąk

System wejściowy udostępnia również zdarzenia, jeśli sondowanie danych z kontrolerów bezpośrednio nie jest pożądane.

Wspólne wydarzenia

IMixedRealityHandJointHandler obsługuje aktualizacje wspólnych pozycji.

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

Zdarzenia siatki

IMixedRealityHandMeshHandler obsługuje zmiany siatki przegubowej ręki.

Należy pamiętać, że siatki ręczne nie są domyślnie włączone.

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

            // ...
        }
    }
}

Znane problemy

Architektura .NET Native

Obecnie istnieje znany problem z kompilacjami głównymi korzystającymi z zaplecza platformy .NET. W .NET Native IInspectable wskaźniki nie mogą być marshalowane z natywnego do zarządzanego kodu przy użyciu polecenia Marshal.GetObjectForIUnknown. Zestaw narzędzi MRTK używa tego elementu do uzyskiwania SpatialCoordinateSystem w celu odbierania danych z platformy.

Źródło biblioteki DLL zostało udostępnione jako obejście tego problemu w natywnym repozytorium Mixed Reality Toolkit. Postępuj zgodnie z instrukcjami zawartymi w pliku README i skopiuj wynikowe pliki binarne do folderu Plugins w zasobach aparatu Unity. Następnie skrypt WindowsMixedRealityUtilities podany w zestawie narzędzi MRTK rozwiąże obejście problemu.

Jeśli chcesz utworzyć własną bibliotekę DLL lub uwzględnić to obejście w istniejącym, podstawowym obejściem jest:

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

Jego użycie w kodzie aparatu Unity w języku C#:

[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;
    }
}