I have a model of a human hand in Unity.
I need to calculate the position of each finger joint using the rotation of the previous joint. In the model this is portraited as an object that is the wrist, the next 5 joints of each finger being its child object, and so on till you reach the tip of the fingers.
I’ve managed to do this in unity, and I added the code below. What I am now trying to do is convert it to python code, so that when I’m given the rotations, I can then draw points in matplotlib to reconstruct the hand.
I will provide any other necessary information.
Here is the code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
public class PositionToRotationQtr : MonoBehaviour
{
public static int jointCount = 18;
public GameObject lHand, rHand;
public TextMeshPro lText, rText, lDistText, rDistText;
public Dictionary<string, Vector3> lRotations = new Dictionary<string, Vector3>();
public Dictionary<string, Vector3> rRotations = new Dictionary<string, Vector3>();
public Dictionary<string, float> lDistFromPrev = new Dictionary<string, float>();
public Dictionary<string, float> rDistFromPrev = new Dictionary<string, float>();
public List<Transform[]> lJoints, rJoints;
public GameObject[] lPoints = new GameObject[jointCount];
public GameObject[] rPoints = new GameObject[jointCount];
// Start is called before the first frame update
void Start()
{
if (lHand == null)
lHand = GameObject.Find("OculusHand_L");
if (rHand == null)
rHand = GameObject.Find("OculusHand_R");
for (int i = 0; i < jointCount; i++)
{
lPoints[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
lPoints[i].GetComponent<Renderer>().material.color = Color.blue;
lPoints[i].transform.localScale = new Vector3(0.005f, 0.005f, 0.005f);
rPoints[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);
rPoints[i].GetComponent<Renderer>().material.color = Color.blue;
rPoints[i].transform.localScale = new Vector3(0.005f, 0.005f, 0.005f);
}
MapJoints();
}
// Update is called once per frame
void Update()
{
UpdateData();
//PrintData();
CalcHandsQtr();
}
void UpdateData()
{
lRotations.Clear();
rRotations.Clear();
lDistFromPrev.Clear();
rDistFromPrev.Clear();
//int counter = 0;
//lPoints[counter++].transform.position = lJoints[0][0].transform.position;
foreach (Transform[] joints in lJoints)
{
if (joints.Length == 1)
lRotations.Add(joints[0].name, joints[0].rotation.eulerAngles);
else
{
for (int i = 0; i < joints.Length; i++)
{
//lPoints[counter++].transform.position = joints[i].transform.position;
lRotations.Add(joints[i].name.ToString(), joints[i].rotation.eulerAngles);
if (i == 0)
lDistFromPrev.Add(joints[i].name, Vector3.Distance(lJoints[0][0].position, joints[i].position));
else
lDistFromPrev.Add(joints[i].name, Vector3.Distance(joints[i - 1].position, joints[i].position));
}
}
}
//counter = 0;
//rPoints[counter++].transform.position = rJoints[0][0].transform.position;
foreach (Transform[] joints in rJoints)
{
if (joints.Length == 1)
rRotations.Add(joints[0].name, joints[0].rotation.eulerAngles);
else
{
for (int i = 0; i < joints.Length; i++)
{
//rPoints[counter++].transform.position = joints[i].transform.position;
rRotations.Add(joints[i].name.ToString(), joints[i].rotation.eulerAngles);
if (i == 0)
rDistFromPrev.Add(joints[i].name, Vector3.Distance(rJoints[0][0].position, joints[i].position));
else
rDistFromPrev.Add(joints[i].name, Vector3.Distance(joints[i - 1].position, joints[i].position));
}
}
}
}
void PrintData()
{
string lData = "n Left Hand Rotations:n", rData = "n Right Hand Rotations:n";
foreach (KeyValuePair<string, Vector3> rotation in lRotations)
lData += " " + rotation.Key + ": " + rotation.Value.ToString() + "n";
foreach (KeyValuePair<string, Vector3> rotation in rRotations)
rData += " " + rotation.Key + ": " + rotation.Value.ToString() + "n";
string lDistData = "n Left Hand Distances:n", rDistData = "n Right Hand Distances:n";
foreach (KeyValuePair<string, float> distance in lDistFromPrev)
lDistData += " " + distance.Key + ": " + distance.Value.ToString() + "n";
foreach (KeyValuePair<string, float> distance in rDistFromPrev)
rDistData += " " + distance.Key + ": " + distance.Value.ToString() + "n";
lText.text = lData;
rText.text = rData;
lDistText.text = lDistData;
rDistText.text = rDistData;
}
void MapJoints()
{
Transform lWrist = lHand.transform.Find("b_l_wrist");
Transform[] lThumb = {
lWrist.Find("b_l_thumb0"),
lWrist.Find("b_l_thumb0/b_l_thumb1"),
lWrist.Find("b_l_thumb0/b_l_thumb1/b_l_thumb2"),
lWrist.Find("b_l_thumb0/b_l_thumb1/b_l_thumb2/b_l_thumb3") };
Transform[] lIndex = {
lWrist.Find("b_l_index1"),
lWrist.Find("b_l_index1/b_l_index2"),
lWrist.Find("b_l_index1/b_l_index2/b_l_index3") };
Transform[] lMiddle = {
lWrist.Find("b_l_middle1"),
lWrist.Find("b_l_middle1/b_l_middle2"),
lWrist.Find("b_l_middle1/b_l_middle2/b_l_middle3") };
Transform[] lRing = {
lWrist.Find("b_l_ring1"),
lWrist.Find("b_l_ring1/b_l_ring2"),
lWrist.Find("b_l_ring1/b_l_ring2/b_l_ring3") };
Transform[] lPinky = {
lWrist.Find("b_l_pinky0"),
lWrist.Find("b_l_pinky0/b_l_pinky1"),
lWrist.Find("b_l_pinky0/b_l_pinky1/b_l_pinky2"),
lWrist.Find("b_l_pinky0/b_l_pinky1/b_l_pinky2/b_l_pinky3") };
Transform rWrist = rHand.transform.Find("b_r_wrist");
Transform[] rThumb = {
rWrist.Find("b_r_thumb0"),
rWrist.Find("b_r_thumb0/b_r_thumb1"),
rWrist.Find("b_r_thumb0/b_r_thumb1/b_r_thumb2"),
rWrist.Find("b_r_thumb0/b_r_thumb1/b_r_thumb2/b_r_thumb3") };
Transform[] rIndex = {
rWrist.Find("b_r_index1"),
rWrist.Find("b_r_index1/b_r_index2"),
rWrist.Find("b_r_index1/b_r_index2/b_r_index3") };
Transform[] rMiddle = {
rWrist.Find("b_r_middle1"),
rWrist.Find("b_r_middle1/b_r_middle2"),
rWrist.Find("b_r_middle1/b_r_middle2/b_r_middle3") };
Transform[] rRing = {
rWrist.Find("b_r_ring1"),
rWrist.Find("b_r_ring1/b_r_ring2"),
rWrist.Find("b_r_ring1/b_r_ring2/b_r_ring3") };
Transform[] rPinky = {
rWrist.Find("b_r_pinky0"),
rWrist.Find("b_r_pinky0/b_r_pinky1"),
rWrist.Find("b_r_pinky0/b_r_pinky1/b_r_pinky2"),
rWrist.Find("b_r_pinky0/b_r_pinky1/b_r_pinky2/b_r_pinky3") };
lJoints = new List<Transform[]>{
new Transform[] { lWrist }, lThumb, lIndex, lMiddle, lRing, lPinky};
rJoints = new List<Transform[]>{
new Transform[] { rWrist }, rThumb, rIndex, rMiddle, rRing, rPinky};
}
void CalcHandsQtr()
{
int pointCount = 0;
foreach (Transform[] joints in lJoints)
{
if (joints.Length == 1)
continue;
Vector3 p0 = joints[0].position; // Starting position (global)
lPoints[pointCount++].transform.position = p0; // Update first point position
// Use global rotation to calculate the next joint positions
for (int i = 1; i < joints.Length; i++)
{
// Get the previous joint's global rotation
Quaternion globalRotation = joints[i - 1].rotation;
// Get the vector pointing in the direction of the next joint (in local space)
Vector3 localDirection = new Vector3(lDistFromPrev[joints[i].name], 0, 0);
// Transform the local direction to global space
Vector3 globalDirection = globalRotation * localDirection * (-1);
// Calculate the next joint position
Vector3 pNext = p0 + globalDirection;
lPoints[pointCount++].transform.position = pNext;
// Update the current position for the next iteration
p0 = pNext;
}
}
}
}
8