Hand tracker: Initialization, interaction, and visualization

In this chapter we'll cover how to get started with using and visualizing Ur for hand tracking.

Initializing Handtracker

Install the Ur package and import it to ^ConjureKitManager^.

using Auki.Ur;

Also import ^ARFoundation^ to be able to use the ^ARRaycastManager^.

using UnityEngine.XR.ARFoundation;

Create a private ^HandTracker^ variable, as well as serializable ^ARSession^ and ^ARRaycastManager^ variables.

private HandTracker _handTracker;

[SerializeField] private ARSession arSession;
[SerializeField] private ARRaycastManager arRaycastManager;

Attach the ^ARRaycastManager^ component to AR Session Origin GameObject. Then drag the ^ARSession^ and the ^ARRaycastManager^ components to coressponding fields on the ^ConjureKitManager^ GameObject.

Get the ^HandTracker^ instance and initialize the AR system in ^ConjureKitManager^'s ^Start()^ function.

_handTracker = HandTracker.GetInstance();
_handTracker.SetARSystem(arSession, arCamera, arRaycastManager);

Start the ^HandTracker^ by calling

_handTracker.Start();

Call ^_handTracker.Update()^ every frame to continuously track the hand while moving.

private void Update()
{
    _handTracker.Update();
}

Hand Interaction

Now we want to position a sphere with a collider on our hand's index fingertip so it can interact with the cube.

To begin, create a 3d sphere, rename it to FingertipLandmark, and scale it down to 0.3. On the collider component, tick the ^isTrigger^ checkbox.

Create a new material, change its color to something more noticeable, and drag it to the sphere mesh renderer.

Add a new tag in Project Settings -> Tags and Layers named hand or any other name you choose and add this tag to the FingertipLandmark we just created.

Create a ^Renderer^ variable for the FingertipLandmark.

[SerializeField] private Renderer Fingertip Landmark;

Populate it with the sphere we just created. And in Start function, set the fingertip landmark as a child of our camera transform.

fingertipLandmark.transform.SetParent(arCamera.transform);

To get triggers from other colliders, the cube should have a ^Rigidbody^ component. Add it and tick the ^Is Kinematic^ checkbox to make sure the cube doesn't fall.

Create a new C# script called ^TouchableByHand.cs^ that will handle trigger events on the cube. If the cube is triggered with an object tagged with hand its color will change to a random color. If the trigger exits the cube, it will return to white.

public class TouchableByHand : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "hand")
        {
            gameObject.GetComponent<Renderer>().material.color = Random.ColorHSV();
        }
    }

    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "hand")
        {
            gameObject.GetComponent<Renderer>().material.color = Color.white;
        }
    }
}

Add this script to the cube prefab.

To get our landmark positions in real-time, we will use the Ur callback - ^OnUpdate^ that is invoked when a new hand pose is received. This callback will pass 4 data types:

  1. landmarks: landmark positions relative to the hand position
  2. translations: the positions of each hand in camera space
  3. isRightHand: indicates whether the right or left hand was detected
  4. score: is the hand confidence score. If 0, no hand was detected.

The landmark and translation arrays contain consecutive floats representing the x, y & z-components of a 3D vector.

Once we get the landmarks and translations, we can place the fingertip landmark on landmark 8, the tip of the index finger (see the Ur documentation for a diagram of all hand landmarks). If the hand tracker detects a hand, we should see the fingertip landmark. If not, meaning our hand is not in camera sight, we can disable the fingertip landmark renderer.

_handTracker.OnUpdate += (landmarks, translations, isRightHand, score) =>
{
    if (score[0] > 0)
    {
        var handPosition = new Vector3(
            translations[0],
            translations[1],
            translations[2]);

        var pointerLandmarkIndex = 8 * 3; // Index fingertip
        var pointerLandMarkPosition = new Vector3(
            landmarks[pointerLandmarkIndex + 0],
            landmarks[pointerLandmarkIndex + 1],
            landmarks[pointerLandmarkIndex + 2]);

        fingertipLandmark.enabled = true;
        fingertipLandmark.transform.localPosition = handPosition + pointerLandMarkPosition;
    }
    else
    {
        fingertipLandmark.enabled = false;
    }
};

Visualization of Hand Landmarks

The Ur package allows us to visualize the hand landmarks in two simple steps.

Start by creating a private boolean.

landmarksVisualizeBool = true;

Then create a toggle method that uses the hand tracker methods ^ShowHandMesh^ and ^HideHandMesh^.

public void ToggleHandLandmarks()
{
    landmarksVisualizeBool = !landmarksVisualizeBool;

    if (landmarksVisualizeBool)
    {
        _handTracker.ShowHandMesh();
    }
    else
    {
        _handTracker.HideHandMesh();
    }
}

Now it can be toggled using a UI toggle or any other method you choose.

This is the beginning of this lesson

Need a refresher on the essentials?

Check out more lessons, DIY kits and essentials reading material at the developer learning centre homepage.

想在 posemesh 上进行建设,需要帮助吗?

申请 AUKI 代币补助金以启动您的项目,并直接与 Auki Labs 团队合作,将您的创意推向市场。成功申请者可获得价值高达 10 万美元的 AUKI 代币,以及 Auki Labs 团队提供的开发和营销支持。