The open source OpenXR runtime
at prediction-2 359 lines 11 kB view raw
1// Copyright 2020-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Functions for manipulating a @ref xrt_relation_chain struct. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup aux_math 8 */ 9 10#include "util/u_misc.h" 11 12#include "math/m_api.h" 13#include "math/m_vec2.h" 14#include "math/m_vec3.h" 15#include "math/m_space.h" 16 17#include <stdio.h> 18#include <assert.h> 19 20 21/* 22 * 23 * Dump functions. 24 * 25 */ 26 27static void 28dump_relation(const struct xrt_space_relation *r) 29{ 30 fprintf(stderr, "%04x", r->relation_flags); 31 32 if (r->relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) { 33 fprintf(stderr, " P{%f %f %f}", r->pose.position.x, r->pose.position.y, r->pose.position.z); 34 } 35 36 if (r->relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) { 37 fprintf(stderr, " O{%f %f %f %f}", r->pose.orientation.x, r->pose.orientation.y, r->pose.orientation.z, 38 r->pose.orientation.w); 39 } 40 41 if (r->relation_flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT) { 42 fprintf(stderr, " LV{%f %f %f}", r->linear_velocity.x, r->linear_velocity.y, r->linear_velocity.z); 43 } 44 45 if (r->relation_flags & 46 XRT_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT) { 47 fprintf(stderr, " LA{%f %f %f}", r->linear_acceleration.x, 48 r->linear_acceleration.y, r->linear_acceleration.z); 49 } 50 51 if (r->relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) { 52 fprintf(stderr, " AV{%f %f %f}", r->angular_velocity.x, r->angular_velocity.y, r->angular_velocity.z); 53 } 54 55 if (r->relation_flags & 56 XRT_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT) { 57 fprintf(stderr, " AA{%f %f %f}", r->angular_acceleration.x, 58 r->angular_acceleration.y, r->angular_acceleration.z); 59 } 60 61 fprintf(stderr, "\n"); 62} 63 64static void 65dump_chain(const struct xrt_relation_chain *xrc) 66{ 67 fprintf(stderr, "%s %u\n", __func__, xrc->step_count); 68 for (uint32_t i = 0; i < xrc->step_count; i++) { 69 const struct xrt_space_relation *r = &xrc->steps[i]; 70 fprintf(stderr, "\t%2u: ", i); 71 dump_relation(r); 72 } 73} 74 75 76/* 77 * 78 * Helper functions. 79 * 80 */ 81 82static bool 83has_step_with_no_pose(const struct xrt_relation_chain *xrc) 84{ 85 const enum xrt_space_relation_flags pose_flags = (enum xrt_space_relation_flags)( 86 XRT_SPACE_RELATION_POSITION_VALID_BIT | XRT_SPACE_RELATION_ORIENTATION_VALID_BIT); 87 88 for (uint32_t i = 0; i < xrc->step_count; i++) { 89 const struct xrt_space_relation *r = &xrc->steps[i]; 90 if ((r->relation_flags & pose_flags) == 0) { 91 return true; 92 } 93 } 94 95 return false; 96} 97 98struct flags 99{ 100 unsigned int has_orientation : 1; 101 unsigned int has_position : 1; 102 unsigned int has_linear_velocity : 1; 103 unsigned int has_angular_velocity : 1; 104 unsigned int has_tracked_orientation : 1; 105 unsigned int has_tracked_position : 1; 106}; 107 108flags 109get_flags(const struct xrt_space_relation *r) 110{ 111 // clang-format off 112 flags flags = {}; 113 flags.has_orientation = (r->relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0; 114 flags.has_position = (r->relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) != 0; 115 flags.has_linear_velocity = (r->relation_flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT) != 0; 116 flags.has_angular_velocity = (r->relation_flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) != 0; 117 flags.has_tracked_orientation = (r->relation_flags & XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT) != 0; 118 flags.has_tracked_position = (r->relation_flags & XRT_SPACE_RELATION_POSITION_TRACKED_BIT) != 0; 119 // clang-format on 120 121 return flags; 122} 123 124static void 125make_valid_pose(flags flags, const struct xrt_pose *in_pose, struct xrt_pose *out_pose) 126{ 127 if (flags.has_orientation) { 128 out_pose->orientation = in_pose->orientation; 129 } else { 130 out_pose->orientation = XRT_QUAT_IDENTITY; 131 } 132 133 if (flags.has_position) { 134 out_pose->position = in_pose->position; 135 } else { 136 out_pose->position = XRT_VEC3_ZERO; 137 } 138} 139 140static void 141apply_relation(const struct xrt_space_relation *a, 142 const struct xrt_space_relation *b, 143 struct xrt_space_relation *out_relation) 144{ 145 flags af = get_flags(a); 146 flags bf = get_flags(b); 147 148 struct xrt_pose pose = XRT_POSE_IDENTITY; 149 struct xrt_vec3 linear_velocity = XRT_VEC3_ZERO; 150 struct xrt_vec3 angular_velocity = XRT_VEC3_ZERO; 151 152 153 /* 154 * Pose. 155 */ 156 157 struct xrt_pose body_pose = XRT_POSE_IDENTITY; // aka valid_a_pose 158 struct xrt_pose base_pose = XRT_POSE_IDENTITY; // aka valid_b_pose 159 160 // If either orientation or position component is not valid, make that component identity so that transforms 161 // work. The flags of the result are determined in nf and not taken from the result of the transform. 162 make_valid_pose(af, &a->pose, &body_pose); 163 make_valid_pose(bf, &b->pose, &base_pose); 164 165 166 // This is a band aid to make 3dof devices work until we have a real solution. 167 // A 3dof device may return a relation with only orientation valid/tracked and no position. 168 // 169 // Monado wants to apply a predefined offset to 3dof devices, giving them a position. 170 // 171 // But per the comment below "If either of the relations does not have a valid or tracked flag, the entire chain 172 // loses that flag". 173 // 174 // For now we upgrade every relation that only has an orientation, to also have a position. Note that 175 // make_valid_pose zeroed the position if has_position was not set originally, ensuring there are no garbage 176 // values propagated. 177 if (af.has_orientation && !af.has_position) { 178 af.has_position = true; 179 } 180 if (bf.has_orientation && !bf.has_position) { 181 bf.has_position = true; 182 } 183 184 185 // If either of the relations does not have a valid or tracked flag, the entire chain loses that flag. 186 flags nf = {}; 187 nf.has_orientation = af.has_orientation && bf.has_orientation; 188 nf.has_position = af.has_position && bf.has_position; 189 nf.has_tracked_orientation = af.has_tracked_orientation && bf.has_tracked_orientation; 190 nf.has_tracked_position = af.has_tracked_position && bf.has_tracked_position; 191 nf.has_linear_velocity = af.has_linear_velocity && bf.has_linear_velocity; 192 nf.has_angular_velocity = af.has_angular_velocity && bf.has_angular_velocity; 193 194 195 // Not already valid poses needed to be made valid because the transoformed pose would be undefined otherwise 196 // and we still want e.g. valid positions. 197 math_pose_transform(&base_pose, &body_pose, &pose); 198 199 200 /* 201 * Linear velocity. 202 */ 203 204 // We only need to bother with velocities if we know that we will pass them on. 205 if (nf.has_linear_velocity) { 206 struct xrt_vec3 tmp = XRT_VEC3_ZERO; 207 208 math_quat_rotate_vec3(&base_pose.orientation, // Base rotation 209 &a->linear_velocity, // In base space 210 &tmp); // Output 211 212 linear_velocity += tmp; 213 linear_velocity += b->linear_velocity; 214 } 215 216 217 /* 218 * Angular velocity. 219 */ 220 221 if (nf.has_angular_velocity) { 222 struct xrt_vec3 tmp = XRT_VEC3_ZERO; 223 224 math_quat_rotate_derivative(&base_pose.orientation, // Base rotation 225 &a->angular_velocity, // In base space 226 &tmp); // Output 227 228 angular_velocity += tmp; 229 angular_velocity += b->angular_velocity; 230 231 // handle tangential velocity AKA "lever arm" effect on velocity: 232 // an angular velocity at the origin produces a linear velocity everywhere else 233 struct xrt_vec3 rotated_position = XRT_VEC3_ZERO; 234 struct xrt_vec3 position = XRT_VEC3_ZERO; 235 struct xrt_quat orientation = XRT_QUAT_IDENTITY; 236 struct xrt_vec3 tangental_velocity = XRT_VEC3_ZERO; 237 238 position = body_pose.position; // In the base space 239 orientation = base_pose.orientation; // Base space 240 241 math_quat_rotate_vec3(&orientation, // Rotation 242 &position, // Vector 243 &rotated_position); // Result 244 245 math_vec3_cross(&b->angular_velocity, // A 246 &rotated_position, // B 247 &tangental_velocity); // Result 248 249 linear_velocity += tangental_velocity; 250 } 251 252 253 /* 254 * Flags. 255 */ 256 257 int new_flags = 0; 258 259 if (nf.has_orientation) { 260 new_flags |= XRT_SPACE_RELATION_ORIENTATION_VALID_BIT; 261 } 262 if (nf.has_position) { 263 new_flags |= XRT_SPACE_RELATION_POSITION_VALID_BIT; 264 } 265 if (nf.has_tracked_position) { 266 new_flags |= XRT_SPACE_RELATION_POSITION_TRACKED_BIT; 267 } 268 if (nf.has_tracked_orientation) { 269 new_flags |= XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT; 270 } 271 if (nf.has_linear_velocity) { 272 new_flags |= XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT; 273 } 274 if (nf.has_angular_velocity) { 275 new_flags |= XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT; 276 } 277 278 279 /* 280 * Write everything out. 281 */ 282 283 struct xrt_space_relation tmp = {}; 284 tmp.relation_flags = (enum xrt_space_relation_flags)new_flags; 285 tmp.pose = pose; 286 tmp.linear_velocity = linear_velocity; 287 tmp.angular_velocity = angular_velocity; 288 289 *out_relation = tmp; 290} 291 292 293/* 294 * 295 * Exported functions. 296 * 297 */ 298 299extern "C" void 300m_relation_chain_resolve(const struct xrt_relation_chain *xrc, struct xrt_space_relation *out_relation) 301{ 302 if (xrc->step_count == 0 || has_step_with_no_pose(xrc)) { 303 *out_relation = XRT_SPACE_RELATION_ZERO; 304 return; 305 } 306 307 struct xrt_space_relation r = xrc->steps[0]; 308 for (uint32_t i = 1; i < xrc->step_count; i++) { 309 apply_relation(&r, &xrc->steps[i], &r); 310 } 311 312#if 0 313 dump_chain(xrc); 314 fprintf(stderr, "\tRR: "); 315 dump_relation(&r); 316#else 317 (void)&dump_chain; 318#endif 319 320 // Ensure no errors have crept in. 321 math_quat_normalize(&r.pose.orientation); 322 323 *out_relation = r; 324} 325 326extern "C" void 327m_space_relation_invert(struct xrt_space_relation *relation, struct xrt_space_relation *out_relation) 328{ 329 assert(relation != NULL); 330 assert(out_relation != NULL); 331 332 out_relation->relation_flags = relation->relation_flags; 333 math_pose_invert(&relation->pose, &out_relation->pose); 334 out_relation->linear_velocity = m_vec3_mul_scalar(relation->linear_velocity, -1); 335 out_relation->angular_velocity = m_vec3_mul_scalar(relation->angular_velocity, -1); 336} 337 338extern "C" void 339m_space_relation_interpolate(struct xrt_space_relation *a, 340 struct xrt_space_relation *b, 341 float t, 342 enum xrt_space_relation_flags flags, 343 struct xrt_space_relation *out_relation) 344{ 345 out_relation->relation_flags = flags; 346 347 if (flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) { 348 math_quat_slerp(&a->pose.orientation, &b->pose.orientation, t, &out_relation->pose.orientation); 349 } 350 if (flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) { 351 out_relation->pose.position = m_vec3_lerp(a->pose.position, b->pose.position, t); 352 } 353 if (flags & XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT) { 354 out_relation->linear_velocity = m_vec3_lerp(a->linear_velocity, b->linear_velocity, t); 355 } 356 if (flags & XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) { 357 out_relation->angular_velocity = m_vec3_lerp(a->angular_velocity, b->angular_velocity, t); 358 } 359}