Scripting Fundamentals

The Ultraleap Unity Plugin contains utility methods to get access to hand tracking data.

This page will cover common methods to get access to hand tracking data and how to make use of it.


Getting hand tracking data

Hand tracking data in the plugin comes via a LeapProvider. It comes in the form of Frames. This is a collection of data that contains the Hand data for both hands as well as extra IDs and timestamps for you to reference the frames by.

You can subscribe to a provider to get a hand tracking frame as soon as it is ready:

using Leap;
using UnityEngine;

public class Example : MonoBehaviour
{
    public LeapProvider leapProvider;

    private void OnEnable()
    {
        leapProvider.OnUpdateFrame += OnUpdateFrame;
    }
    private void OnDisable()
    {
        leapProvider.OnUpdateFrame -= OnUpdateFrame;
    }

    void OnUpdateFrame(Frame frame)
    {
        Debug.Log("We got a frame");
    }
}

If you wish, you can also access the latest Frame directly via leapProvider.CurrentFrame.

Access specific Hands

When you have the Frame that you would like the Hand data from, you can access specific hands in various ways. Here are some common approaches that build on the above:

void OnUpdateFrame(Frame frame)
{
    //Get a list of all the hands in the frame and loop through
    //to find the first hand that matches the Chirality
    foreach (var hand in frame.Hands)
    {
        if (hand.IsLeft)
        {
            //We found a left hand
        }
    }

    //Use a helpful utility function to get the first hand that matches the Chirality
    Hand _leftHand = frame.GetHand(Chirality.Left);
    Hand _rightHand = frame.GetHand(Chirality.Right);
}

When you have access to a specific hand, you can then make use of all joints and utilities from within that class. Jump to Getting hand details to discover more.


Convenience methods

Note

When using Hands.Provider, the LeapProvider used is assumed and may not be correct if you have multiple in your scene at once. Consider explicitly specifying the LeapProvider you wish to use instead.

Getting Hand Data (Statically)

This snippet shows how you can quickly access hand data through the Hands class static methods:

using Leap;
using System.Collections.Generic;
using UnityEngine;

public class Example: MonoBehaviour
{
    private void Update()
    {
        Hand _specificHand = Hands.Provider.GetHand(Chirality.Left);
        List<Hand> _allHands = Hands.Provider.CurrentFrame.Hands;
    }
}

Getting Hands for Physics (Statically)

using Leap;
using System.Collections.Generic;
using UnityEngine;

public class Example : MonoBehaviour
{
    private void FixedUpdate()
    {
        Hand _specificPhysicsHand = Hands.Provider.GetHand(Chirality.Left);
        List<Hand> _allPhysicsHands = Hands.Provider.CurrentFixedFrame.Hands;
    }
}

Getting hand details

Getting a Specific Hand

Getting a specific Hand can allow you to gain access to additional data. Here we will get access to a Hand to use in future methods:

using Leap;
using UnityEngine;

public class Example : MonoBehaviour
{
    public LeapProvider leapProvider;

    private void OnEnable()
    {
        leapProvider.OnUpdateFrame += OnUpdateFrame;
    }
    private void OnDisable()
    {
        leapProvider.OnUpdateFrame -= OnUpdateFrame;
    }

    void OnUpdateFrame(Frame frame)
    {
        //Use a helpful utility function to get the first hand that matches the Chirality
        Hand _leftHand = frame.GetHand(Chirality.Left);

        //When we have a valid left hand, we can begin searching for more Hand information
        if(_leftHand != null)
        {
            OnUpdateHand(_leftHand)
        }
    }

    void OnUpdateHand(Hand _hand)
    {
        // Here we can get additional information.
    }
}

Getting Hand Fingers

Once you have a hand, you can access the Finger data for the hand in several ways:

void OnUpdateHand(Hand _hand)
{
    //Use _hand to Explicitly get the specified fingers from it
    Finger _thumb = _hand.GetThumb();
    Finger _index = _hand.GetIndex();
    Finger _middle = _hand.GetMiddle();
    Finger _ring = _hand.GetRing();
    Finger _pinky = _hand.GetPinky();

    //Explicitly get the fingers associated with the hand
    _thumb = Hands.GetThumb(_hand);
    _index = Hands.GetIndex(_hand);
    _middle = Hands.GetMiddle(_hand);
    _ring = Hands.GetRing(_hand);
    _pinky = Hands.GetPinky(_hand);

    //Use the FingerType Enum cast to an int to select a finger from the hand
    _thumb = _hand.Finger((int)Finger.FingerType.TYPE_THUMB);
    _index = _hand.Finger((int)Finger.FingerType.TYPE_INDEX);
    _middle = _hand.Finger((int)Finger.FingerType.TYPE_MIDDLE);
    _ring = _hand.Finger((int)Finger.FingerType.TYPE_RING);
    _pinky = _hand.Finger((int)Finger.FingerType.TYPE_PINKY);

    //Use an index to define what finger you want.
    _thumb = _hand.Fingers[0];
    _index = _hand.Fingers[1];
    _middle = _hand.Fingers[2];
    _ring = _hand.Fingers[3];
    _pinky = _hand.Fingers[4];
}

Getting Hand Bones

Similarly, you can access the Bones from the hand data by doing any of the following.

void OnUpdateHand(Hand _hand)
{
    //Use _hand to Explicitly get the specified finger and subsequent bone from it
    Finger _thumb = _hand.GetThumb();
    Finger _index = _hand.GetIndex();
    Finger _middle = _hand.GetMiddle();
    Finger _ring = _hand.GetRing();
    Finger _pinky = _hand.GetPinky();

    //Use the _finger to subsequently get the Metacarpa bone from it using the BoneType Enum
    Bone _thumbMetacarpal = _thumb.Bone(Bone.BoneType.TYPE_METACARPAL);
    Bone _indexMetacarpal = _index.Bone(Bone.BoneType.TYPE_METACARPAL);
    Bone _middleMetacarpal = _middle.Bone(Bone.BoneType.TYPE_METACARPAL);
    Bone _ringMetacarpal = _ring.Bone(Bone.BoneType.TYPE_METACARPAL);
    Bone _pinkyMetacarpal = _pinky.Bone(Bone.BoneType.TYPE_METACARPAL);

    //Use the _indexFinger to access the bone array, then get the Metacarpal bone from it using the BoneType Enum cast to an int
    _thumbMetacarpal = _thumb.bones[(int)Bone.BoneType.TYPE_METACARPAL];
    _indexMetacarpal = _index.bones[(int)Bone.BoneType.TYPE_METACARPAL];
    _middleMetacarpal = _middle.bones[(int)Bone.BoneType.TYPE_METACARPAL];
    _ringMetacarpal = _ring.bones[(int)Bone.BoneType.TYPE_METACARPAL];
    _pinkyMetacarpal = _pinky.bones[(int)Bone.BoneType.TYPE_METACARPAL];

    //Use the _indexFinger to access the bone array, then get the metacarpal by index
    _thumbMetacarpal = _thumb.bones[0];
    _indexMetacarpal = _index.bones[1];
    _middleMetacarpal = _middle.bones[2];
    _ringMetacarpal = _ring.bones[3];
    _pinkyMetacarpal = _pinky.bones[4];
}

Getting Arm Details

You can access the Arm (connected to the hand) as follows:

void OnUpdateHand(Hand _hand)
{
    Arm _arm = _hand.Arm;

    float _armLength = _arm.Length;
    float _armWidth = _arm.Width;
    Vector3 _elbowPosition = _arm.ElbowPosition;
}

Getting Pinch Details

Once you have a hand, the API provides details about the hands pinching states.

void OnUpdateHand(Hand _hand)
{
    float _pinchStrength = _hand.PinchStrength;
    float _pinchDistance = _hand.PinchDistance;
    Vector3 _pinchPosition = _hand.GetPinchPosition();
    Vector3 _predictedPinchPosition = _hand.GetPredictedPinchPosition();
    bool isPinching = _hand.IsPinching();
}

Getting Grab Details

The API also provides details about the hands-grabbing states.

void OnUpdateHand(Hand _hand)
{
    float _grabStrength = _hand.GrabStrength;
    float _grabAngle = _hand.GrabAngle;
}

Hand Rays

The following code snippet shows how to obtain an ‘unsmoothed’ ray representing the general reaching/interaction intent direction. Under the hood this creates a ray whose origin is anchored at the left or right shoulder and which passes through the index proximal bone.

void OnUpdateHand(Hand _hand)
{
    Ray _handRay = _hand.HandRay(Camera.main);
}