We've got some convenience/extension methods built into our UnityModules that make copying hand data around easier:
hand.Transform(LeapTransform transform)
-- this will apply a transform to the Hand.
hand.SetTransform(Vector3 position, Quaternion rotation)
-- this will transform a Hand to center the PalmPosition on position and transform the whole hand to align with rotation
.
hand.CopyFrom(Hand other)
-- this one will handle all the gorey details of copying the data (read: pose) from one Hand to another.
In this case, CopyFrom and SetTransform will get you the data you're looking for.
EDIT: So, the new aspect of your question involves using this data to drive a HandModel -- in this case, a CapsuleHand. For the current version of our Unity assets, the hand model pipeline is pretty shut-down. You're either using the standard Leap rig to drive real tracked hands, or you have a bit of a rough time.
Fortunately, you can just drive a HandModel manually, but you have to be careful to call the right methods in the right order. Check out this example script, which can drive a HandModel that it has a reference to. Important: because you're driving the HandModel independently of the normal Provider/HandPool/HandGroup pipeline, you need to create a new HandModel -- e.g. a new, duplicate CapsuleHand object -- that isn't in your Leap Rig and isn't being driven by that rig's HandPool. This script can then drive it:
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 HandModelBase handModelToDrive;
private bool _handModelInitialized = false;
private bool _handModelBegun = false;
[Header("Debug")]
public bool drawEditorGizmos = false;
private Hand mimicHand = null;
private void Update() {
// Get a hand from the standard tracking pipeline.
var sourceHand = Hands.Get(whichHand);
if (sourceHand != null) {
// Copy data from the tracked hand into the mimic hand.
if (mimicHand == null) { mimicHand = new Hand(); }
mimicHand.CopyFrom(sourceHand);
mimicHand.Arm.CopyFrom(sourceHand.Arm); // Capsule Hands like to have Arm data too.
// Figure out what rotation to use for the mimic hand.
var handRotation = this.transform.rotation;
if (rotationMode == RotationMode.Inherit) {
handRotation = mimicHand.Rotation.ToQuaternion();
}
// Transform the copied hand so that it's centered on this object's transform.
mimicHand.SetTransform(this.transform.position, handRotation);
}
// Drive the attached HandModel.
if (mimicHand != null && handModelToDrive != null) {
// Initialize the handModel if it hasn't already been initialized.
if (!_handModelInitialized) {
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;
}
// Every Update, we call UpdateHand. It's necessary to call this every update
// specifically for CapsuleHands, which uses manual GL calls to render rather than
// a standard MeshRenderer.
handModelToDrive.UpdateHand();
}
}
// Draw some gizmos in case there's no HandModel attached.
private void OnDrawGizmos() {
if (!drawEditorGizmos) return;
Gizmos.color = Color.red;
if (mimicHand != null) {
draw(mimicHand.PalmPosition.ToVector3());
for (int f = 0; f < 5; f++) {
for (int b = 0; b < 4; b++) {
draw(mimicHand.Fingers[f].bones[b].NextJoint.ToVector3());
}
}
}
}
private void draw(Vector3 pos) {
Gizmos.DrawWireSphere(pos, 0.01f);
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…