

OVRCameraRig to your project, follow these steps:








HandTrackingScript.csHandTrackingScript class, add the following: public Camera sceneCamera;
public OVRHand leftHand;
public OVRHand rightHand;
public OVRSkeleton skeleton;
private Vector3 targetPosition;
private Quaternion targetRotation;
private float step;
private bool isIndexFingerPinching;
private LineRenderer line;
private Transform p0;
private Transform p1;
private Transform p2;
private Transform handIndexTipTransform;
| Variables | Description |
|---|---|
sceneCamera | The camera that the scene uses |
leftHand and rightHand | The left and right hand prefabs |
skeleton | The skeleton (used for retrieving the bones’ position and rotation data) |
targetPosition and targetRotation | Position and rotation used for animating the cube while attached to the ribbon) |
step | Helps with the animation ( Time.deltaTime) |
line | The LineRenderer that represents the ribbon |
p0, p1, and p2 | Starting, bend, and end points’ transforms to help draw the ribbon LineRenderer |
handIndexTipTransform | The transform of the left hand index fingertip |
Start()Start() function, define the initial cube’s position and assign the LineRenderer component to line. void Start()
{
transform.position = sceneCamera.transform.position + sceneCamera.transform.forward * 1.0f;
line = GetComponent<LineRenderer>();
}
pinchCube() function and add the following lines. void pinchCube()
{
targetPosition = leftHand.transform.position - leftHand.transform.forward * 0.4f;
targetRotation = Quaternion.LookRotation(transform.position - leftHand.transform.position);
transform.position = Vector3.Lerp(transform.position, targetPosition, step);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, step);
}
B(t) = (1 - t)^2 * P0 + 2 * (1 - t) * t * P1 + t^2 * P2.B, P0, P1, and P2 are Vector3 and represent positions.t represents the size / portion of the line, so it is between 0 and 1 (included).t = 0.5, then B(t) is halfway between point P0 and P2 (passing from P1) and half of the line is drawn.B(0) and, then, gradually iterate over each segment to draw it.HandTrackingScript class: void DrawCurve(Vector3 point_0, Vector3 point_1, Vector3 point_2)
{
line.positionCount = 200;
Vector3 B = new Vector3(0, 0, 0);
float t = 0f;
for (int i = 0; i < line.positionCount; i++)
{
t += 0.005f;
B = (1 - t) * (1 - t) * point_0 + 2 * (1 - t) * t * point_1 + t * t * point_2;
line.SetPosition(i, B);
}
}
DrawCurve() function requires the start (point_0), the bending point (point_1), and the end point (point_2) Vector3 positions of the line as parameters. It loops until every one of the 200 segments renders.Update() function, add the following: void Update()
{
step = 5.0f * Time.deltaTime;
if (leftHand.IsTracked)
{
isIndexFingerPinching = leftHand.GetFingerIsPinching(OVRHand.HandFinger.Index);
if (isIndexFingerPinching)
{
line.enabled = true;
// Animate cube smoothly next to left hand
pinchCube();
// ...
}
else
{
line.enabled = false;
}
}
}
leftHand OVRHand object is tracked with the isTracked() function. This returns true if that happens.GetFingerIsPinching(OVRHand.HandFinger.Index) function to confirm that the user is pinching by using their index finger and assigns the returned value to the boolean variable isIndexFingerPinching. This function is defined as bool OVRHand.GetFingerIsPinching (HandFinger finger). For details on the rest of the fingers defined in theHandFinger enum, see OVRHand.line LineRenderer if the user is pinching and makes it visible to the user. Otherwise, it disables it.pinchCube() helper function to place and rotate the cube (if the user is pinching).Update() function to the following. (Notice the new lines under the pinchCube() invocation.) void Update()
{
step = 5.0f * Time.deltaTime;
if (leftHand.IsTracked)
{
isIndexFingerPinching = leftHand.GetFingerIsPinching(OVRHand.HandFinger.Index);
if (isIndexFingerPinching)
{
line.enabled = true;
pinchCube();
// New lines added below this point
foreach (var b in skeleton.Bones)
{
if (b.Id == OVRSkeleton.BoneId.Hand_IndexTip)
{
handIndexTipTransform = b.Transform;
break;
}
}
p0 = transform;
p2 = handIndexTipTransform;
p1 = sceneCamera.transform;
p1.position += sceneCamera.transform.forward * 0.8f;
DrawCurve(p0.position, p1.position, p2.position);
// New lines added above this point
}
else
{
line.enabled = false;
}
}
}
OVRSkeleton object.skeleton.Bones is an OVRBone list that stores all bones by their Id. For definitions of all the bone Ids, see enum OVRSkeleton.BoneId in OVRSkeleton.OVRSkeleton.BoneId.Hand_IndexTip bone id is found. This represents the left hand’s index tip.handIndexTipTransform.p0 and the transform of the left hand’s index tip to p2.p1 . This will serve as the point that bends the LineRenderer.DrawCurve() helper function to draw the ribbon LineRenderer.p1 definition and assign different values to it relating to the hand or the cube.
HandTrackingScript.cs.using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandTrackingScript : MonoBehaviour
{
public Camera sceneCamera;
public OVRHand leftHand;
public OVRHand rightHand;
public OVRSkeleton skeleton;
private Vector3 targetPosition;
private Quaternion targetRotation;
private float step;
private bool isIndexFingerPinching;
private LineRenderer line;
private Transform p0;
private Transform p1;
private Transform p2;
private Transform handIndexTipTransform;
// Start is called before the first frame update
void Start()
{
// Set initial cube's position in front of user
transform.position = sceneCamera.transform.position + sceneCamera.transform.forward * 1.0f;
// Assign the LineRenderer component of the cube GameObject to line
line = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
// Define step value for animation
step = 5.0f * Time.deltaTime;
// If left hand is tracked
if (leftHand.IsTracked)
{
// Gather info whether left hand is pinching
isIndexFingerPinching = leftHand.GetFingerIsPinching(OVRHand.HandFinger.Index);
// Proceed only if left hand is pinching
if (isIndexFingerPinching)
{
// Show the Line Renderer
line.enabled = true;
// Animate cube smoothly next to left hand
pinchCube();
// Loop through all the bones in the skeleton
foreach (var b in skeleton.Bones)
{
// If bone is the hand index tip
if (b.Id == OVRSkeleton.BoneId.Hand_IndexTip)
{
// Store its transform and break the loop
handIndexTipTransform = b.Transform;
break;
}
}
// p0 is the cube's transform and p2 the left hand's index tip transform
// These are the two edges of the line connecting the cube to the left hand index tip
p0 = transform;
p2 = handIndexTipTransform;
// This is a somewhat random point between the cube and the index tip
// Need to reference as the point that "bends" the curve
p1 = sceneCamera.transform;
p1.position += sceneCamera.transform.forward * 0.8f;
// Draw the line that connects the cube to the user's left index tip and bend it at p1
DrawCurve(p0.position, p1.position, p2.position);
}
// If the user is not pinching
else
{
// Don't display the line at all
line.enabled = false;
}
}
}
void DrawCurve(Vector3 point_0, Vector3 point_1, Vector3 point_2)
/***********************************************************************************
# Helper function that draws a curve between point_0 and point_2, bending at point_1.
# Gradually draws a line as Quadratic Bézier Curve that consists of 200 segments.
#
# Bézier curve draws a path as function B(t), given three points P0, P1, and P2.
# B, P0, P1, P2 are all Vector3 and represent positions.
#
# B = (1 - t)^2 * P0 + 2 * (1-t) * t * P1 + t^2 * P2
#
# t is 0 <= t <= 1 representing size / portion of line when moving to the next segment.
# For example, if t = 0.5f, B(t) is halfway from point P0 to P2.
***********************************************************************************/
{
// Set the number of segments to 200
line.positionCount = 200;
Vector3 B = new Vector3(0, 0, 0);
float t = 0f;
// Draw segments
for (int i = 0; i < line.positionCount; i++)
{
// Move to next segment
t += 0.005f;
B = (1 - t) * (1 - t) * point_0 + 2 * (1 - t) * t * point_1 + t * t * point_2;
line.SetPosition(i, B);
}
}
void pinchCube()
// Places and rotates cube smoothly next to user's left hand
{
targetPosition = leftHand.transform.position - leftHand.transform.forward * 0.4f;
targetRotation = Quaternion.LookRotation(transform.position - leftHand.transform.position);
transform.position = Vector3.Lerp(transform.position, targetPosition, step);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, step);
}
}