The open source OpenXR runtime
at main 478 lines 17 kB view raw
1// Copyright 2019-2020, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Wrapper around Mercury's parametric hand code, used by Index and OpenGloves to simulate hand tracking. 6 * @author Christoph Haag <christoph.haag@collabora.com> 7 * @author Moshi Turner <moshiturner@protonmail.com> 8 * @author Daniel Willmott <web@dan-w.com> 9 * @ingroup aux_util 10 */ 11 12#include "math/m_mathinclude.h" 13#include "util/u_hand_tracking.h" 14#include "xrt/xrt_defines.h" 15#include "u_hand_simulation.h" 16#include "math/m_api.h" 17#include "u_trace_marker.h" 18 19#define HAND_SIM_NUM_FINGERS 5 20 21// This is a lie for the thumb; we usually do the hidden metacarpal trick there 22#define HAND_SIM_NUM_JOINTS_IN_FINGER 5 23#define HAND_SIM_NUM_ORIENTATIONS_IN_FINGER 4 24 25struct translations55 26{ 27 struct xrt_vec3 t[HAND_SIM_NUM_FINGERS][HAND_SIM_NUM_JOINTS_IN_FINGER]; 28}; 29 30struct orientations54 31{ 32 struct xrt_quat q[HAND_SIM_NUM_FINGERS][HAND_SIM_NUM_ORIENTATIONS_IN_FINGER]; 33}; 34 35// For debugging. 36#if 0 37#include <iostream> 38#define assert_quat_length_1(q) \ 39 { \ 40 const T scale = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]; \ 41 if (abs(scale - T(1.0)) > 0.001) { \ 42 std::cout << "Length bad! " << scale << std::endl; \ 43 assert(false); \ 44 }; \ 45 } 46#else 47#define assert_quat_length_1(q) 48#endif 49 50static void 51eval_hand_set_rel_orientations(const struct u_hand_sim_hand *opt, struct orientations54 *rel_orientations) 52{ 53 54// Thumb MCP hidden orientation 55#if 0 56 Vec2<T> mcp_root_swing; 57 58 mcp_root_swing.x = rad<T>((T)(-10)); 59 mcp_root_swing.y = rad<T>((T)(-40)); 60 61 T mcp_root_twist = rad<T>((T)(-80)); 62 63 SwingTwistToQuaternion(mcp_root_swing, mcp_root_twist, rel_orientations.q[0][0]); 64 65 std::cout << "\n\n\n\nHIDDEN ORIENTATION\n"; 66 std::cout << std::setprecision(100); 67 std::cout << rel_orientations.q[0][0].w << std::endl; 68 std::cout << rel_orientations.q[0][0].x << std::endl; 69 std::cout << rel_orientations.q[0][0].y << std::endl; 70 std::cout << rel_orientations.q[0][0].z << std::endl; 71#else 72 // This should be exactly equivalent to the above 73 rel_orientations->q[0][0].w = 0.716990172863006591796875f; 74 rel_orientations->q[0][0].x = 0.1541481912136077880859375f; 75 rel_orientations->q[0][0].y = -0.31655871868133544921875f; 76 rel_orientations->q[0][0].z = -0.6016261577606201171875f; 77#endif 78 79 // Thumb MCP orientation 80 math_quat_from_swing_twist(&opt->thumb.metacarpal.swing, // 81 opt->thumb.metacarpal.twist, // 82 &rel_orientations->q[0][1]); 83 84 // Thumb curls 85 struct xrt_vec2 thumb_swing0 = {opt->thumb.rotations[0], 0.f}; 86 math_quat_from_swing(&thumb_swing0, &rel_orientations->q[0][2]); 87 88 struct xrt_vec2 thumb_swing1 = {opt->thumb.rotations[1], 0.f}; 89 math_quat_from_swing(&thumb_swing1, &rel_orientations->q[0][3]); 90 91 // Finger orientations 92 for (int i = 0; i < 4; i++) { 93 math_quat_from_swing_twist(&opt->finger[i].metacarpal.swing, // 94 opt->finger[i].metacarpal.twist, // 95 &rel_orientations->q[i + 1][0]); 96 97 math_quat_from_swing(&opt->finger[i].proximal_swing, // 98 &rel_orientations->q[i + 1][1]); 99 100 struct xrt_vec2 finger_swing0 = {opt->finger[i].rotations[0], 0.f}; 101 math_quat_from_swing(&finger_swing0, &rel_orientations->q[i + 1][2]); 102 struct xrt_vec2 finger_swing1 = {opt->finger[i].rotations[1], 0.f}; 103 math_quat_from_swing(&finger_swing1, &rel_orientations->q[i + 1][3]); 104 } 105} 106 107static inline void 108eval_hand_set_rel_translations(const struct u_hand_sim_hand *opt, struct translations55 *rel_translations) 109{ 110 // Basically, we're walking up rel_translations, writing strictly sequentially. Hopefully this is fast. 111 112 113 // Thumb metacarpal translation. 114 rel_translations->t[0][0] = (struct xrt_vec3){0.33097f, -0.1f, -0.25968f}; 115 116 // Comes after the invisible joint. 117 rel_translations->t[0][1] = (struct xrt_vec3){0.f, 0.f, 0.f}; 118 // prox, distal, tip 119 rel_translations->t[0][2] = (struct xrt_vec3){0.f, 0.f, -0.389626f}; 120 rel_translations->t[0][3] = (struct xrt_vec3){0.f, 0.f, -0.311176f}; 121 rel_translations->t[0][4] = (struct xrt_vec3){0.f, 0.f, -0.232195f}; 122 123 // What's the best place to put this? Here works, but is there somewhere we could put it where it gets accessed 124 // faster? 125 float finger_joint_lengths[4][4] = { 126 { 127 -0.66f, 128 -0.365719f, 129 -0.231581f, 130 -0.201790f, 131 }, 132 { 133 -0.645f, 134 -0.404486f, 135 -0.247749f, 136 -0.210121f, 137 }, 138 { 139 -0.58f, 140 -0.365639f, 141 -0.225666f, 142 -0.187089f, 143 }, 144 { 145 -0.52f, 146 -0.278197f, 147 -0.176178f, 148 -0.157566f, 149 }, 150 }; 151 152 // Index metacarpal 153 rel_translations->t[1][0] = (struct xrt_vec3){0.16926f, 0.f, -0.34437f}; 154 // Middle 155 rel_translations->t[2][0] = (struct xrt_vec3){0.034639f, 0.01f, -0.35573f}; 156 // Ring 157 rel_translations->t[3][0] = (struct xrt_vec3){-0.063625f, 0.005f, -0.34164f}; 158 // Little 159 rel_translations->t[4][0] = (struct xrt_vec3){-0.1509f, -0.005f, -0.30373f}; 160 161 // Index to little finger 162 for (int finger = 0; finger < 4; finger++) { 163 for (int i = 0; i < 4; i++) { 164 int bone = i + 1; 165 rel_translations->t[finger + 1][bone].x = 0.f; 166 rel_translations->t[finger + 1][bone].y = 0.f; 167 rel_translations->t[finger + 1][bone].z = finger_joint_lengths[finger][i]; 168 } 169 } 170} 171 172void 173eval_hand_with_orientation(const struct u_hand_sim_hand *opt, 174 bool is_right, 175 struct translations55 *translations_absolute, 176 struct orientations54 *orientations_absolute) 177 178{ 179 XRT_TRACE_MARKER(); 180 181 struct translations55 rel_translations; 182 struct orientations54 rel_orientations; 183 184 eval_hand_set_rel_orientations(opt, &rel_orientations); 185 186 eval_hand_set_rel_translations(opt, &rel_translations); 187 188 struct xrt_quat orientation_root = XRT_QUAT_IDENTITY; 189 190 // Get each joint's tracking-relative orientation by rotating its parent-relative orientation by the 191 // tracking-relative orientation of its parent. 192 for (size_t finger = 0; finger < HAND_SIM_NUM_FINGERS; finger++) { 193 struct xrt_quat *last_orientation = &orientation_root; 194 for (size_t bone = 0; bone < HAND_SIM_NUM_ORIENTATIONS_IN_FINGER; bone++) { 195 struct xrt_quat *rel_orientation = &rel_orientations.q[finger][bone]; 196 struct xrt_quat *out_orientation = &orientations_absolute->q[finger][bone]; 197 198 math_quat_rotate(last_orientation, rel_orientation, out_orientation); 199 last_orientation = out_orientation; 200 } 201 } 202 203 // Get each joint's tracking-relative position by rotating its parent-relative translation by the 204 // tracking-relative orientation of its parent, then adding that to its parent's tracking-relative position. 205 struct xrt_vec3 zero = XRT_VEC3_ZERO; 206 for (size_t finger = 0; finger < HAND_SIM_NUM_FINGERS; finger++) { 207 const struct xrt_vec3 *last_translation = &zero; 208 const struct xrt_quat *last_orientation = &orientation_root; 209 for (size_t bone = 0; bone < HAND_SIM_NUM_JOINTS_IN_FINGER; bone++) { 210 struct xrt_vec3 *out_translation = &translations_absolute->t[finger][bone]; 211 struct xrt_vec3 *rel_translation = &rel_translations.t[finger][bone]; 212 213 // rotate and scale 214 math_quat_rotate_vec3(last_orientation, rel_translation, out_translation); 215 math_vec3_scalar_mul(opt->hand_size, out_translation); 216 217 // If this is a right hand, mirror it. 218 if (is_right) { 219 out_translation->x *= -1; 220 } 221 222 out_translation->x += last_translation->x; 223 out_translation->y += last_translation->y; 224 out_translation->z += last_translation->z; 225 226 // Next iteration, the orientation to rotate by should be the tracking-relative orientation of 227 // this joint. 228 229 // If bone < 4 so we don't go over the end of orientations_absolute. I hope this gets optimized 230 // out anyway. 231 if (bone < 4) { 232 last_orientation = &orientations_absolute->q[finger][bone]; 233 // Ditto for translation 234 last_translation = out_translation; 235 } 236 } 237 } 238} 239 240static inline void 241zldtt_ori_right(const struct xrt_quat *orientation, struct xrt_quat *out) 242{ 243 struct xrt_quat tmp; 244 tmp.w = orientation->w; 245 tmp.x = orientation->x; 246 tmp.y = orientation->y; 247 tmp.z = orientation->z; 248 249 struct xrt_vec3 x = XRT_VEC3_UNIT_X; 250 struct xrt_vec3 z = XRT_VEC3_UNIT_Z; 251 252 math_quat_rotate_vec3(&tmp, &x, &x); 253 math_quat_rotate_vec3(&tmp, &z, &z); 254 255 // This is a very squashed change-of-basis from left-handed coordinate systems to right-handed coordinate 256 // systems: you multiply everything by (-1 0 0) then negate the X axis. 257 258 x.y *= -1; 259 x.z *= -1; 260 261 z.x *= -1; 262 263 math_quat_from_plus_x_z(&x, &z, out); 264} 265 266 267static inline void 268zldtt(const struct xrt_vec3 *trans, const struct xrt_quat *orientation, bool is_right, struct xrt_space_relation *out) 269{ 270 271 out->relation_flags = (enum xrt_space_relation_flags)( 272 XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | 273 XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT); 274 out->pose.position.x = trans->x; 275 out->pose.position.y = trans->y; 276 out->pose.position.z = trans->z; 277 278 if (is_right) { 279 zldtt_ori_right(orientation, &out->pose.orientation); 280 } else { 281 out->pose.orientation = *orientation; 282 } 283} 284 285 286static void 287our_eval_to_viz_hand(struct u_hand_sim_hand *opt, 288 struct translations55 *translations_absolute, 289 struct orientations54 *orientations_absolute, 290 bool is_right, 291 struct xrt_hand_joint_set *out_viz_hand) 292{ 293 XRT_TRACE_MARKER(); 294 295 eval_hand_with_orientation(opt, is_right, translations_absolute, orientations_absolute); 296 297 struct xrt_quat final_wrist_orientation = XRT_QUAT_IDENTITY; 298 299 int joint_acc_idx = 0; 300 301 // Palm. 302 struct xrt_vec3 palm_position; 303 palm_position.x = (translations_absolute->t[2][0].x + translations_absolute->t[2][1].x) / 2; 304 palm_position.y = (translations_absolute->t[2][0].y + translations_absolute->t[2][1].y) / 2; 305 palm_position.z = (translations_absolute->t[2][0].z + translations_absolute->t[2][1].z) / 2; 306 307 struct xrt_quat *palm_orientation = &orientations_absolute->q[2][0]; 308 309 zldtt(&palm_position, palm_orientation, is_right, 310 &out_viz_hand->values.hand_joint_set_default[joint_acc_idx++].relation); 311 312 // Wrist. 313 zldtt(&opt->wrist_pose.pose.position, &final_wrist_orientation, is_right, 314 &out_viz_hand->values.hand_joint_set_default[joint_acc_idx++].relation); 315 316 for (int finger = 0; finger < 5; finger++) { 317 for (int joint = 0; joint < 5; joint++) { 318 // This one is necessary 319 if (finger == 0 && joint == 0) { 320 continue; 321 } 322 struct xrt_quat *orientation; 323 if (joint != 4) { 324 orientation = &orientations_absolute->q[finger][joint]; 325 } else { 326 orientation = &orientations_absolute->q[finger][joint - 1]; 327 } 328 zldtt(&translations_absolute->t[finger][joint], orientation, is_right, 329 &out_viz_hand->values.hand_joint_set_default[joint_acc_idx++].relation); 330 } 331 } 332 out_viz_hand->is_active = true; 333} 334 335static void 336hand_sim_hand_init(struct u_hand_sim_hand *out_opt, enum xrt_hand xhand, const struct xrt_space_relation *root_pose) 337{ 338 out_opt->hand_size = 0.095f; 339 340 out_opt->is_right = xhand == XRT_HAND_RIGHT; 341 out_opt->hand_pose = *root_pose; 342 343 for (int i = 0; i < 4; i++) { 344 //!@todo needed? 345 out_opt->finger[i].metacarpal.swing.x = 0.f; 346 out_opt->finger[i].metacarpal.twist = 0.f; 347 348 out_opt->finger[i].proximal_swing.x = DEG_TO_RAD(15); 349 out_opt->finger[i].rotations[0] = DEG_TO_RAD(-5); 350 out_opt->finger[i].rotations[1] = DEG_TO_RAD(-5); 351 } 352 353 out_opt->thumb.metacarpal.swing.x = 0.f; 354 out_opt->thumb.metacarpal.swing.y = 0.f; 355 out_opt->thumb.metacarpal.twist = 0.f; 356 357 out_opt->thumb.rotations[0] = DEG_TO_RAD(10); 358 out_opt->thumb.rotations[1] = DEG_TO_RAD(10); 359 360 out_opt->finger[0].metacarpal.swing.y = -0.19f; 361 out_opt->finger[1].metacarpal.swing.y = 0.f; 362 out_opt->finger[2].metacarpal.swing.y = 0.19f; 363 out_opt->finger[3].metacarpal.swing.y = 0.38f; 364 365 out_opt->finger[0].proximal_swing.y = -0.01f; 366 out_opt->finger[1].proximal_swing.y = 0.f; 367 out_opt->finger[2].proximal_swing.y = 0.01f; 368 out_opt->finger[3].proximal_swing.y = 0.02f; 369} 370 371 372void 373u_hand_sim_simulate(struct u_hand_sim_hand *hand_ptr, struct xrt_hand_joint_set *out_set) 374{ 375 struct translations55 translations; 376 struct orientations54 orientations; 377 378 eval_hand_with_orientation(hand_ptr, hand_ptr->is_right, &translations, &orientations); 379 380 our_eval_to_viz_hand(hand_ptr, &translations, &orientations, hand_ptr->is_right, out_set); 381 382 u_hand_joints_apply_joint_width(out_set); 383 384 out_set->hand_pose = hand_ptr->hand_pose; 385 386 out_set->hand_pose.relation_flags = (enum xrt_space_relation_flags)( 387 XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT | 388 XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_POSITION_TRACKED_BIT); 389 390 out_set->is_active = true; 391} 392 393void 394u_hand_sim_simulate_for_valve_index_knuckles(const struct u_hand_tracking_curl_values *values, 395 enum xrt_hand xhand, 396 const struct xrt_space_relation *root_pose, 397 struct xrt_hand_joint_set *out_set) 398{ 399 struct u_hand_sim_hand hand; 400 401 hand_sim_hand_init(&hand, xhand, root_pose); 402 hand.wrist_pose.pose.position.x = 0.f; 403 hand.wrist_pose.pose.position.y = 0.f; 404 hand.wrist_pose.pose.position.z = 0.f; 405 406 hand.hand_size = 0.095; 407 408 // Thumb 409 hand.thumb.metacarpal.swing.x += values->thumb * 0.08f; 410 hand.thumb.metacarpal.swing.y += -0.35f; 411 hand.thumb.metacarpal.twist = 0; 412 hand.thumb.rotations[0] += values->thumb * -1.57f; 413 hand.thumb.rotations[1] += values->thumb * -1.4f; 414 415 // Index finger - this is treated differently on Valve Knuckles controllers so the pinch gesture feels good 416 float finger_values[4] = {values->index, values->middle, values->ring, values->little}; 417 418 { 419 int finger = 0; 420 float val_turn = finger_values[finger] * -1.1f; 421 hand.finger[finger].proximal_swing.x = val_turn * 1.3f; 422 hand.finger[finger].rotations[0] = val_turn; 423 hand.finger[finger].rotations[1] = val_turn; 424 } 425 426 for (int finger = 1; finger < 4; finger++) { 427 float val_turn = finger_values[finger] * -1.1f * 1.3f; 428 hand.finger[finger].proximal_swing.x = val_turn * 1.3f; 429 hand.finger[finger].rotations[0] = val_turn * 1.0f; 430 hand.finger[finger].rotations[1] = val_turn * 0.4f; 431 } 432 433 u_hand_sim_simulate(&hand, out_set); 434} 435 436static void 437u_hand_sim_apply_generic_finger_transform(const struct u_hand_tracking_finger_value *finger_value, 438 struct u_hand_sim_finger *out_finger) 439{ 440 out_finger->metacarpal.swing.x = finger_value->joint_curls[0] * -1.f; 441 442 out_finger->proximal_swing.x = finger_value->joint_curls[1] * -1.f; 443 out_finger->proximal_swing.y = finger_value->splay; 444 445 out_finger->rotations[0] = finger_value->joint_curls[2] * -1.f; 446 out_finger->rotations[1] = finger_value->joint_curls[3] * -1.f; 447} 448 449void 450u_hand_sim_simulate_generic(const struct u_hand_tracking_values *values, 451 enum xrt_hand xhand, 452 const struct xrt_space_relation *root_pose, 453 struct xrt_hand_joint_set *out_set) 454{ 455 struct u_hand_sim_hand hand; 456 457 hand_sim_hand_init(&hand, xhand, root_pose); 458 hand.wrist_pose.pose.position.x = 0.f; 459 hand.wrist_pose.pose.position.y = 0.f; 460 hand.wrist_pose.pose.position.z = 0.f; 461 462 hand.hand_size = 0.095; 463 464 // Thumb 465 hand.thumb.metacarpal.swing.x += values->thumb.joint_curls[0] * 0.08f; // curl 466 467 hand.thumb.metacarpal.swing.y += values->thumb.splay; // splay 468 hand.thumb.metacarpal.twist = 0; 469 hand.thumb.rotations[0] += values->thumb.joint_curls[1] * -1.f; 470 hand.thumb.rotations[1] += values->thumb.joint_curls[2] * -1.f; 471 472 u_hand_sim_apply_generic_finger_transform(&values->little, &hand.finger[3]); 473 u_hand_sim_apply_generic_finger_transform(&values->ring, &hand.finger[2]); 474 u_hand_sim_apply_generic_finger_transform(&values->middle, &hand.finger[1]); 475 u_hand_sim_apply_generic_finger_transform(&values->index, &hand.finger[0]); 476 477 u_hand_sim_simulate(&hand, out_set); 478}