// --------------------------------------------------------------------------------------------------------------------
//
// 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
}
}