VR: Change how landmarks affect viewer pose

* Changing to a landmark moves the view exactly to it, rather than
  keeping the current position offset.
* Disabling positional tracking moves the viewer back to the landmark
  position.
This is a more predictable and practical way to use landmarks. See
feedback in T71347.

On the code side, I did some cleanup so the logic flow is more clear.

Note: This is entirely untested. I currently don't have access to a
device. There might be issues, tomorrow I'll hopefully get feedback.
This commit is contained in:
2020-07-21 23:55:14 +02:00
parent 878d191bae
commit 607d745a79

View File

@@ -159,6 +159,13 @@ static void wm_xr_session_draw_data_populate(wmXrData *xr_data,
wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose); wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose);
} }
typedef enum wmXrSessionStateEvent {
SESSION_STATE_EVENT_NONE = 0,
SESSION_STATE_EVENT_START,
SESSION_STATE_EVENT_RESET_TO_BASE_POSE,
SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE,
} wmXrSessionStateEvent;
static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state,
const XrSessionSettings *settings) const XrSessionSettings *settings)
{ {
@@ -170,36 +177,64 @@ static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionSt
(state->prev_base_pose_object != settings->base_pose_object)); (state->prev_base_pose_object != settings->base_pose_object));
} }
wmXrSessionStateEvent wm_xr_session_state_to_event(const wmXrSessionState *state,
const XrSessionSettings *settings)
{
if (!state->is_view_data_set) {
return SESSION_STATE_EVENT_START;
}
else if (wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) {
return SESSION_STATE_EVENT_RESET_TO_BASE_POSE;
}
else {
const bool position_tracking_toggled = ((state->prev_settings_flag &
XR_SESSION_USE_POSITION_TRACKING) !=
(settings->flag & XR_SESSION_USE_POSITION_TRACKING));
if (position_tracking_toggled) {
return SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE;
}
}
return SESSION_STATE_EVENT_NONE;
}
void wm_xr_session_draw_data_update(const wmXrSessionState *state, void wm_xr_session_draw_data_update(const wmXrSessionState *state,
const XrSessionSettings *settings, const XrSessionSettings *settings,
const GHOST_XrDrawViewInfo *draw_view, const GHOST_XrDrawViewInfo *draw_view,
wmXrDrawData *draw_data) wmXrDrawData *draw_data)
{ {
const bool position_tracking_toggled = ((state->prev_settings_flag & const wmXrSessionStateEvent event = wm_xr_session_state_to_event(state, settings);
XR_SESSION_USE_POSITION_TRACKING) != const bool use_position_tracking = (settings->flag & XR_SESSION_USE_POSITION_TRACKING);
(settings->flag & XR_SESSION_USE_POSITION_TRACKING));
const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING;
/* Set the eye position offset, it's used to offset the base pose when changing positional switch (event) {
* tracking. */ case SESSION_STATE_EVENT_START:
if (!state->is_view_data_set || /* Always use the exact base pose with no offset when starting the session. */
wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) {
/* Always use the exact base pose with no offset when starting the session. */
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
else if (position_tracking_toggled) {
if (use_position_tracking) {
copy_v3_fl(draw_data->eye_position_ofs, 0.0f); copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
} break;
else { /* This should be triggered by the VR add-on if a landmark changes. */
/* Store the current local offset (local pose) so that we can apply that to the eyes. This case SESSION_STATE_EVENT_RESET_TO_BASE_POSE:
* way the eyes stay exactly where they are when disabling positional tracking. */ if (use_position_tracking) {
copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position); /* Switch exactly to base pose, so use eye offset to cancel out current position delta. */
} copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position);
} }
else if (!use_position_tracking) { else {
/* Keep previous offset when positional tracking is disabled. */ copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs); }
break;
case SESSION_STATE_EVENT_POSITON_TRACKING_TOGGLE:
if (use_position_tracking) {
/* Keep the current position, and let the user move from there. */
copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
}
else {
/* Back to the exact base-pose position. */
copy_v3_fl(draw_data->eye_position_ofs, 0.0f);
}
break;
case SESSION_STATE_EVENT_NONE:
/* Keep previous offset when positional tracking is disabled. */
copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs);
break;
} }
} }
@@ -299,9 +334,9 @@ bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr,
/** /**
* \brief Call Ghost-XR to draw a frame * \brief Call Ghost-XR to draw a frame
* *
* Draw callback for the XR-session surface. It's expected to be called on each main loop iteration * Draw callback for the XR-session surface. It's expected to be called on each main loop
* and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view, * iteration and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing
* #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()). * each view, #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()).
*/ */
static void wm_xr_session_surface_draw(bContext *C) static void wm_xr_session_surface_draw(bContext *C)
{ {