reckfellENGINE

Отслеживание рук: суставы, pinch и модель

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

На этой странице

Отслеживание суставов руки и ввод контроллера — разные источники данных. XRHandTracker даёт трансформы и флаги суставов; карта действий даёт логические команды. Наличие суставов не создаёт автоматически select, захват или готовую модель руки.

Включите и проверьте данные

  1. Подготовьте XR-сессию и обработку фокуса.
  2. До инициализации включите xr/openxr/extensions/hand_tracking. Для OpenXR нужны расширение XR_EXT_hand_tracking и поддержка hand tracking устройством/runtime. Настройка запрашивает возможность, но не гарантирует её доступность.
  3. Получайте левую руку через XRServer.GetTracker("/user/hand_tracker/left") as XRHandTracker, правую — через /user/hand_tracker/right. Это другие имена, чем left_hand/right_hand у контроллеров.
  4. Проверяйте null, затем HasTrackingData руки, затем флаги конкретных суставов. Отсутствие tracker может означать незавершённую инициализацию, остановленный сеанс или недоступную возможность; оно само по себе не доказывает причину.

У XRHandTracker есть 26 суставов. HandJoint.Max — граница диапазона, не сустав. Transform сустава в OpenXR задан в пространстве tracking, а не относительно предыдущей кости. В этом пути ориентация дополнительно приведена к соглашениям Humanoid-рига. Не записывайте такие трансформы напрямую как локальные трансформы костей.

Что нужноЧто проверять
Координата суставаPositionValid; для строгого взаимодействия также PositionTracked
ОриентацияOrientationValid; требование OrientationTracked зависит от вашей политики
СкоростьСоответствующий LinearVelocityValid/AngularVelocityValid, а не просто ненулевой Vector3
Радиус в OpenXRPositionValid; радиус дан в метрах и без валидной позиции не определён

VALID и TRACKED различаются: пригодная оценка не обязательно непосредственно отслеживается. Единицы радиуса и правила валидности: справочник OpenXR.

Подтверждён дефект текущего конструктора: начальные флаги суставов не инициализированы. Не считайте новый XRHandTracker готовыми данными и не включайте ему HasTrackingData вручную в игровом коде. Собственный поставщик обязан заполнить флаги и значения всех нужных суставов до публикации валидного состояния. Пример ниже предполагает данные такого поставщика; он не исправляет конструктор.

Пример жеста pinch

Сохраните HandPinch.cs и создайте отдельный экземпляр для каждой руки. Вызывайте Update с текущим tracker и состоянием фокуса из XrStartup. Это локальный детектор расстояния, не команда action map и не реализация распознавания жестов runtime.

C#
using Reckfell;

public sealed class HandPinch
{
    public bool IsPinching { get; private set; }

    // OpenXR raw positions are meters. No game WorldScale is applied here.
    public bool Update(XRHandTracker tracker, bool focused)
    {
        if (!focused || !TryDistance(tracker, out float meters))
            return IsPinching = false;
        IsPinching = IsPinching ? meters < 0.04f : meters <= 0.025f;
        return IsPinching;
    }

    public static bool TryDistance(XRHandTracker tracker, out float meters)
    {
        meters = 0;
        if (tracker is null || !tracker.HasTrackingData) return false;
        const XRHandTracker.HandJointFlags required =
            XRHandTracker.HandJointFlags.PositionValid | XRHandTracker.HandJointFlags.PositionTracked;
        var thumb = XRHandTracker.HandJoint.ThumbTip;
        var index = XRHandTracker.HandJoint.IndexFingerTip;
        if ((tracker.GetHandJointFlags(thumb) & required) != required
            || (tracker.GetHandJointFlags(index) & required) != required) return false;
        Vector3 a = tracker.GetHandJointTransform(thumb).Origin;
        Vector3 b = tracker.GetHandJointTransform(index).Origin;
        if (!a.IsFinite() || !b.IsFinite()) return false;
        meters = a.DistanceTo(b);
        return float.IsFinite(meters);
    }
}

Вход — расстояние до 0.025 м, отпускание — от 0.04 м. Гистерезис предотвращает переключение на одной границе; пороги нужно проверить на целевых руках и устройстве. Пример требует PositionValid и PositionTracked у обоих кончиков, поэтому намеренно отвергает только оценённые положения. Для OpenXR используются сырые метрические координаты; WorldScale сюда не добавляется. Для другого поставщика сначала подтвердите его соглашения.

При потере фокуса/данных состояние сбрасывается. При возврате фокуса уже сведённые пальцы могут сразу снова дать true; если меню требует нового жеста после возврата, добавьте отдельное перевооружение. Сам helper не выбирает объект, не создаёт луч или коллайдер. Для события одного нажатия сравнивайте текущее состояние с предыдущим; не выполняйте действие каждый кадр удержания.

Покажите настоящую модель руки

Понадобится своя корректно скиненная модель со скелетом. В риге используйте такую структуру:

Текст
XROrigin3D
└── XREntity3D (/user/hand_tracker/left, default)
    └── Model
        └── Skeleton3D
            └── XRHandModifier3D

У XREntity3D сначала задайте Tracker, затем Pose=default. У XRHandModifier3D задайте HandTracker на ту же руку. Модификатор сопоставляет имена костей с префиксами Left/Right: например LeftHand, LeftThumbTip, LeftIndexProximal. Отсутствующие кости пропускаются с предупреждением; это не автоматическая починка скелета.

Режим Full меняет позиции и вращения костей, RotationOnly — вращения, сохраняя длины модели. Модификатор не создаёт skin weights, не исправляет оси костей и не добавляет коллизии пальцев. При потере данных он может сохранять предыдущую позу. Видимость ShowWhenTracked не заменяет запрет взаимодействий; ограничения tracking у XREntity3D описаны отдельно.

Читайте результат в момент модификации

Skeleton3D временно применяет модификаторы и затем восстанавливает базовую pose. Поэтому для диагностики читайте кость внутри ModificationProcessed, а не произвольно после кадра. Сохраните HandPoseProbe.cs, добавьте обычный Entity с этим скриптом, задайте Skeleton, Modifier и существующий индекс Bone. LastModified хранит копию и сам по себе не подтверждает актуальный tracking.

C#
using Reckfell;

public partial class HandPoseProbe : Entity
{
    [Export] public Skeleton3D Skeleton { get; set; } = null!;
    [Export] public XRHandModifier3D Modifier { get; set; } = null!;
    [Export] public int Bone { get; set; }
    public Transform3D LastModified { get; private set; } = Transform3D.Identity;

    public override void _Ready()
    {
        if (Skeleton is null || Modifier is null || Modifier.GetSkeleton() != Skeleton
            || Bone < 0 || Bone >= Skeleton.GetBoneCount())
        {
            ReckfellApi.PushError("HandPoseProbe: assign a matching skeleton, modifier and bone index.");
            return;
        }
        Modifier.ModificationProcessed += Capture;
    }
    private void Capture() => LastModified = Skeleton.GetBonePose(Bone);
    public override void _ExitTree()
    {
        if (Modifier is not null && ReckfellObject.IsInstanceValid(Modifier))
            Modifier.ModificationProcessed -= Capture;
    }
}

Исполнение уточнило поведение: до первой валидной руки модификатор оставляет базовую pose; при потере HasTrackingData после валидного кадра повторяет сохранённую относительную pose. При невалидной Palm и HasTrackingData=true он пропускает обработку. HandTracker setter в дереве перестраивает карту и очищает cache даже при повторе имени — не вызывайте его каждый кадр.

Используемая иерархия суставов должна быть полностью согласована и валидна. В исходнике после проверки ORIENTATION_VALID нет отдельной защиты каждого дочернего сустава перед применением; частично невалидная иерархия не проверена как корректный сценарий. Не подставляйте флаги вручную у настоящего поставщика.

HandTrackingSource=Unknown означает неизвестный источник. Не определяйте по названию runtime, оптическая рука это или имитация от контроллера. Профили взаимодействия рук могут давать действия через карту OpenXR, но требуют своей поддержки и привязок; суставы сами по себе этого не подтверждают.

Диагностика и охват

Если руки нет, сначала проверьте запуск и наличие tracker; если tracker есть, но данные невалидны — состояние сеанса, настройки устройства и видимость рук его камерам. Если модель стоит на месте — pose default, HandTracker модификатора и имена костей. Если жест срабатывает неверно — флаги обоих суставов, пространство координат, конечность значений и пороги.

Выполнены 19 проверок искусственного XRHandTracker и ещё 14 проверок настоящего Skeleton3D/XRHandModifier3D с 26 сопоставленными костями и искусственными суставами. Точный HandPoseProbe выполнен в движке. Дефект начальных флагов сохранён как отрицательный результат; тестовый поставщик инициализирует их явно. Оптическое tracking, профиль ввода, экспорт, skin weights, качество модели/анимации и изображение не проверялись. Старые ссылки на отсутствующие демо и прогнозы поддержки платформ удалены.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.