Files
dungeons/Assets/UltimateXR/Runtime/Scripts/Avatar/Rig/UxrAvatarRig.HandTransformation.cs
2024-08-06 21:58:35 +02:00

195 lines
13 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrAvatarRig.HandTransformation.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Math;
using UltimateXR.Manipulation.HandPoses;
using UnityEngine;
namespace UltimateXR.Avatar.Rig
{
partial class UxrAvatarRig
{
#region Public Methods
/// <summary>
/// Updates an avatar's hand transforms using a fixed hand descriptor.
/// </summary>
/// <param name="avatar">The avatar to update</param>
/// <param name="handSide">Which hand to update</param>
/// <param name="handDescriptor">The descriptor to get the data from</param>
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);
}
/// <summary>
/// Updates an avatar's hand transforms using two hand descriptors and a blend value.
/// </summary>
/// <param name="avatar">The avatar to update</param>
/// <param name="handSide">Which hand to update</param>
/// <param name="handDescriptorA">The descriptor for the hand pose to blend from</param>
/// <param name="handDescriptorB">The descriptor for the hand pose to blend to</param>
/// <param name="blend">The interpolation value [0.0, 1.0]</param>
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);
}
/// <summary>
/// Updates the hand transforms using a hand descriptor.
/// </summary>
/// <param name="hand">The hand to update</param>
/// <param name="handDescriptor">The descriptor of the hand pose</param>
/// <param name="handLocalAxes">The universal coordinate system of the hand transform</param>
/// <param name="handLocalFingerAxes">The universal coordinate system of the finger transforms</param>
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);
}
/// <summary>
/// Updates the hand transforms using two hand descriptors and an interpolation value.
/// </summary>
/// <param name="hand">The hand to update</param>
/// <param name="handDescriptorA">The descriptor of the hand pose to blend from</param>
/// <param name="handDescriptorB">The descriptor of the hand pose to blend to</param>
/// <param name="blend">The interpolation value [0.0, 1.0]</param>
/// <param name="handLocalAxes">The universal coordinate system of the hand transform</param>
/// <param name="fingerLocalAxes">The universal coordinate system of the finger transforms</param>
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
/// <summary>
/// Updates a finger's transforms from a finger descriptor.
/// </summary>
/// <param name="wrist">The wrist (root) transform of the hand</param>
/// <param name="finger">The finger to update</param>
/// <param name="fingerDescriptor">The descriptor to get the data from</param>
/// <param name="handLocalAxes">The universal coordinate system of the hand transform</param>
/// <param name="fingerLocalAxes">The universal coordinate system of the finger transforms</param>
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);
}
/// <summary>
/// Updates a finger's transforms using two finger descriptors and an interpolation value.
/// </summary>
/// <param name="wrist">The wrist (root) transform of the hand</param>
/// <param name="finger">The finger to update</param>
/// <param name="fingerDescriptorA">The descriptor A to get the data from</param>
/// <param name="fingerDescriptorB">The descriptor B to get the data from</param>
/// <param name="blend">The interpolation value [0.0, 1.0]</param>
/// <param name="handLocalAxes">The universal coordinate system of the hand transform</param>
/// <param name="fingerLocalAxes">The universal coordinate system of the finger transforms</param>
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);
}
/// <summary>
/// Updates a finger bone transform from a node descriptor.
/// </summary>
/// <param name="parent">The node parent</param>
/// <param name="node">The node being updated</param>
/// <param name="nodeDescriptor">The descriptor to get the data from</param>
/// <param name="parentLocalAxes">The universal coordinate system of the parent's transform</param>
/// <param name="nodeLocalAxes">The universal coordinate system of the node transform</param>
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;
}
/// <summary>
/// Updates a finger bone transform using two node descriptors and an interpolation value.
/// </summary>
/// <param name="parent">The node parent</param>
/// <param name="node">The node being updated</param>
/// <param name="nodeDescriptorA">The descriptor A to get the data from</param>
/// <param name="nodeDescriptorB">The descriptor B to get the data from</param>
/// <param name="blend">The interpolation value [0.0, 1.0]</param>
/// <param name="parentLocalAxes">The universal coordinate system of the parent's transform</param>
/// <param name="nodeLocalAxes">The universal coordinate system of the node transform</param>
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
}
}