1using System.Collections.Generic;
3using Microsoft.Azure.Kinect.BodyTracking;
11 [Header(
"References (Do NOT edit unless you know what you're doing!)")]
12 [SerializeField]
private Transform rootJoint =
null;
15 readonly Quaternion Y_180_FLIP =
new Quaternion(0.0f, 1.0f, 0.0f, 0.0f);
16 readonly Vector3 X_POSITIVE = Vector3.right;
17 readonly Vector3 Y_POSITIVE = Vector3.up;
18 readonly Vector3 Z_POSITIVE = Vector3.forward;
21 [Header(
"Internal Variables (Exposed for debugging purposes.)")]
22 [SerializeField, Tooltip(
"Joint Positions")]
private Vector3[] jointPositions =
new Vector3[(int)JointId.Count];
23 [SerializeField, Tooltip(
"Absolute Joint Rotations")]
private Quaternion[] absoluteJointRotations =
new Quaternion[(int)JointId.Count];
24 private Dictionary<JointId, JointId> parentJointMap;
25 private Dictionary<JointId, Quaternion> basisJointMap;
27 private void Awake() {
33 private void InitParentJointMap() {
34 parentJointMap =
new Dictionary<JointId, JointId>();
36 parentJointMap[JointId.Pelvis] = JointId.Count;
37 parentJointMap[JointId.SpineNavel] = JointId.Pelvis;
38 parentJointMap[JointId.SpineChest] = JointId.SpineNavel;
39 parentJointMap[JointId.Neck] = JointId.SpineChest;
40 parentJointMap[JointId.ClavicleLeft] = JointId.SpineChest;
41 parentJointMap[JointId.ShoulderLeft] = JointId.ClavicleLeft;
42 parentJointMap[JointId.ElbowLeft] = JointId.ShoulderLeft;
43 parentJointMap[JointId.WristLeft] = JointId.ElbowLeft;
44 parentJointMap[JointId.HandLeft] = JointId.WristLeft;
45 parentJointMap[JointId.HandTipLeft] = JointId.HandLeft;
46 parentJointMap[JointId.ThumbLeft] = JointId.HandLeft;
47 parentJointMap[JointId.ClavicleRight] = JointId.SpineChest;
48 parentJointMap[JointId.ShoulderRight] = JointId.ClavicleRight;
49 parentJointMap[JointId.ElbowRight] = JointId.ShoulderRight;
50 parentJointMap[JointId.WristRight] = JointId.ElbowRight;
51 parentJointMap[JointId.HandRight] = JointId.WristRight;
52 parentJointMap[JointId.HandTipRight] = JointId.HandRight;
53 parentJointMap[JointId.ThumbRight] = JointId.HandRight;
54 parentJointMap[JointId.HipLeft] = JointId.SpineNavel;
55 parentJointMap[JointId.KneeLeft] = JointId.HipLeft;
56 parentJointMap[JointId.AnkleLeft] = JointId.KneeLeft;
57 parentJointMap[JointId.FootLeft] = JointId.AnkleLeft;
58 parentJointMap[JointId.HipRight] = JointId.SpineNavel;
59 parentJointMap[JointId.KneeRight] = JointId.HipRight;
60 parentJointMap[JointId.AnkleRight] = JointId.KneeRight;
61 parentJointMap[JointId.FootRight] = JointId.AnkleRight;
62 parentJointMap[JointId.Head] = JointId.Pelvis;
63 parentJointMap[JointId.Nose] = JointId.Head;
64 parentJointMap[JointId.EyeLeft] = JointId.Head;
65 parentJointMap[JointId.EarLeft] = JointId.Head;
66 parentJointMap[JointId.EyeRight] = JointId.Head;
67 parentJointMap[JointId.EarRight] = JointId.Head;
71 private void InitBasisJointMap() {
73 Quaternion leftHipBasis = Quaternion.LookRotation(X_POSITIVE, -Z_POSITIVE);
74 Quaternion spineHipBasis = Quaternion.LookRotation(X_POSITIVE, -Z_POSITIVE);
75 Quaternion rightHipBasis = Quaternion.LookRotation(X_POSITIVE, Z_POSITIVE);
78 Quaternion leftArmBasis = Quaternion.LookRotation(Y_POSITIVE, -Z_POSITIVE);
79 Quaternion rightArmBasis = Quaternion.LookRotation(-Y_POSITIVE, Z_POSITIVE);
80 Quaternion leftHandBasis = Quaternion.LookRotation(-Z_POSITIVE, -Y_POSITIVE);
81 Quaternion rightHandBasis = Quaternion.identity;
82 Quaternion leftFootBasis = Quaternion.LookRotation(X_POSITIVE, Y_POSITIVE);
83 Quaternion rightFootBasis = Quaternion.LookRotation(X_POSITIVE, -Y_POSITIVE);
85 basisJointMap =
new Dictionary<JointId, Quaternion>();
88 basisJointMap[JointId.Pelvis] = spineHipBasis;
89 basisJointMap[JointId.SpineNavel] = spineHipBasis;
90 basisJointMap[JointId.SpineChest] = spineHipBasis;
91 basisJointMap[JointId.Neck] = spineHipBasis;
92 basisJointMap[JointId.ClavicleLeft] = leftArmBasis;
93 basisJointMap[JointId.ShoulderLeft] = leftArmBasis;
94 basisJointMap[JointId.ElbowLeft] = leftArmBasis;
95 basisJointMap[JointId.WristLeft] = leftHandBasis;
96 basisJointMap[JointId.HandLeft] = leftHandBasis;
97 basisJointMap[JointId.HandTipLeft] = leftHandBasis;
98 basisJointMap[JointId.ThumbLeft] = leftArmBasis;
99 basisJointMap[JointId.ClavicleRight] = rightArmBasis;
100 basisJointMap[JointId.ShoulderRight] = rightArmBasis;
101 basisJointMap[JointId.ElbowRight] = rightArmBasis;
102 basisJointMap[JointId.WristRight] = rightHandBasis;
103 basisJointMap[JointId.HandRight] = rightHandBasis;
104 basisJointMap[JointId.HandTipRight] = rightHandBasis;
105 basisJointMap[JointId.ThumbRight] = rightArmBasis;
106 basisJointMap[JointId.HipLeft] = leftHipBasis;
107 basisJointMap[JointId.KneeLeft] = leftHipBasis;
108 basisJointMap[JointId.AnkleLeft] = leftHipBasis;
109 basisJointMap[JointId.FootLeft] = leftFootBasis;
110 basisJointMap[JointId.HipRight] = rightHipBasis;
111 basisJointMap[JointId.KneeRight] = rightHipBasis;
112 basisJointMap[JointId.AnkleRight] = rightHipBasis;
113 basisJointMap[JointId.FootRight] = rightFootBasis;
114 basisJointMap[JointId.Head] = spineHipBasis;
115 basisJointMap[JointId.Nose] = spineHipBasis;
116 basisJointMap[JointId.EyeLeft] = spineHipBasis;
117 basisJointMap[JointId.EarLeft] = spineHipBasis;
118 basisJointMap[JointId.EyeRight] = spineHipBasis;
119 basisJointMap[JointId.EarRight] = spineHipBasis;
122 private int FindClosestTrackedBody(
FrameData trackerFrameData) {
123 int closestBody = -1;
124 float minDistanceFromKinect =
float.MaxValue;
127 Vector3 pelvisPos =
new Vector3((
float)pelvisPosition.X, (float)pelvisPosition.Y, (
float)pelvisPosition.Z);
128 if (pelvisPos.magnitude < minDistanceFromKinect) {
130 minDistanceFromKinect = pelvisPos.magnitude;
136 private Quaternion OrientateRotation(Quaternion rotation, SensorOrientation sensorOrientation) {
137 switch (sensorOrientation) {
138 case SensorOrientation.Clockwise90:
139 return Quaternion.AngleAxis(90.0f, Z_POSITIVE) * rotation;
140 case SensorOrientation.CounterClockwise90:
141 return Quaternion.AngleAxis(-90.0f, Z_POSITIVE) * rotation;
142 case SensorOrientation.Flip180:
143 return Quaternion.AngleAxis(180.0f, Z_POSITIVE) * rotation;
148 private Vector3 OrientatePosition(Vector3 position, SensorOrientation sensorOrientation) {
149 float rotationAngle = 0.0f;
150 switch (sensorOrientation) {
151 case SensorOrientation.Clockwise90:
156 rotationAngle = 90.0f;
158 case SensorOrientation.CounterClockwise90:
159 rotationAngle = -90.0f;
161 case SensorOrientation.Flip180:
162 rotationAngle = 180.0f;
167 Matrix4x4 translationMatrix = Matrix4x4.Translate(position);
168 Matrix4x4 rotationMatrix = Matrix4x4.Rotate(Quaternion.AngleAxis(rotationAngle, Z_POSITIVE));
169 Matrix4x4 positionMatrix = rotationMatrix * translationMatrix;
170 return new Vector3(positionMatrix.m03, positionMatrix.m13, positionMatrix.m23);
173 private void SetBonesTransform(
BodyData body, SensorOrientation sensorOrientation) {
174 for (
int jointNum = 0; jointNum < (int)JointId.Count; jointNum++) {
176 Vector3 jointPos = OrientatePosition(
182 jointPositions[jointNum] = jointPos;
185 Quaternion bodyJointRotation =
new Quaternion(
192 Quaternion jointRot = OrientateRotation(Y_180_FLIP * bodyJointRotation * Quaternion.Inverse(basisJointMap[(JointId)jointNum]), sensorOrientation);
193 absoluteJointRotations[jointNum] = jointRot;
196 transform.GetChild(0).GetChild(jointNum).localPosition = jointPos;
197 transform.GetChild(0).GetChild(jointNum).localRotation = jointRot;
200 if (parentJointMap[(JointId)jointNum] == JointId.Head ||
201 parentJointMap[(JointId)jointNum] == JointId.Count) {
202 transform.GetChild(0).GetChild(jointNum).GetChild(0).gameObject.SetActive(
false);
207 Vector3 parentTrackerSpacePosition = OrientatePosition(
208 new Vector3(body.
JointPositions3D[(
int)parentJointMap[(JointId)jointNum]].X,
212 Vector3 boneDirectionTrackerSpace = jointPos - parentTrackerSpacePosition;
213 Vector3 boneDirectionWorldSpace = transform.rotation * boneDirectionTrackerSpace;
214 Vector3 boneDirectionLocalSpace = Quaternion.Inverse(transform.GetChild(0).GetChild(jointNum).rotation) * Vector3.Normalize(boneDirectionWorldSpace);
217 transform.GetChild(0).GetChild(jointNum).GetChild(0).localScale =
new Vector3(1, 20.0f * 0.5f * boneDirectionWorldSpace.magnitude, 1);
218 transform.GetChild(0).GetChild(jointNum).GetChild(0).localRotation = Quaternion.FromToRotation(Vector3.up, boneDirectionLocalSpace);
219 transform.GetChild(0).GetChild(jointNum).GetChild(0).position = transform.GetChild(0).GetChild(jointNum).position - 0.5f * boneDirectionWorldSpace;
230 for (
int jointNum = 0; jointNum < (int)JointId.Count; jointNum++) {
231 transform.GetChild(0).GetChild(jointNum).gameObject.GetComponent<MeshRenderer>().enabled = show;
232 transform.GetChild(0).GetChild(jointNum).GetChild(0).GetComponent<MeshRenderer>().enabled = show;
259 JointId parent = parentJointMap[jointId];
260 Quaternion parentJointRotationBodySpace = Quaternion.identity;
261 if (parent == JointId.Count) {
262 parentJointRotationBodySpace = Y_180_FLIP;
264 parentJointRotationBodySpace = absoluteJointRotations[(int)parent];
266 Quaternion jointRotationBodySpace = absoluteJointRotations[(int)jointId];
267 Quaternion relativeRotation = Quaternion.Inverse(parentJointRotationBodySpace) * jointRotationBodySpace;
269 return relativeRotation;
282 int closestBody = FindClosestTrackedBody(frameData);
286 SetBonesTransform(skeleton, orientation);
BodyTracker represents the BodyData from the ORBBEC sensor as a skeleton. Important: BodyTracker pref...
Quaternion GetAbsoluteJointRotation(JointId jointId)
Get the rotation of a joint, relative to the root.
void UpdateSkeleton(FrameData frameData, SensorOrientation orientation)
Update the skeleton based on frame data.
Vector3 GetJointPosition(JointId jointId)
void ShowSkeleton(bool show)
Show or hide the skeleton in the game scene.
Quaternion GetRelativeJointRotation(JointId jointId)
Get the rotation of a joint, relative to its parent.
BodyData[] Bodies
Array of bodies. Use NumDetectedBodies to determine how many bodies contain useful data.
System.Numerics.Quaternion[] JointRotations
System.Numerics.Vector3[] JointPositions3D