// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System.Collections.Generic; using UltimateXR.Avatar.Rig; using UltimateXR.Manipulation; using UltimateXR.Manipulation.HandPoses; using UnityEngine; namespace UltimateXR.Editor.Manipulation.HandPoses { /// /// Stores bone information for preview meshes. /// public class UxrPreviewHandBoneInfo { #region Public Types & Data /// /// Gets the bind pose. /// public Matrix4x4 BindPose { get; private set; } /// /// Gets the matrix representing the bone transform relative to the hand bone. /// public Matrix4x4 TransformRelativeToHand { get; private set; } /// /// Gets the matrix representing the bone transform relative to the parent, in hand bone space. /// public Matrix4x4 TransformRelativeToParent { get; private set; } /// /// Gets the index of the parent bone. /// public int ParentBoneIndex { get; private set; } /// /// Gets the currently computed transform in hand space (relative to the hand bone). /// public Matrix4x4 CurrentRelativeTransform { get; set; } = Matrix4x4.identity; /// /// Gets the currently computed transform in grabber space (relative to where the component /// is located in the hand). /// public Matrix4x4 CurrentTransform { get; set; } = Matrix4x4.identity; #endregion #region Public Methods /// /// Creates the hand bone data. /// /// Skinned mesh renderer with the mesh data that contains the hand /// Bind poses /// Hand bind pose /// Hand descriptor /// Hand rig /// List of bone information public static List CreateHandBoneData(SkinnedMeshRenderer skinnedMeshRenderer, Matrix4x4[] bindPoses, Matrix4x4 handBindPose, UxrHandDescriptor handDescriptor, UxrAvatarHand hand) { List boneList = new List(); for (int i = 0; i < skinnedMeshRenderer.bones.Length; ++i) { boneList.Add(new UxrPreviewHandBoneInfo()); } FillHandBoneData(skinnedMeshRenderer, bindPoses, handBindPose, handDescriptor, hand, boneList); ResolveBoneTransformsRelativeToParent(boneList); return boneList; } #endregion #region Private Methods /// /// Fills hand bone information. /// /// The skin that has the hand mesh /// The bind poses /// The hand bind pose /// The hand descriptor /// The hand rig /// The bone information to fill private static void FillHandBoneData(SkinnedMeshRenderer skinnedMeshRenderer, Matrix4x4[] bindPoses, Matrix4x4 handBindPose, UxrHandDescriptor handDescriptor, UxrAvatarHand hand, List boneList) { FillFingerBoneData(skinnedMeshRenderer, bindPoses, handBindPose, hand.Wrist, handDescriptor.Index, hand.Index, boneList); FillFingerBoneData(skinnedMeshRenderer, bindPoses, handBindPose, hand.Wrist, handDescriptor.Middle, hand.Middle, boneList); FillFingerBoneData(skinnedMeshRenderer, bindPoses, handBindPose, hand.Wrist, handDescriptor.Ring, hand.Ring, boneList); FillFingerBoneData(skinnedMeshRenderer, bindPoses, handBindPose, hand.Wrist, handDescriptor.Little, hand.Little, boneList); FillFingerBoneData(skinnedMeshRenderer, bindPoses, handBindPose, hand.Wrist, handDescriptor.Thumb, hand.Thumb, boneList); for (int i = 0; i < boneList.Count; ++i) { if (boneList[i].Initialized == false) { boneList[i].Initialized = true; boneList[i].BindPose = bindPoses[i]; boneList[i].TransformRelativeToHand = hand.Wrist.worldToLocalMatrix * skinnedMeshRenderer.bones[i].localToWorldMatrix; boneList[i].ParentBoneIndex = -1; } } } /// /// Fills finger bone information /// /// The skin that has the hand mesh /// The bind poses /// The hand bind pose /// The hand's transform /// The finger descriptor /// The finger rig /// The bone information to fill private static void FillFingerBoneData(SkinnedMeshRenderer skinnedMeshRenderer, Matrix4x4[] bindPoses, Matrix4x4 handBindPose, Transform handTransform, UxrFingerDescriptor fingerDescriptor, UxrAvatarFinger finger, List boneList) { TryResolveBoneInfo(skinnedMeshRenderer, bindPoses, finger.Metacarpal, fingerDescriptor.Metacarpal, boneList); TryResolveBoneInfo(skinnedMeshRenderer, bindPoses, finger.Proximal, fingerDescriptor.Proximal, boneList); TryResolveBoneInfo(skinnedMeshRenderer, bindPoses, finger.Intermediate, fingerDescriptor.Intermediate, boneList); TryResolveBoneInfo(skinnedMeshRenderer, bindPoses, finger.Distal, fingerDescriptor.Distal, boneList); } /// /// Tries to resolve bone information. /// /// The skin that has the hand mesh /// The bind poses /// The bone's transform /// The finger node descriptor /// The bone information to fill private static void TryResolveBoneInfo(SkinnedMeshRenderer skinnedMeshRenderer, Matrix4x4[] bindPoses, Transform boneTransform, UxrFingerNodeDescriptor nodeDescriptor, List boneList) { if (boneTransform != null) { for (int i = 0; i < skinnedMeshRenderer.bones.Length; ++i) { if (skinnedMeshRenderer.bones[i] == boneTransform && i < boneList.Count) { boneList[i].Initialized = true; boneList[i].BindPose = bindPoses[i]; boneList[i].TransformRelativeToHand = nodeDescriptor.TransformRelativeToHand; boneList[i].ParentBoneIndex = -1; for (int j = 0; j < skinnedMeshRenderer.bones.Length; ++j) { if (skinnedMeshRenderer.bones[j] == boneTransform.parent && j < boneList.Count) { boneList[i].ParentBoneIndex = j; break; } } } } } } /// /// Resolves the parent information in the list of bones. /// /// The bone information to fill private static void ResolveBoneTransformsRelativeToParent(List boneList) { foreach (UxrPreviewHandBoneInfo bone in boneList) { if (bone.ParentBoneIndex != -1) { bone.TransformRelativeToParent = boneList[bone.ParentBoneIndex].TransformRelativeToHand.inverse * bone.TransformRelativeToHand; } else { bone.TransformRelativeToParent = bone.TransformRelativeToHand; } } } #endregion #region Private Types & Data /// /// Gets whether the object has been initialized. /// private bool Initialized { get; set; } #endregion } }