8#include <Threedim/HumanoidPose.hpp>
9#include <Threedim/HumanoidSourceMaps.hpp>
22inline void quat_mul_xyzw(
23 const float a[4],
const float b[4],
float out[4])
noexcept
25 const float x = a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1];
26 const float y = a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0];
27 const float z = a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3];
28 const float w = a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2];
29 out[0] = x; out[1] = y; out[2] = z; out[3] = w;
32inline void quat_inv_xyzw(
const float q[4],
float out[4])
noexcept
35 out[0] = -q[0]; out[1] = -q[1]; out[2] = -q[2]; out[3] = q[3];
44inline void shortest_arc(
45 const float from[3],
const float to[3],
float out[4])
noexcept
47 const float d = from[0] * to[0] + from[1] * to[1] + from[2] * to[2];
48 const float eps = 1e-6f;
53 out[0] = 0.f; out[1] = 0.f; out[2] = 0.f; out[3] = 1.f;
61 if(std::fabs(from[0]) < 0.9f)
63 axis[0] = 1.f - from[0] * from[0];
64 axis[1] = -from[0] * from[1];
65 axis[2] = -from[0] * from[2];
69 axis[0] = -from[1] * from[0];
70 axis[1] = 1.f - from[1] * from[1];
71 axis[2] = -from[1] * from[2];
74 = std::sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
77 const float inv = 1.f / len;
78 out[0] = axis[0] * inv;
79 out[1] = axis[1] * inv;
80 out[2] = axis[2] * inv;
84 out[0] = 1.f; out[1] = 0.f; out[2] = 0.f;
91 const float cross[3] = {
92 from[1] * to[2] - from[2] * to[1],
93 from[2] * to[0] - from[0] * to[2],
94 from[0] * to[1] - from[1] * to[0]};
95 const float s = std::sqrt((1.f + d) * 2.f);
96 const float invs = 1.f / s;
97 out[0] = cross[0] * invs;
98 out[1] = cross[1] * invs;
99 out[2] = cross[2] * invs;
118inline humanoid_pose keypoints_to_humanoid_pose(
119 const keypoint_stream& stream,
120 const HumanoidKeypointMap& map,
121 float confidence_threshold = 0.5f) noexcept
126 constexpr std::size_t N = std::size_t(humanoid_bone_index::Count);
127 std::array<std::array<float, 4>, N> q_world{};
128 std::array<bool, N> has_world{};
130 const auto& kps = stream.keypoints;
131 const int K = int(kps.size());
133 for(std::size_t b = 0; b < N; ++b)
135 has_world[b] =
false;
136 q_world[b] = {0.f, 0.f, 0.f, 1.f};
138 const auto& edge = map[b];
139 if(!edge.valid() || edge.parent_idx == edge.child_idx)
141 if(edge.parent_idx >= K || edge.child_idx >= K)
144 const auto& p = kps[std::size_t(edge.parent_idx)];
145 const auto& c = kps[std::size_t(edge.child_idx)];
146 if(p.confidence < confidence_threshold
147 || c.confidence < confidence_threshold)
150 float d[3] = {c.x - p.x, c.y - p.y, c.z - p.z};
151 const float len = std::sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
154 const float inv = 1.f / len;
155 d[0] *= inv; d[1] *= inv; d[2] *= inv;
157 const auto& rest = kHumanoidRestAxis[b];
158 shortest_arc(rest.data(), d, q_world[b].data());
164 for(std::size_t b = 0; b < N; ++b)
166 auto& bone = out.bones[b];
170 bone.qx = 0.f; bone.qy = 0.f; bone.qz = 0.f; bone.qw = 1.f;
174 const auto parent_idx = kHumanoidParent[b];
175 if(parent_idx == humanoid_bone_index::Count
176 || !has_world[std::size_t(parent_idx)])
183 bone.qx = q_world[b][0];
184 bone.qy = q_world[b][1];
185 bone.qz = q_world[b][2];
186 bone.qw = q_world[b][3];
191 quat_inv_xyzw(q_world[std::size_t(parent_idx)].data(), inv_parent);
193 quat_mul_xyzw(inv_parent, q_world[b].data(), local);
194 bone.qx = local[0]; bone.qy = local[1];
195 bone.qz = local[2]; bone.qw = local[3];
204 const auto& spine_edge = map[std::size_t(humanoid_bone_index::Spine)];
205 if(spine_edge.parent_idx >= 0 && spine_edge.parent_idx < K)
207 const auto& hip_kp = kps[std::size_t(spine_edge.parent_idx)];
208 if(hip_kp.confidence >= confidence_threshold)
210 out.hip_x = hip_kp.x;
211 out.hip_y = hip_kp.y;
212 out.hip_z = hip_kp.z;
232inline humanoid_pose trackers_to_humanoid_pose(
233 const tracker_bundle_6& t)
noexcept
240 humanoid_bone_index bone;
241 const tracker_pose* tr;
243 const Slot slots[] = {
244 {humanoid_bone_index::Hips, &t.hips},
245 {humanoid_bone_index::Head, &t.head},
246 {humanoid_bone_index::LeftHand, &t.left_hand},
247 {humanoid_bone_index::RightHand, &t.right_hand},
248 {humanoid_bone_index::LeftFoot, &t.left_foot},
249 {humanoid_bone_index::RightFoot, &t.right_foot},
253 constexpr std::size_t N = std::size_t(humanoid_bone_index::Count);
254 std::array<std::array<float, 4>, N> q_world{};
255 std::array<bool, N> has_world{};
256 for(std::size_t b = 0; b < N; ++b)
258 q_world[b] = {0.f, 0.f, 0.f, 1.f};
259 has_world[b] =
false;
262 for(
const auto& slot : slots)
264 if(slot.tr->validity < 0.5f)
266 const std::size_t idx = std::size_t(slot.bone);
267 q_world[idx] = {slot.tr->qx, slot.tr->qy, slot.tr->qz, slot.tr->qw};
268 has_world[idx] =
true;
275 for(std::size_t b = 0; b < N; ++b)
277 auto& bone = out.bones[b];
284 const auto parent_idx = kHumanoidParent[b];
285 if(parent_idx == humanoid_bone_index::Count
286 || !has_world[std::size_t(parent_idx)])
288 bone.qx = q_world[b][0]; bone.qy = q_world[b][1];
289 bone.qz = q_world[b][2]; bone.qw = q_world[b][3];
294 quat_inv_xyzw(q_world[std::size_t(parent_idx)].data(), inv_parent);
296 quat_mul_xyzw(inv_parent, q_world[b].data(), local);
297 bone.qx = local[0]; bone.qy = local[1];
298 bone.qz = local[2]; bone.qw = local[3];
304 if(t.hips.validity >= 0.5f)
306 out.hip_x = t.hips.x;
307 out.hip_y = t.hips.y;
308 out.hip_z = t.hips.z;