Отслеживание рук

Профиль отслеживания вручную

Профиль отслеживания вручную находится в системном профиле входной системы. Он содержит параметры для настройки представления руки.

Hand Tracking Profile

Совместное Prefabs

Совместное использование Prefabs с помощью простого Prefabs. Соединения Palm и пальца имеют особую важность и имеют собственные prefab, тогда как все остальные соединения совместно используют один и тот же prefab.

По умолчанию стыки Prefabs являются простыми геометрическими примитивами. При необходимости их можно заменить. Если не указано ни одного prefab, вместо него создаются пустые объекты gameobject .

Предупреждение

Старайтесь не использовать сложные сценарии или дорогостоящую отрисовку в совместных Prefabs, так как совместное использование объектов преобразуются во все кадры и может иметь значительные затраты!

Представление соединения вручную по умолчанию Совместные метки
Articulated hand joints Input Hand joints

Сетка prefab

Сетка "рука" используется, если полностью определенные данные сетки предоставлены устройством отслеживания вручную. Сетка, отображаемая в prefab, заменяется данными с устройства, поэтому вполне достаточно фиктивной сетки, такой как куб. Материал prefab используется для сетки "рука".

Input Hand Mesh

Отображение сетки "рука" может оказать заметное влияние на производительность. по этой причине ее можно полностью отключить, отменив параметр " включить визуализацию сетки ".

Параметры визуализации вручную

Можно отключить или включить визуализацию в сетке и режиме отображения с помощью параметров режима визуализации сетки , а также использовать режимы визуализации , соответственно. Эти параметры зависят от режима приложения. Это означает, что можно включить некоторые функции в редакторе (чтобы увидеть соединения с имитацией в редакторе, например), одновременно выключив те же функции при развертывании на устройстве (в сборках проигрывателя).

Обратите внимание, что в редакторе обычно рекомендуется включить совместную визуализацию (так что в имитации в редакторе будет показано, где находятся соединения с рукой) и как одноранговая визуализация, так и визуализация сетки руки отключены в проигрывателе (так как они вызывают снижение производительности).

Написание сценариев

В системе ввода можно запросить расположение и поворот для каждого отдельного соединения MixedRealityPose .

Кроме того, система предоставляет доступ к объекты gameobject , которые следуют за соединениями. Это может быть полезно, если другой GameObject должен постоянно относиться к совместному взаимозаписи.

Доступные соединения перечислены в TrackedHandJoint перечислении.

Примечание

Совместный объект уничтожается при потере отслеживания. Убедитесь, что все скрипты, использующие совместный объект, корректно обрабатывали null случай, чтобы избежать ошибок.

Доступ к данному контроллеру

Часто доступен отдельный контроллер, например при обработке входных событий. В этом случае совместное использование данных может быть запрошено непосредственно с устройства с помощью IMixedRealityHand интерфейса.

Опрос соединения от контроллера

TryGetJointФункция возвращает значение, false если запрошенное соединение недоступно по какой-либо причине. В этом случае итоговый объект будет иметь значение MixedRealityPose.ZeroIdentity .

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

Совместное преобразование из визуализатора руки

В визуализаторе контроллераможно запросить совместное соединение объектов.

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

Упрощенный совместный доступ к данным

Если конкретный контроллер не указан, то для удобного доступа к данным с помощью служебных программ предоставляются вспомогательные классы. Эти функции запрашивают совместное данные от первого доступного устройства, отслеживающего текущее устройство.

Опрос соединения a от Ханджоинтутилс

HandJointUtils — Это статический класс, запрашивающий первое активное устройство.

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

Совместное преобразование из службы совместных соединений

IMixedRealityHandJointService сохраняет постоянный набор объекты gameobject для отслеживания соединений.

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

События отслеживания

Входная система также предоставляет события, если не желательно выполнять опрос данных непосредственно из контроллеров.

Совместные события

IMixedRealityHandJointHandler обрабатывает обновления совместных позиций.

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

События сетки

IMixedRealityHandMeshHandler обрабатывает изменения в сетке с назначением руки.

Обратите внимание, что сетки "рука" не включены по умолчанию.

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

            // ...
        }
    }
}

Известные проблемы

.NET Native

В настоящее время существует известная ошибка с основными сборками, использующими серверную часть .NET. в .NET Native IInspectable нельзя маршалировать указатели из машинного кода в управляемый с помощью Marshal.GetObjectForIUnknown . МРТК использует этот метод для получения SpatialCoordinateSystem данных, чтобы получать данные о руки и глаз с платформы.

мы предоставили источник DLL в качестве обходного решения для этой проблемы в собственном репозитории набор средств смешанной реальности. Следуйте инструкциям в файле сведений и скопируйте полученные двоичные файлы в папку plugins в ресурсах Unity. После этого сценарий Виндовсмикседреалитютилитиес, указанный в МРТК, решит проблему.

Если вы хотите создать собственную библиотеку DLL или включить в нее этот обходной путь, то основным решением этой проблемы является:

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

И его использование в коде Unity 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;
    }
}