I am trying to set the hand into one of a series of poses. I have created a script that captures a frame, serializes the left hand which is then stored as an xml for loading. I currently have the system setting the hand to the correct pose by calculating the offset between the palm position in the live data and that of the stored pose. The problem I am having is getting the hand to rotate.
The 'hand' parameter is the current hand from the live data and the 'pose' parameter is the hand that has been loaded from xml.
This is the method I have created:
public static Hand SetHandInPose(Hand hand, Hand pose)
{
if(hand == null)
{
Debug.Log("Hand is null, so returning that");
return hand;
}
if(pose == null)
{
Debug.Log("The loaded pose is null, so let's just return the original hand");
return hand;
}
Hand h = pose;
Quaternion handRotOffset = pose.Rotation.ToQuaternion() * Quaternion.Inverse(hand.Rotation.ToQuaternion());
//Debug.Log("The rotational offset is: " + handRotOffset.eulerAngles);
Vector offset = hand.PalmPosition - pose.PalmPosition;
h.Rotation = hand.Rotation;//(h.Rotation.ToQuaternion() * handRotOffset).ToLeapQuaternion();
h.PalmPosition += (offset.ToVector3()).ToVector();
h.WristPosition += (offset.ToVector3()).ToVector();
for(int f = 0; f< h.Fingers.Count; f++)
{
for(int i = 0; i < h.Fingers[f].bones.Length; i++)
{
//offset = hand.Fingers[f].bones[i].Center - pose.Fingers[f].bones[i].Center;
//if (h.Fingers[f].bones[i].Type == Bone.BoneType.TYPE_METACARPAL) continue;
h.Fingers[f].bones[i].Center += (offset.ToVector3()).ToVector();
h.Fingers[f].bones[i].NextJoint += (offset.ToVector3()).ToVector();
h.Fingers[f].bones[i].PrevJoint += (offset.ToVector3()).ToVector();
h.Fingers[f].bones[i].Rotation = hand.Fingers[f].bones[i].Rotation;
//h.Fingers[f].bones[i].Rotation = (h.Fingers[f].bones[i].Rotation.ToQuaternion() * handRotOffset).ToLeapQuaternion();
h.Fingers[f].bones[i].Direction = (h.Fingers[f].bones[i].NextJoint - h.Fingers[f].bones[i].PrevJoint);
h.Fingers[f].bones[i].Center = (h.Fingers[f].bones[i].PrevJoint + h.Fingers[f].bones[i].NextJoint) / 2f;
}
h.Fingers[f].Direction = h.Fingers[f].GetBone(Bone.BoneType.TYPE_INTERMEDIATE).Direction;
}
return h;
}
Any suggestions/help would be much appreciated.
UPDATE:
Here's the new code based on the suggestion recieved.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Leap;
using Leap.Unity;
public class MimicHandModelDriver : MonoBehaviour
{
public Chirality whichHand = Chirality.Left;
public enum RotationMode { Inherit, Overwrite }
public RotationMode rotationMode = RotationMode.Inherit;
public MultiLeap_CapsuleHand handModelToDrive;
private bool _handModelInitialized = false;
private bool _handModelBegun = false;
private Hand mimicHand = null;
Hand sourceHand; //The current hand from the live data
Hand poseHand; //Reference to the hand we load from XML that is in the pose we want
public Hand SourceHand
{
set
{
sourceHand = value;
}
}
public Hand PoseHand
{
set
{
poseHand = value;
}
}
private void Update()
{
if (sourceHand != null)
{
// Copy data from the tracked hand into the mimic hand.
if (mimicHand == null) { mimicHand = new Hand(); }
mimicHand.CopyFrom(poseHand); //copy the stored pose in the mimic hand
mimicHand.Arm.CopyFrom(poseHand.Arm); // copy the stored pose's arm into the mimic hand
// Use the rotation from the live data
var handRotation = sourceHand.Rotation.ToQuaternion();
// Transform the copied hand so that it's centered on the current hands position and matches it's rotation.
mimicHand.SetTransform(sourceHand.PalmPosition.ToVector3(), handRotation);
}
// Drive the attached HandModel.
if (mimicHand != null && handModelToDrive != null)
{
// Initialize the handModel if it hasn't already been initialized.
if (!_handModelInitialized)
{
handModelToDrive.SetLeapHand(mimicHand); //Prevents an error with null reference exception when creating the spheres from
//the init hand call
handModelToDrive.InitHand();
_handModelInitialized = true;
}
// Set the HandModel's hand data.
handModelToDrive.SetLeapHand(mimicHand);
// "Begin" the HandModel to represent a 'newly tracked' hand.
if (!_handModelBegun)
{
handModelToDrive.BeginHand();
_handModelBegun = true;
}
Debug.Log("Updating the mimic hand");
handModelToDrive.UpdateTheHand(); //This method contains the update code, with update code commented out
//so i control when a hand is updated. I have used this throughout the rest of my project so i know this works.
}
}
}