xrt: Implement & hook up hand joint tracking infrastructure

Include <inttypes.h> to satisfy older compilers
This commit is contained in:
Christoph Haag 2020-10-12 02:09:19 +02:00
parent 2a07c1034e
commit 256e2c68d8
22 changed files with 605 additions and 5 deletions

View file

@ -26,6 +26,7 @@ EXTENSIONS = (
['XR_EXTX_overlay'],
['XR_MNDX_egl_enable', 'XR_USE_PLATFORM_EGL', 'XR_USE_GRAPHICS_API_OPENGL'],
['XR_MNDX_ball_on_a_stick_controller'],
['XR_EXT_hand_tracking']
)
ROOT = Path(__file__).resolve().parent.parent

View file

@ -95,6 +95,30 @@ math_vec3_validate(const struct xrt_vec3 *vec3);
void
math_vec3_accum(const struct xrt_vec3 *additional, struct xrt_vec3 *inAndOut);
/*!
* Subtract from a vector in-place.
*
* Logically, *inAndOut -= *subtrahend
* OK if the two arguments are the same addresses.
*
* @relates xrt_vec3
* @ingroup aux_math
*/
void
math_vec3_subtract(const struct xrt_vec3 *subtrahend,
struct xrt_vec3 *inAndOut);
/*!
* Multiply a vector in-place.
*
* Logically, *inAndOut *= scalar
*
* @relates xrt_vec3
* @ingroup aux_math
*/
void
math_vec3_scalar_mul(float scalar, struct xrt_vec3 *inAndOut);
/*!
* Cross product of a vector.
*

View file

@ -86,6 +86,23 @@ math_vec3_accum(const struct xrt_vec3 *additional, struct xrt_vec3 *inAndOut)
map_vec3(*inAndOut) += map_vec3(*additional);
}
extern "C" void
math_vec3_subtract(const struct xrt_vec3 *subtrahend, struct xrt_vec3 *inAndOut)
{
assert(subtrahend != NULL);
assert(inAndOut != NULL);
map_vec3(*inAndOut) -= map_vec3(*subtrahend);
}
extern "C" void
math_vec3_scalar_mul(float scalar, struct xrt_vec3 *inAndOut)
{
assert(inAndOut != NULL);
map_vec3(*inAndOut) *= scalar;
}
extern "C" void
math_vec3_cross(const struct xrt_vec3 *l,
const struct xrt_vec3 *r,

View file

@ -454,6 +454,8 @@ enum xrt_input_type
XRT_INPUT_TYPE_BOOLEAN = 0x04,
//! A tracked pose
XRT_INPUT_TYPE_POSE = 0x05,
//! A tracked hand
XRT_INPUT_TYPE_HAND_TRACKING = 0x06,
// clang-format on
};
@ -492,6 +494,7 @@ enum xrt_input_name
// clang-format off
XRT_INPUT_GENERIC_HEAD_POSE = XRT_INPUT_NAME(0x0000, POSE),
XRT_INPUT_GENERIC_HEAD_DETECT = XRT_INPUT_NAME(0x0001, BOOLEAN),
XRT_INPUT_GENERIC_HAND_TRACKING_DEFAULT_SET = XRT_INPUT_NAME(0x0002, HAND_TRACKING),
XRT_INPUT_PSMV_PS_CLICK = XRT_INPUT_NAME(0x0020, BOOLEAN),
XRT_INPUT_PSMV_MOVE_CLICK = XRT_INPUT_NAME(0x0021, BOOLEAN),
@ -560,6 +563,103 @@ enum xrt_input_name
// clang-format on
};
/*!
* Number of joints in a hand. Corresponds to XR_HAND_JOINT_COUNT_EXT.
*
* @see xrt_hand_joint
* @ingroup xrt_iface
*/
#define XRT_HAND_JOINT_COUNT 26
/*!
* Number of joints in a hand. Corresponds to XrHandJointEXT.
*
* @ingroup xrt_iface
*/
enum xrt_hand_joint
{
XRT_HAND_JOINT_PALM = 0,
XRT_HAND_JOINT_WRIST = 1,
XRT_HAND_JOINT_THUMB_METACARPAL = 2,
XRT_HAND_JOINT_THUMB_PROXIMAL = 3,
XRT_HAND_JOINT_THUMB_DISTAL = 4,
XRT_HAND_JOINT_THUMB_TIP = 5,
XRT_HAND_JOINT_INDEX_METACARPAL = 6,
XRT_HAND_JOINT_INDEX_PROXIMAL = 7,
XRT_HAND_JOINT_INDEX_INTERMEDIATE = 8,
XRT_HAND_JOINT_INDEX_DISTAL = 9,
XRT_HAND_JOINT_INDEX_TIP = 10,
XRT_HAND_JOINT_MIDDLE_METACARPAL = 11,
XRT_HAND_JOINT_MIDDLE_PROXIMAL = 12,
XRT_HAND_JOINT_MIDDLE_INTERMEDIATE = 13,
XRT_HAND_JOINT_MIDDLE_DISTAL = 14,
XRT_HAND_JOINT_MIDDLE_TIP = 15,
XRT_HAND_JOINT_RING_METACARPAL = 16,
XRT_HAND_JOINT_RING_PROXIMAL = 17,
XRT_HAND_JOINT_RING_INTERMEDIATE = 18,
XRT_HAND_JOINT_RING_DISTAL = 19,
XRT_HAND_JOINT_RING_TIP = 20,
XRT_HAND_JOINT_LITTLE_METACARPAL = 21,
XRT_HAND_JOINT_LITTLE_PROXIMAL = 22,
XRT_HAND_JOINT_LITTLE_INTERMEDIATE = 23,
XRT_HAND_JOINT_LITTLE_DISTAL = 24,
XRT_HAND_JOINT_LITTLE_TIP = 25,
XRT_HAND_JOINT_MAX_ENUM = 0x7FFFFFFF
};
/*!
* Enumeration for left and right hand.
*
* @ingroup xrt_iface
*/
enum xrt_hand
{
XRT_HAND_LEFT = 0,
XRT_HAND_RIGHT = 1
};
/*!
* Location of a single hand joint. Corresponds to XrHandJointLocationEXT.
*
* @ingroup xrt_iface
*/
struct xrt_hand_joint_value
{
struct xrt_space_relation relation;
float radius;
};
/*!
* Number of fingers on a hand.
*
* @ingroup xrt_iface
*/
#define XRT_FINGER_COUNT 5
/*!
* Names for fingers on a hand.
*
* @ingroup xrt_iface
*/
enum xrt_finger
{
XRT_FINGER_LITTLE = 0,
XRT_FINGER_RING,
XRT_FINGER_MIDDLE,
XRT_FINGER_INDEX,
XRT_FINGER_THUMB
};
/*!
* Joint set type used for hand tracking. Corresponds to XrHandJointSetEXT.
*
* @ingroup xrt_iface
*/
union xrt_hand_joint_set {
struct xrt_hand_joint_value
hand_joint_set_default[XRT_HAND_JOINT_COUNT];
};
/*!
* A union of all input types.
*

View file

@ -206,6 +206,7 @@ struct xrt_device
bool orientation_tracking_supported;
bool position_tracking_supported;
bool hand_tracking_supported;
/*!
* Update any attached inputs.
@ -238,6 +239,30 @@ struct xrt_device
uint64_t at_timestamp_ns,
struct xrt_space_relation *out_relation);
/*!
* Get relationship of hand joints to the tracking origin space as
* the base space. It is the responsibility of the device driver to do
* any prediction, there are helper functions available for this.
*
* The timestamps are system monotonic timestamps, such as returned by
* os_monotonic_get_ns().
*
* @param[in] xdev The device.
* @param[in] name Some devices may have multiple poses on
* them, select the one using this field. For
* hand tracking use @p
* XRT_INPUT_GENERIC_HAND_TRACKING_DEFAULT_SET.
* @param[in] at_timestamp_ns If the device can predict or has a history
* of positions, this is when the caller
* wants the pose to be from.
* @param[out] out_relation The relation read from the device.
*
* @see xrt_input_name
*/
void (*get_hand_tracking)(struct xrt_device *xdev,
enum xrt_input_name name,
uint64_t at_timestamp_ns,
union xrt_hand_joint_set *out_value);
/*!
* Set a output value.
*
@ -312,6 +337,20 @@ xrt_device_get_tracked_pose(struct xrt_device *xdev,
out_relation);
}
/*!
* Helper function for @ref xrt_device::get_hand_tracking.
*
* @public @memberof xrt_device
*/
static inline void
xrt_device_get_hand_tracking(struct xrt_device *xdev,
enum xrt_input_name name,
uint64_t requested_timestamp_ns,
union xrt_hand_joint_set *out_value)
{
xdev->get_hand_tracking(xdev, name, requested_timestamp_ns, out_value);
}
/*!
* Helper function for @ref xrt_device::set_output.
*

View file

@ -104,6 +104,21 @@ ipc_client_device_get_tracked_pose(struct xrt_device *xdev,
}
}
void
ipc_client_device_get_hand_tracking(struct xrt_device *xdev,
enum xrt_input_name name,
uint64_t at_timestamp_ns,
union xrt_hand_joint_set *out_value)
{
struct ipc_client_device *icd = ipc_client_device(xdev);
xrt_result_t r = ipc_call_device_get_hand_tracking(
icd->ipc_c, icd->device_id, name, at_timestamp_ns, out_value);
if (r != XRT_SUCCESS) {
IPC_ERROR(icd->ipc_c, "IPC: Error sending input update!");
}
}
static void
ipc_client_device_get_view_pose(struct xrt_device *xdev,
struct xrt_vec3 *eye_relation,
@ -147,6 +162,7 @@ ipc_client_device_create(struct ipc_connection *ipc_c,
icd->ipc_c = ipc_c;
icd->base.update_inputs = ipc_client_device_update_inputs;
icd->base.get_tracked_pose = ipc_client_device_get_tracked_pose;
icd->base.get_hand_tracking = ipc_client_device_get_hand_tracking;
icd->base.get_view_pose = ipc_client_device_get_view_pose;
icd->base.set_output = ipc_client_device_set_output;
icd->base.destroy = ipc_client_device_destroy;
@ -176,6 +192,10 @@ ipc_client_device_create(struct ipc_connection *ipc_c,
u_var_add_root(icd, icd->base.str, true);
u_var_add_ro_u32(icd, &icd->device_id, "device_id");
icd->base.orientation_tracking_supported =
isdev->orientation_tracking_supported;
icd->base.hand_tracking_supported = isdev->hand_tracking_supported;
icd->base.device_type = isdev->device_type;
return &icd->base;
}

View file

@ -202,6 +202,7 @@ ipc_client_hmd_create(struct ipc_connection *ipc_c,
ich->base.position_tracking_supported =
isdev->position_tracking_supported;
ich->base.device_type = isdev->device_type;
ich->base.hand_tracking_supported = isdev->hand_tracking_supported;
return &ich->base;
}

View file

@ -79,6 +79,7 @@ struct ipc_shared_device
bool orientation_tracking_supported;
bool position_tracking_supported;
bool hand_tracking_supported;
};
/*!

View file

@ -593,6 +593,23 @@ ipc_handle_device_get_tracked_pose(volatile struct ipc_client_state *ics,
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_device_get_hand_tracking(volatile struct ipc_client_state *ics,
uint32_t id,
enum xrt_input_name name,
uint64_t at_timestamp,
union xrt_hand_joint_set *out_value)
{
// To make the code a bit more readable.
uint32_t device_id = id;
struct xrt_device *xdev = get_xdev(ics, device_id);
// Get the pose.
xrt_device_get_hand_tracking(xdev, name, at_timestamp, out_value);
return XRT_SUCCESS;
}
xrt_result_t
ipc_handle_device_get_view_pose(volatile struct ipc_client_state *ics,
uint32_t id,

View file

@ -199,6 +199,7 @@ init_shm(struct ipc_server *s)
isdev->position_tracking_supported =
xdev->position_tracking_supported;
isdev->device_type = xdev->device_type;
isdev->hand_tracking_supported = xdev->hand_tracking_supported;
// Is this a HMD?
if (xdev->hmd != NULL) {

View file

@ -180,6 +180,17 @@
]
},
"device_get_hand_tracking": {
"in": [
{"name": "id", "type": "uint32_t"},
{"name": "name", "type": "enum xrt_input_name"},
{"name": "at_timestamp", "type": "uint64_t"}
],
"out": [
{"name": "value", "type": "union xrt_hand_joint_set"}
]
},
"device_get_view_pose": {
"in": [
{"name": "id", "type": "uint32_t"},

View file

@ -536,6 +536,21 @@ XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrStopHapticFeedback(XrSession session,
const XrHapticActionInfo *hapticActionInfo);
//! OpenXR API function @ep{xrCreateHandTrackerEXT}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrCreateHandTrackerEXT(XrSession session,
const XrHandTrackerCreateInfoEXT *createInfo,
XrHandTrackerEXT *handTracker);
//! OpenXR API function @ep{xrDestroyHandTrackerEXT}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrDestroyHandTrackerEXT(XrHandTrackerEXT handTracker);
//! OpenXR API function @ep{xrLocateHandJointsEXT}
XRAPI_ATTR XrResult XRAPI_CALL
oxr_xrLocateHandJointsEXT(XrHandTrackerEXT handTracker,
const XrHandJointsLocateInfoEXT *locateInfo,
XrHandJointLocationsEXT *locations);
/*!
* @}

View file

@ -224,6 +224,10 @@ handle_non_null(struct oxr_instance *inst,
ENTRY_IF_EXT(xrThermalGetTemperatureTrendEXT, EXT_thermal_query)
#endif // OXR_HAVE_EXT_thermal_query
ENTRY_IF_EXT(xrCreateHandTrackerEXT, EXT_hand_tracking);
ENTRY_IF_EXT(xrDestroyHandTrackerEXT, EXT_hand_tracking);
ENTRY_IF_EXT(xrLocateHandJointsEXT, EXT_hand_tracking);
#if 0
#ifdef OXR_HAVE_EXT_debug_utils
ENTRY_IF_EXT(xrSetDebugUtilsObjectNameEXT, EXT_debug_utils);

View file

@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "xrt/xrt_compiler.h"
@ -21,7 +22,7 @@
#include "oxr_api_funcs.h"
#include "oxr_api_verify.h"
#include "oxr_handle.h"
XrResult
@ -256,4 +257,131 @@ oxr_xrThermalGetTemperatureTrendEXT(
return oxr_error(&log, XR_ERROR_HANDLE_INVALID, "Not implemented");
}
/*
*
* XR_EXT_hand_tracking
*
*/
static XrResult
oxr_hand_tracker_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb)
{
struct oxr_hand_tracker *hand_tracker = (struct oxr_hand_tracker *)hb;
free(hand_tracker);
return XR_SUCCESS;
}
XrResult
oxr_hand_tracker_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrHandTrackerCreateInfoEXT *createInfo,
struct oxr_hand_tracker **out_hand_tracker)
{
if (!oxr_system_get_hand_tracking_support(log, sess->sys->inst)) {
return oxr_error(log, XR_ERROR_FEATURE_UNSUPPORTED,
"System does not support hand tracking");
}
struct oxr_hand_tracker *hand_tracker = NULL;
OXR_ALLOCATE_HANDLE_OR_RETURN(log, hand_tracker, OXR_XR_DEBUG_HTRACKER,
oxr_hand_tracker_destroy_cb,
&sess->handle);
hand_tracker->sess = sess;
hand_tracker->hand = createInfo->hand;
hand_tracker->hand_joint_set = createInfo->handJointSet;
*out_hand_tracker = hand_tracker;
return XR_SUCCESS;
}
XrResult
oxr_xrCreateHandTrackerEXT(XrSession session,
const XrHandTrackerCreateInfoEXT *createInfo,
XrHandTrackerEXT *handTracker)
{
struct oxr_hand_tracker *hand_tracker = NULL;
struct oxr_session *sess = NULL;
struct oxr_logger log;
XrResult ret;
OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
"xrCreateHandTrackerEXT");
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, createInfo,
XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT);
OXR_VERIFY_ARG_NOT_NULL(&log, handTracker);
OXR_VERIFY_EXTENSION(&log, sess->sys->inst, EXT_hand_tracking);
if (createInfo->hand != XR_HAND_LEFT_EXT &&
createInfo->hand != XR_HAND_RIGHT_EXT) {
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
"Invalid hand value %d\n", createInfo->hand);
}
if (createInfo->handJointSet != XR_HAND_JOINT_SET_DEFAULT_EXT) {
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
"Invalid handJointSet value %d\n",
createInfo->handJointSet);
}
ret = oxr_hand_tracker_create(&log, sess, createInfo, &hand_tracker);
if (ret != XR_SUCCESS) {
return ret;
}
*handTracker = oxr_hand_tracker_to_openxr(hand_tracker);
return XR_SUCCESS;
}
XrResult
oxr_xrDestroyHandTrackerEXT(XrHandTrackerEXT handTracker)
{
struct oxr_hand_tracker *hand_tracker;
struct oxr_logger log;
OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(&log, handTracker, hand_tracker,
"xrDestroyHandTrackerEXT");
return oxr_handle_destroy(&log, &hand_tracker->handle);
}
XrResult
oxr_xrLocateHandJointsEXT(XrHandTrackerEXT handTracker,
const XrHandJointsLocateInfoEXT *locateInfo,
XrHandJointLocationsEXT *locations)
{
struct oxr_hand_tracker *hand_tracker;
struct oxr_space *spc;
struct oxr_logger log;
OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(&log, handTracker, hand_tracker,
"xrLocateHandJointsEXT");
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, locateInfo,
XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT);
OXR_VERIFY_ARG_TYPE_AND_NOT_NULL(&log, locations,
XR_TYPE_HAND_JOINT_LOCATIONS_EXT);
OXR_VERIFY_SPACE_NOT_NULL(&log, locateInfo->baseSpace, spc);
if (locateInfo->time <= (XrTime)0) {
return oxr_error(&log, XR_ERROR_TIME_INVALID,
"(time == %" PRIi64 ") is not a valid time.",
locateInfo->time);
}
if (hand_tracker->hand_joint_set == XR_HAND_JOINT_SET_DEFAULT_EXT) {
if (locations->jointCount != XR_HAND_JOINT_COUNT_EXT) {
return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
"joint count must be %d, not %d\n",
XR_HAND_JOINT_COUNT_EXT,
locations->jointCount);
}
};
return oxr_session_hand_joints(&log, hand_tracker, locateInfo,
locations);
}
#endif

View file

@ -72,6 +72,8 @@ extern "C" {
_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_swapchain, SWAPCHAIN, name, new_thing->sess->sys->inst)
#define OXR_VERIFY_ACTIONSET_AND_INIT_LOG(log, thing, new_thing, name) \
_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_action_set, ACTIONSET, name, new_thing->inst)
#define OXR_VERIFY_HAND_TRACKER_AND_INIT_LOG(log, thing, new_thing, name) \
_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, oxr_hand_tracker, HTRACKER, name, new_thing->sess->sys->inst)
#define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, oxr_instance, INSTANCE);
#define OXR_VERIFY_MESSENGER_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, oxr_messenger, MESSENGER);

View file

@ -216,6 +216,18 @@
#define OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_)
#endif
/*
* XR_EXT_hand_tracking
*/
#if defined(XR_EXT_hand_tracking)
#define OXR_HAVE_EXT_hand_tracking
#define OXR_EXTENSION_SUPPORT_EXT_hand_tracking(_) \
_(EXT_hand_tracking, EXT_HAND_TRACKING)
#else
#define OXR_EXTENSION_SUPPORT_EXT_hand_tracking(_)
#endif
// end of GENERATED per-extension defines - do not modify - used by scripts
/*!
@ -255,5 +267,6 @@
OXR_EXTENSION_SUPPORT_MND_swapchain_usage_input_attachment_bit(_) \
OXR_EXTENSION_SUPPORT_EXTX_overlay(_) \
OXR_EXTENSION_SUPPORT_MNDX_egl_enable(_) \
OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_)
OXR_EXTENSION_SUPPORT_MNDX_ball_on_a_stick_controller(_) \
OXR_EXTENSION_SUPPORT_EXT_hand_tracking(_)
// clang-format on

View file

@ -948,6 +948,9 @@ oxr_input_combine_input(struct oxr_session *sess,
case XRT_INPUT_TYPE_POSE:
// shouldn't be possible to get here
break;
case XRT_INPUT_TYPE_HAND_TRACKING:
// shouldn't be possible to get here
break;
}
}

View file

@ -84,6 +84,7 @@ extern "C" {
#define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0")
#define OXR_XR_DEBUG_SOURCESET (*(uint64_t *)"oxrsrcs\0")
#define OXR_XR_DEBUG_SOURCE (*(uint64_t *)"oxrsrc_\0")
#define OXR_XR_DEBUG_HTRACKER (*(uint64_t *)"oxrhtra\0")
// clang-format on
@ -114,6 +115,7 @@ struct oxr_binding;
struct oxr_interaction_profile;
struct oxr_action_set_ref;
struct oxr_action_ref;
struct oxr_hand_tracker;
#define XRT_MAX_HANDLE_CHILDREN 256
#define OXR_MAX_SWAPCHAIN_IMAGES 8
@ -344,6 +346,17 @@ oxr_action_set_to_openxr(struct oxr_action_set *act_set)
return XRT_CAST_PTR_TO_OXR_HANDLE(XrActionSet, act_set);
}
/*!
* To go back to a OpenXR object.
*
* @relates oxr_hand_tracker
*/
static inline XrHandTrackerEXT
oxr_hand_tracker_to_openxr(struct oxr_hand_tracker *hand_tracker)
{
return XRT_CAST_PTR_TO_OXR_HANDLE(XrHandTrackerEXT, hand_tracker);
}
/*!
* To go back to a OpenXR object.
*
@ -498,6 +511,15 @@ oxr_action_stop_haptic_feedback(struct oxr_logger *log,
uint32_t act_key,
struct oxr_sub_paths sub_paths);
/*!
* @public @memberof oxr_instance
*/
XrResult
oxr_hand_tracker_create(struct oxr_logger *log,
struct oxr_session *sess,
const XrHandTrackerCreateInfoEXT *createInfo,
struct oxr_hand_tracker **out_hand_tracker);
/*!
* @}
*/
@ -656,6 +678,11 @@ oxr_session_frame_end(struct oxr_logger *log,
struct oxr_session *sess,
const XrFrameEndInfo *frameEndInfo);
XrResult
oxr_session_hand_joints(struct oxr_logger *log,
struct oxr_hand_tracker *hand_tracker,
const XrHandJointsLocateInfoEXT *locateInfo,
XrHandJointLocationsEXT *locations);
/*
*
@ -703,6 +730,9 @@ oxr_space_ref_relation(struct oxr_logger *log,
bool
initial_head_relation_valid(struct oxr_session *sess);
XrSpaceLocationFlags
xrt_to_xr_space_location_flags(enum xrt_space_relation_flags relation_flags);
bool
global_to_local_space(struct oxr_session *sess, struct xrt_space_relation *rel);
@ -820,6 +850,9 @@ oxr_system_enumerate_view_conf_views(
uint32_t *viewCountOutput,
XrViewConfigurationView *views);
bool
oxr_system_get_hand_tracking_support(struct oxr_logger *log,
struct oxr_instance *inst);
/*
*
@ -898,6 +931,17 @@ oxr_xdev_get_space_relation(struct oxr_logger *log,
XrTime at_time,
struct xrt_space_relation *out_relation);
/*!
* Returns the hand tracking value of the named input from the device.
* Does NOT apply tracking origin offset to each joint.
*/
void
oxr_xdev_get_hand_tracking_at(struct oxr_logger *log,
struct oxr_instance *inst,
struct xrt_device *xdev,
enum xrt_input_name name,
XrTime at_time,
union xrt_hand_joint_set *out_value);
/*
*
@ -1889,6 +1933,27 @@ struct oxr_debug_messenger
void *XR_MAY_ALIAS user_data;
};
/*!
* A hand tracker.
*
* Parent type/handle is @ref oxr_instance
*
*
* @obj{XrHandTrackerEXT}
* @extends oxr_handle_base
*/
struct oxr_hand_tracker
{
//! Common structure for things referred to by OpenXR handles.
struct oxr_handle_base handle;
//! Owner of this hand tracker.
struct oxr_session *sess;
XrHandEXT hand;
XrHandJointSetEXT hand_joint_set;
};
/*!
* @}
*/

View file

@ -2036,3 +2036,94 @@ oxr_session_create(struct oxr_logger *log,
return ret;
}
void
xrt_to_xr_pose(struct xrt_pose *xrt_pose, XrPosef *xr_pose)
{
xr_pose->orientation.x = xrt_pose->orientation.x;
xr_pose->orientation.y = xrt_pose->orientation.y;
xr_pose->orientation.z = xrt_pose->orientation.z;
xr_pose->orientation.w = xrt_pose->orientation.w;
xr_pose->position.x = xrt_pose->position.x;
xr_pose->position.y = xrt_pose->position.y;
xr_pose->position.z = xrt_pose->position.z;
}
XrResult
oxr_session_hand_joints(struct oxr_logger *log,
struct oxr_hand_tracker *hand_tracker,
const XrHandJointsLocateInfoEXT *locateInfo,
XrHandJointLocationsEXT *locations)
{
struct oxr_space *baseSpc = XRT_CAST_OXR_HANDLE_TO_PTR(
struct oxr_space *, locateInfo->baseSpace);
struct oxr_session *sess = hand_tracker->sess;
struct xrt_device *xdev = NULL;
if (hand_tracker->hand == XR_HAND_LEFT_EXT) {
xdev = GET_XDEV_BY_ROLE(sess->sys, left);
} else if (hand_tracker->hand == XR_HAND_RIGHT_EXT) {
xdev = GET_XDEV_BY_ROLE(sess->sys, right);
} else {
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
"invalid hand value");
}
if (xdev == NULL) {
//! @todo spec is not clear on whether we could have failed
//! creating a hand tracker if we don't have a device for it
locations->isActive = false;
return XR_SUCCESS;
}
struct xrt_pose *tracking_origin_offset =
&xdev->tracking_origin->offset;
XrTime at_time = locateInfo->time;
union xrt_hand_joint_set value;
enum xrt_input_name name;
if (hand_tracker->hand_joint_set == XR_HAND_JOINT_SET_DEFAULT_EXT) {
name = XRT_INPUT_GENERIC_HAND_TRACKING_DEFAULT_SET;
} else {
return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
"invalid hand joint set");
}
oxr_xdev_get_hand_tracking_at(log, sess->sys->inst, xdev, name, at_time,
&value);
for (uint32_t i = 0; i < locations->jointCount; i++) {
locations->jointLocations[i]
.locationFlags = xrt_to_xr_space_location_flags(
value.hand_joint_set_default[i].relation.relation_flags);
locations->jointLocations[i].radius =
value.hand_joint_set_default[i].radius;
struct xrt_space_relation r =
value.hand_joint_set_default[i].relation;
struct xrt_space_relation result;
struct xrt_space_graph graph = {0};
m_space_graph_add_relation(&graph, &r);
m_space_graph_add_pose_if_not_identity(&graph,
tracking_origin_offset);
m_space_graph_add_inverted_pose_if_not_identity(&graph,
&baseSpc->pose);
m_space_graph_resolve(&graph, &result);
//! @todo need general handling of local space
if (baseSpc->type == XR_REFERENCE_SPACE_TYPE_LOCAL) {
global_to_local_space(sess, &result);
}
xrt_to_xr_pose(&result.pose,
&locations->jointLocations[i].pose);
}
locations->isActive = true;
return true;
}

View file

@ -417,8 +417,8 @@ print_space(const char *name, struct oxr_space *spc)
print_pose(spc->sess, "", &spc->pose);
}
static XrSpaceLocationFlags
get_xr_space_location_flags(enum xrt_space_relation_flags relation_flags)
XrSpaceLocationFlags
xrt_to_xr_space_location_flags(enum xrt_space_relation_flags relation_flags)
{
// clang-format off
bool valid_ori = (relation_flags & XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0;
@ -492,7 +492,7 @@ oxr_space_locate(struct oxr_logger *log,
location->pose = safe_copy.oxr;
location->locationFlags =
get_xr_space_location_flags(result.relation_flags);
xrt_to_xr_space_location_flags(result.relation_flags);
XrSpaceVelocity *vel = (XrSpaceVelocity *)location->next;
if (vel) {

View file

@ -19,6 +19,7 @@
#include "oxr_objects.h"
#include "oxr_logger.h"
#include "oxr_two_call.h"
#include "oxr_chain.h"
// clang-format off
DEBUG_GET_ONCE_NUM_OPTION(scale_percentage, "OXR_VIEWPORT_SCALE_PERCENTAGE", 100)
@ -206,6 +207,19 @@ oxr_system_fill_in(struct oxr_logger *log,
return XR_SUCCESS;
}
bool
oxr_system_get_hand_tracking_support(struct oxr_logger *log,
struct oxr_instance *inst)
{
struct oxr_system *sys = &inst->system;
struct xrt_device *left = GET_XDEV_BY_ROLE(sys, left);
struct xrt_device *right = GET_XDEV_BY_ROLE(sys, right);
bool left_supported = left && left->hand_tracking_supported;
bool right_supported = right && right->hand_tracking_supported;
return left_supported || right_supported;
}
XrResult
oxr_system_get_properties(struct oxr_logger *log,
struct oxr_system *sys,
@ -231,6 +245,21 @@ oxr_system_get_properties(struct oxr_logger *log,
properties->trackingProperties.positionTracking =
xdev->position_tracking_supported;
XrSystemHandTrackingPropertiesEXT *hand_tracking_props =
OXR_GET_OUTPUT_FROM_CHAIN(
properties, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT,
XrSystemHandTrackingPropertiesEXT);
if (hand_tracking_props) {
if (!sys->inst->extensions.EXT_hand_tracking) {
return oxr_error(
log, XR_ERROR_VALIDATION_FAILURE,
"XR_EXT_hand_tracking is not enabled.");
}
hand_tracking_props->supportsHandTracking =
oxr_system_get_hand_tracking_support(log, sys->inst);
}
return XR_SUCCESS;
}

View file

@ -101,6 +101,24 @@ oxr_xdev_get_space_graph(struct oxr_logger *log,
m_space_graph_add_pose(xsg, &xdev->tracking_origin->offset);
}
void
oxr_xdev_get_hand_tracking_at(struct oxr_logger *log,
struct oxr_instance *inst,
struct xrt_device *xdev,
enum xrt_input_name name,
XrTime at_time,
union xrt_hand_joint_set *out_value)
{
//! @todo Convert at_time to monotonic and give to device.
uint64_t at_timestamp_ns = os_monotonic_get_ns();
(void)at_time;
union xrt_hand_joint_set value;
xrt_device_get_hand_tracking(xdev, name, at_timestamp_ns, &value);
*out_value = value;
}
void
oxr_xdev_get_space_relation(struct oxr_logger *log,
struct oxr_instance *inst,