// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System.Collections.Generic; using UltimateXR.Core; using UltimateXR.Core.Math; using UnityEngine; namespace UltimateXR.Avatar.Rig { partial class UxrAvatarRig { #region Public Methods /// /// Saves all the transform information of the bones of a hand so that it can later be restored using /// . /// /// Hand to store all the transforms information of /// Transform information public static Dictionary PushHandTransforms(UxrAvatarHand hand) { Dictionary transforms = new Dictionary(); foreach (Transform transform in hand.Transforms) { transforms.Add(transform, new UxrTransform(transform)); } return transforms; } /// /// Restores all the transform information of the bones of a hand saved using . /// /// Hand to restore /// Transform information /// The transform information is restored using local position/rotation/scale values public static void PopHandTransforms(UxrAvatarHand hand, Dictionary transforms) { foreach (var transform in transforms) { transform.Value.ApplyLocalTo(transform.Key); } } /// /// Curls an avatar finger. /// /// Avatar to curl the finger of /// Which hand the finger belongs to /// Finger to curl /// Curl angle in degrees for the proximal bone /// Curl angle in degrees for the intermediate bone /// Curl angle in degrees for the distal bone /// Spread angle in degrees for the finger (finger "left" or "right" amount with respect to the wrist) public static void CurlFinger(UxrAvatar avatar, UxrHandSide handSide, UxrAvatarFinger finger, float proximalCurl, float intermediateCurl, float distalCurl, float spread = 0.0f) { UxrUniversalLocalAxes fingerAxes = avatar.AvatarRigInfo.GetArmInfo(handSide).FingerUniversalLocalAxes; if (avatar.GetInitialBoneLocalRotation(finger.Proximal, out Quaternion localRotationProximal)) { finger.Proximal.Rotate(fingerAxes.LocalRight, proximalCurl, Space.Self); finger.Proximal.Rotate(fingerAxes.LocalUp, spread * (handSide == UxrHandSide.Left ? 1.0f : -1.0f), Space.Self); } if (avatar.GetInitialBoneLocalRotation(finger.Intermediate, out Quaternion localRotationIntermediate)) { finger.Intermediate.Rotate(fingerAxes.LocalRight, intermediateCurl, Space.Self); } if (avatar.GetInitialBoneLocalRotation(finger.Distal, out Quaternion localRotationDistal)) { finger.Distal.Rotate(fingerAxes.LocalRight, distalCurl, Space.Self); } } /// /// Updates the hand transforms using a runtime hand descriptor. /// /// Avatar to update /// The hand to update /// The runtime descriptor of the hand pose public static void UpdateHandUsingRuntimeDescriptor(UxrAvatar avatar, UxrHandSide handSide, UxrRuntimeHandDescriptor handDescriptor) { UxrAvatarHand hand = avatar.GetHand(handSide); UpdateFingerUsingRuntimeDescriptor(hand.Thumb, handDescriptor.Thumb); UpdateFingerUsingRuntimeDescriptor(hand.Index, handDescriptor.Index); UpdateFingerUsingRuntimeDescriptor(hand.Middle, handDescriptor.Middle); UpdateFingerUsingRuntimeDescriptor(hand.Ring, handDescriptor.Ring); UpdateFingerUsingRuntimeDescriptor(hand.Little, handDescriptor.Little); } /// /// Updates the hand transforms blending between two runtime hand descriptors. /// /// Avatar to update /// The hand to update /// The runtime descriptor of the hand pose to blend from /// The runtime descriptor of the hand pose to blend to /// Interpolation value [0.0, 1.0] public static void UpdateHandUsingRuntimeDescriptor(UxrAvatar avatar, UxrHandSide handSide, UxrRuntimeHandDescriptor handDescriptorA, UxrRuntimeHandDescriptor handDescriptorB, float blend) { UxrAvatarHand hand = avatar.GetHand(handSide); UpdateFingerUsingRuntimeDescriptor(hand.Thumb, handDescriptorA.Thumb, handDescriptorB.Thumb, blend); UpdateFingerUsingRuntimeDescriptor(hand.Index, handDescriptorA.Index, handDescriptorB.Index, blend); UpdateFingerUsingRuntimeDescriptor(hand.Middle, handDescriptorA.Middle, handDescriptorB.Middle, blend); UpdateFingerUsingRuntimeDescriptor(hand.Ring, handDescriptorA.Ring, handDescriptorB.Ring, blend); UpdateFingerUsingRuntimeDescriptor(hand.Little, handDescriptorA.Little, handDescriptorB.Little, blend); } #endregion #region Private Methods /// /// Updates a finger's transforms from a runtime finger descriptor. /// /// The finger to update /// The runtime descriptor to get the data from private static void UpdateFingerUsingRuntimeDescriptor(UxrAvatarFinger finger, UxrRuntimeFingerDescriptor fingerDescriptor) { if (fingerDescriptor.HasMetacarpalInfo) { finger.Metacarpal.localRotation = fingerDescriptor.MetacarpalRotation; } finger.Proximal.localRotation = fingerDescriptor.ProximalRotation; finger.Intermediate.localRotation = fingerDescriptor.IntermediateRotation; finger.Distal.localRotation = fingerDescriptor.DistalRotation; } /// /// Updates a finger's transforms from a runtime finger descriptor. /// /// The finger to update /// The runtime descriptor to blend from /// The runtime descriptor to blend to /// The interpolation parameter [0.0, 1.0] private static void UpdateFingerUsingRuntimeDescriptor(UxrAvatarFinger finger, UxrRuntimeFingerDescriptor fingerDescriptorA, UxrRuntimeFingerDescriptor fingerDescriptorB, float blend) { if (fingerDescriptorA.HasMetacarpalInfo && fingerDescriptorB.HasMetacarpalInfo) { finger.Metacarpal.localRotation = Quaternion.Slerp(fingerDescriptorA.MetacarpalRotation, fingerDescriptorB.MetacarpalRotation, blend); } finger.Proximal.localRotation = Quaternion.Slerp(fingerDescriptorA.ProximalRotation, fingerDescriptorB.ProximalRotation, blend); finger.Intermediate.localRotation = Quaternion.Slerp(fingerDescriptorA.IntermediateRotation, fingerDescriptorB.IntermediateRotation, blend); finger.Distal.localRotation = Quaternion.Slerp(fingerDescriptorA.DistalRotation, fingerDescriptorB.DistalRotation, blend); } #endregion } }