// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Math;
using UltimateXR.Manipulation.HandPoses;
using UnityEngine;
namespace UltimateXR.Avatar.Rig
{
partial class UxrAvatarRig
{
#region Public Methods
///
/// Updates an avatar's hand transforms using a fixed hand descriptor.
///
/// The avatar to update
/// Which hand to update
/// The descriptor to get the data from
public static void UpdateHandUsingDescriptor(UxrAvatar avatar, UxrHandSide handSide, UxrHandDescriptor handDescriptor)
{
UpdateHandUsingDescriptor(avatar.GetHand(handSide), handDescriptor, avatar.AvatarRigInfo.GetArmInfo(handSide).HandUniversalLocalAxes, avatar.AvatarRigInfo.GetArmInfo(handSide).FingerUniversalLocalAxes);
}
///
/// Updates an avatar's hand transforms using two hand descriptors and a blend value.
///
/// The avatar to update
/// Which hand to update
/// The descriptor for the hand pose to blend from
/// The descriptor for the hand pose to blend to
/// The interpolation value [0.0, 1.0]
public static void UpdateHandUsingDescriptor(UxrAvatar avatar, UxrHandSide handSide, UxrHandDescriptor handDescriptorA, UxrHandDescriptor handDescriptorB, float blend)
{
UpdateHandUsingDescriptor(avatar.GetHand(handSide), handDescriptorA, handDescriptorB, blend, avatar.AvatarRigInfo.GetArmInfo(handSide).HandUniversalLocalAxes, avatar.AvatarRigInfo.GetArmInfo(handSide).FingerUniversalLocalAxes);
}
///
/// Updates the hand transforms using a hand descriptor.
///
/// The hand to update
/// The descriptor of the hand pose
/// The universal coordinate system of the hand transform
/// The universal coordinate system of the finger transforms
public static void UpdateHandUsingDescriptor(UxrAvatarHand hand, UxrHandDescriptor handDescriptor, UxrUniversalLocalAxes handLocalAxes, UxrUniversalLocalAxes handLocalFingerAxes)
{
UpdateFingerUsingDescriptor(hand.Wrist, hand.Thumb, handDescriptor.Thumb, handLocalAxes, handLocalFingerAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Index, handDescriptor.Index, handLocalAxes, handLocalFingerAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Middle, handDescriptor.Middle, handLocalAxes, handLocalFingerAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Ring, handDescriptor.Ring, handLocalAxes, handLocalFingerAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Little, handDescriptor.Little, handLocalAxes, handLocalFingerAxes);
}
///
/// Updates the hand transforms using two hand descriptors and an interpolation value.
///
/// The hand to update
/// The descriptor of the hand pose to blend from
/// The descriptor of the hand pose to blend to
/// The interpolation value [0.0, 1.0]
/// The universal coordinate system of the hand transform
/// The universal coordinate system of the finger transforms
public static void UpdateHandUsingDescriptor(UxrAvatarHand hand, UxrHandDescriptor handDescriptorA, UxrHandDescriptor handDescriptorB, float blend, UxrUniversalLocalAxes handLocalAxes, UxrUniversalLocalAxes fingerLocalAxes)
{
UpdateFingerUsingDescriptor(hand.Wrist, hand.Thumb, handDescriptorA.Thumb, handDescriptorB.Thumb, blend, handLocalAxes, fingerLocalAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Index, handDescriptorA.Index, handDescriptorB.Index, blend, handLocalAxes, fingerLocalAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Middle, handDescriptorA.Middle, handDescriptorB.Middle, blend, handLocalAxes, fingerLocalAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Ring, handDescriptorA.Ring, handDescriptorB.Ring, blend, handLocalAxes, fingerLocalAxes);
UpdateFingerUsingDescriptor(hand.Wrist, hand.Little, handDescriptorA.Little, handDescriptorB.Little, blend, handLocalAxes, fingerLocalAxes);
}
#endregion
#region Private Methods
///
/// Updates a finger's transforms from a finger descriptor.
///
/// The wrist (root) transform of the hand
/// The finger to update
/// The descriptor to get the data from
/// The universal coordinate system of the hand transform
/// The universal coordinate system of the finger transforms
private static void UpdateFingerUsingDescriptor(Transform wrist, UxrAvatarFinger finger, UxrFingerDescriptor fingerDescriptor, UxrUniversalLocalAxes handLocalAxes, UxrUniversalLocalAxes fingerLocalAxes)
{
if (fingerDescriptor.HasMetacarpalInfo && finger.Metacarpal)
{
UpdateFingerNodeUsingDescriptor(wrist, finger.Metacarpal, fingerDescriptor.Metacarpal, handLocalAxes, fingerLocalAxes);
UpdateFingerNodeUsingDescriptor(finger.Metacarpal, finger.Proximal, fingerDescriptor.Proximal, fingerLocalAxes, fingerLocalAxes);
}
else
{
UpdateFingerNodeUsingDescriptor(wrist, finger.Proximal, fingerDescriptor.ProximalNoMetacarpal, handLocalAxes, fingerLocalAxes);
}
UpdateFingerNodeUsingDescriptor(finger.Proximal, finger.Intermediate, fingerDescriptor.Intermediate, fingerLocalAxes, fingerLocalAxes);
UpdateFingerNodeUsingDescriptor(finger.Intermediate, finger.Distal, fingerDescriptor.Distal, fingerLocalAxes, fingerLocalAxes);
}
///
/// Updates a finger's transforms using two finger descriptors and an interpolation value.
///
/// The wrist (root) transform of the hand
/// The finger to update
/// The descriptor A to get the data from
/// The descriptor B to get the data from
/// The interpolation value [0.0, 1.0]
/// The universal coordinate system of the hand transform
/// The universal coordinate system of the finger transforms
private static void UpdateFingerUsingDescriptor(Transform wrist,
UxrAvatarFinger finger,
UxrFingerDescriptor fingerDescriptorA,
UxrFingerDescriptor fingerDescriptorB,
float blend,
UxrUniversalLocalAxes handLocalAxes,
UxrUniversalLocalAxes fingerLocalAxes)
{
if (fingerDescriptorA.HasMetacarpalInfo && finger.Metacarpal)
{
UpdateFingerNodeUsingDescriptor(wrist, finger.Metacarpal, fingerDescriptorA.Metacarpal, fingerDescriptorB.Metacarpal, blend, handLocalAxes, fingerLocalAxes);
UpdateFingerNodeUsingDescriptor(finger.Metacarpal, finger.Proximal, fingerDescriptorA.Proximal, fingerDescriptorB.Proximal, blend, fingerLocalAxes, fingerLocalAxes);
}
else
{
UpdateFingerNodeUsingDescriptor(wrist, finger.Proximal, fingerDescriptorA.ProximalNoMetacarpal, fingerDescriptorB.ProximalNoMetacarpal, blend, handLocalAxes, fingerLocalAxes);
}
UpdateFingerNodeUsingDescriptor(finger.Proximal, finger.Intermediate, fingerDescriptorA.Intermediate, fingerDescriptorB.Intermediate, blend, fingerLocalAxes, fingerLocalAxes);
UpdateFingerNodeUsingDescriptor(finger.Intermediate, finger.Distal, fingerDescriptorA.Distal, fingerDescriptorB.Distal, blend, fingerLocalAxes, fingerLocalAxes);
}
///
/// Updates a finger bone transform from a node descriptor.
///
/// The node parent
/// The node being updated
/// The descriptor to get the data from
/// The universal coordinate system of the parent's transform
/// The universal coordinate system of the node transform
private static void UpdateFingerNodeUsingDescriptor(Transform parent, Transform node, UxrFingerNodeDescriptor nodeDescriptor, UxrUniversalLocalAxes parentLocalAxes, UxrUniversalLocalAxes nodeLocalAxes)
{
Matrix4x4 nodeLocalAxesMatrix = new Matrix4x4();
nodeLocalAxesMatrix.SetColumn(0, nodeLocalAxes.LocalRight);
nodeLocalAxesMatrix.SetColumn(1, nodeLocalAxes.LocalUp);
nodeLocalAxesMatrix.SetColumn(2, nodeLocalAxes.LocalForward);
nodeLocalAxesMatrix.SetColumn(3, new Vector4(0, 0, 0, 1));
Quaternion nodeUniversalToActual = Quaternion.Inverse(nodeLocalAxesMatrix.rotation);
Matrix4x4 parentUniversalMatrix = new Matrix4x4();
parentUniversalMatrix.SetColumn(0, parent.TransformVector(parentLocalAxes.LocalRight));
parentUniversalMatrix.SetColumn(1, parent.TransformVector(parentLocalAxes.LocalUp));
parentUniversalMatrix.SetColumn(2, parent.TransformVector(parentLocalAxes.LocalForward));
parentUniversalMatrix.SetColumn(3, new Vector4(0, 0, 0, 1));
Matrix4x4 nodeUniversalMatrix = new Matrix4x4();
nodeUniversalMatrix.SetColumn(0, parentUniversalMatrix.MultiplyVector(nodeDescriptor.Right));
nodeUniversalMatrix.SetColumn(1, parentUniversalMatrix.MultiplyVector(nodeDescriptor.Up));
nodeUniversalMatrix.SetColumn(2, parentUniversalMatrix.MultiplyVector(nodeDescriptor.Forward));
nodeUniversalMatrix.SetColumn(3, new Vector4(0, 0, 0, 1));
node.rotation = nodeUniversalMatrix.rotation * nodeUniversalToActual;
}
///
/// Updates a finger bone transform using two node descriptors and an interpolation value.
///
/// The node parent
/// The node being updated
/// The descriptor A to get the data from
/// The descriptor B to get the data from
/// The interpolation value [0.0, 1.0]
/// The universal coordinate system of the parent's transform
/// The universal coordinate system of the node transform
private static void UpdateFingerNodeUsingDescriptor(Transform parent,
Transform node,
UxrFingerNodeDescriptor nodeDescriptorA,
UxrFingerNodeDescriptor nodeDescriptorB,
float blend,
UxrUniversalLocalAxes parentLocalAxes,
UxrUniversalLocalAxes nodeLocalAxes)
{
UpdateFingerNodeUsingDescriptor(parent, node, nodeDescriptorA, parentLocalAxes, nodeLocalAxes);
Quaternion rotA = node.rotation;
UpdateFingerNodeUsingDescriptor(parent, node, nodeDescriptorB, parentLocalAxes, nodeLocalAxes);
Quaternion rotB = node.rotation;
node.rotation = Quaternion.Slerp(rotA, rotB, blend);
}
#endregion
}
}