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