[Bf-blender-cvs] [2585d7f1b81] xr-controller-support: XR: Add grab navigation operator

Peter Kim noreply at git.blender.org
Fri Jun 18 14:37:18 CEST 2021


Commit: 2585d7f1b812c54043648c128b9aec7a5e24106d
Author: Peter Kim
Date:   Fri Jun 18 21:32:18 2021 +0900
Branches: xr-controller-support
https://developer.blender.org/rB2585d7f1b812c54043648c128b9aec7a5e24106d

XR: Add grab navigation operator

Similar to the XR grab transform operator but applies deltas to the
navigation matrix instead of objects. Supports bimanual interaction
for viewer/navigation scaling and locks for rotation and scale.

===================================================================

M	source/blender/windowmanager/xr/intern/wm_xr_operators.c

===================================================================

diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index 1ef4bdc01c3..d0915b87f13 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -74,6 +74,8 @@ static bool wm_xr_operator_sessionactive(bContext *C)
   return false;
 }
 
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name XR Session Toggle
  *
@@ -160,8 +162,355 @@ static void WM_OT_xr_session_toggle(wmOperatorType *ot)
 /** \} */
 
 /* -------------------------------------------------------------------- */
-/** \name XR Raycast Utilities
+/** \name XR Grab Utilities
+ * \{ */
+
+typedef struct XrGrabData {
+  float mat_prev[4][4];
+  float mat_other_prev[4][4];
+  bool bimanual_prev;
+} XrGrabData;
+
+static void wm_xr_grab_init(wmOperator *op)
+{
+  BLI_assert(op->customdata == NULL);
+
+  op->customdata = MEM_callocN(sizeof(XrGrabData), __func__);
+}
+
+static void wm_xr_grab_uninit(wmOperator *op)
+{
+  MEM_SAFE_FREE(op->customdata);
+}
+
+static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
+{
+  XrGrabData *data = op->customdata;
+
+  quat_to_mat4(data->mat_prev, actiondata->controller_rot);
+  copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
+
+  if (actiondata->bimanual) {
+    quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+    copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
+    data->bimanual_prev = true;
+  }
+  else {
+    data->bimanual_prev = false;
+  }
+}
+
+static void wm_xr_grab_compute(const wmXrActionData *actiondata,
+                               const XrGrabData *data,
+                               const Object *obedit,
+                               bool reverse,
+                               bool loc_lock,
+                               bool rot_lock,
+                               float r_delta[4][4])
+{
+  float m0[4][4], m1[4][4];
+
+  if (obedit) {
+    float m2[4][4];
+
+    if (rot_lock) {
+      unit_m4(m0);
+      copy_v3_v3(m0[3], reverse ? actiondata->controller_loc : data->mat_prev[3]);
+      mul_m4_m4m4(m1, obedit->imat, m0);
+      invert_m4(m1);
+
+      copy_v3_v3(m0[3], reverse ? data->mat_prev[3] : actiondata->controller_loc);
+      mul_m4_m4m4(m2, obedit->imat, m0);
+
+      mul_m4_m4m4(r_delta, m2, m1);
+    }
+    else {
+      if (reverse) {
+        quat_to_mat4(m0, actiondata->controller_rot);
+        copy_v3_v3(m0[3], actiondata->controller_loc);
+        mul_m4_m4m4(m1, obedit->imat, m0);
+        invert_m4(m1);
+
+        mul_m4_m4m4(m2, obedit->imat, data->mat_prev);
+
+        mul_m4_m4m4(r_delta, m2, m1);
+      }
+      else {
+        mul_m4_m4m4(m1, obedit->imat, data->mat_prev);
+        invert_m4(m1);
+
+        quat_to_mat4(m0, actiondata->controller_rot);
+        copy_v3_v3(m0[3], actiondata->controller_loc);
+        mul_m4_m4m4(m2, obedit->imat, m0);
+
+        mul_m4_m4m4(r_delta, m2, m1);
+      }
+
+      if (loc_lock) {
+        zero_v3(r_delta[3]);
+      }
+    }
+  }
+  else {
+    if (rot_lock) {
+      unit_m4(m0);
+      copy_v3_v3(m0[3], reverse ? actiondata->controller_loc : data->mat_prev[3]);
+      invert_m4_m4(m1, m0);
+
+      copy_v3_v3(m0[3], reverse ? data->mat_prev[3] : actiondata->controller_loc);
+
+      mul_m4_m4m4(r_delta, m0, m1);
+    }
+    else {
+      if (reverse) {
+        quat_to_mat4(m1, actiondata->controller_rot);
+        copy_v3_v3(m1[3], actiondata->controller_loc);
+        invert_m4(m1);
+
+        mul_m4_m4m4(r_delta, data->mat_prev, m1);
+      }
+      else {
+        invert_m4_m4(m1, data->mat_prev);
+
+        quat_to_mat4(m0, actiondata->controller_rot);
+        copy_v3_v3(m0[3], actiondata->controller_loc);
+
+        mul_m4_m4m4(r_delta, m0, m1);
+      }
+
+      if (loc_lock) {
+        zero_v3(r_delta[3]);
+      }
+    }
+  }
+}
+
+static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
+                                        const XrGrabData *data,
+                                        const Object *obedit,
+                                        bool reverse,
+                                        bool loc_lock,
+                                        bool rot_lock,
+                                        bool scale_lock,
+                                        float r_delta[4][4])
+{
+  float prev[4][4], curr[4][4];
+  unit_m4(prev);
+  unit_m4(curr);
+
+  if (!rot_lock) {
+    /* Rotation. */
+    float x_axis_prev[3], x_axis_curr[3], y_axis_prev[3], y_axis_curr[3], z_axis_prev[3],
+        z_axis_curr[3];
+    float m0[3][3], m1[3][3];
+    quat_to_mat3(m0, actiondata->controller_rot);
+    quat_to_mat3(m1, actiondata->controller_rot_other);
+
+    /* x-axis is the base line between the two controllers. */
+    sub_v3_v3v3(x_axis_prev, data->mat_prev[3], data->mat_other_prev[3]);
+    sub_v3_v3v3(x_axis_curr, actiondata->controller_loc, actiondata->controller_loc_other);
+    /* y-axis is the average of the controllers' y-axes. */
+    add_v3_v3v3(y_axis_prev, data->mat_prev[1], data->mat_other_prev[1]);
+    mul_v3_fl(y_axis_prev, 0.5f);
+    add_v3_v3v3(y_axis_curr, m0[1], m1[1]);
+    mul_v3_fl(y_axis_curr, 0.5f);
+    /* z-axis is the cross product of the two. */
+    cross_v3_v3v3(z_axis_prev, x_axis_prev, y_axis_prev);
+    cross_v3_v3v3(z_axis_curr, x_axis_curr, y_axis_curr);
+    /* Fix the y-axis to be orthogonal. */
+    cross_v3_v3v3(y_axis_prev, z_axis_prev, x_axis_prev);
+    cross_v3_v3v3(y_axis_curr, z_axis_curr, x_axis_curr);
+    /* Normalize. */
+    normalize_v3_v3(prev[0], x_axis_prev);
+    normalize_v3_v3(prev[1], y_axis_prev);
+    normalize_v3_v3(prev[2], z_axis_prev);
+    normalize_v3_v3(curr[0], x_axis_curr);
+    normalize_v3_v3(curr[1], y_axis_curr);
+    normalize_v3_v3(curr[2], z_axis_curr);
+  }
+
+  if (!loc_lock) {
+    /* Translation: translation of the averaged controller locations. */
+    add_v3_v3v3(prev[3], data->mat_prev[3], data->mat_other_prev[3]);
+    mul_v3_fl(prev[3], 0.5f);
+    add_v3_v3v3(curr[3], actiondata->controller_loc, actiondata->controller_loc_other);
+    mul_v3_fl(curr[3], 0.5f);
+  }
+
+  if (!scale_lock) {
+    /* Scaling: distance between controllers. */
+    float scale, v[3];
+
+    sub_v3_v3v3(v, data->mat_prev[3], data->mat_other_prev[3]);
+    scale = len_v3(v);
+    mul_v3_fl(prev[0], scale);
+    mul_v3_fl(prev[1], scale);
+    mul_v3_fl(prev[2], scale);
+
+    sub_v3_v3v3(v, actiondata->controller_loc, actiondata->controller_loc_other);
+    scale = len_v3(v);
+    mul_v3_fl(curr[0], scale);
+    mul_v3_fl(curr[1], scale);
+    mul_v3_fl(curr[2], scale);
+  }
+
+  if (obedit) {
+    mul_m4_m4m4(prev, obedit->imat, prev);
+    mul_m4_m4m4(curr, obedit->imat, curr);
+  }
+
+  if (reverse) {
+    invert_m4(curr);
+    mul_m4_m4m4(r_delta, prev, curr);
+  }
+  else {
+    invert_m4(prev);
+    mul_m4_m4m4(r_delta, curr, prev);
+  }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Navigation Grab
  *
+ * Navigates the scene by grabbing with XR controllers.
+ * \{ */
+
+static int wm_xr_navigation_grab_invoke_3d(bContext *C, wmOperator *op, const wmEvent *event)
+{
+  BLI_assert(event->type == EVT_XR_ACTION);
+  BLI_assert(event->custom == EVT_DATA_XR);
+  BLI_assert(event->customdata);
+
+  const wmXrActionData *actiondata = event->customdata;
+
+  wm_xr_grab_init(op);
+  wm_xr_grab_update(op, actiondata);
+
+  WM_event_add_modal_handler(C, op);
+
+  return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_navigation_grab_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+  return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_navigation_grab_modal_3d(bContext *C, wmOperator *op, const wmEvent *event)
+{
+  BLI_assert(event->type == EVT_XR_ACTION);
+  BLI_assert(event->custom == EVT_DATA_XR);
+  BLI_assert(event->customdata);
+
+  const wmXrActionData *actiondata = event->customdata;
+  XrGrabData *data = op->customdata;
+  wmWindowManager *wm = CTX_wm_manager(C);
+  wmXrData *xr = &wm->xr;
+  bool loc_lock, rot_lock, scale_lock;
+  GHOST_XrPose nav_pose;
+  float nav_scale, nav_mat[4][4], delta[4][4], m[4][4];
+
+  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "lock_location");
+  loc_lock = prop ? RNA_property_boolean_get(op->ptr, prop) : false;
+  prop = RNA_struct_find_property(op->ptr, "lock_rotation");
+  rot_lock = prop ? RNA_property_boolean_get(op->ptr, prop) : false;
+  prop = RNA_struct_find_property(op->ptr, "lock_scale");
+  scale_lock = prop ? RNA_property_boolean_get(op->ptr, prop) : false;
+
+  const bool do_bimanual = (actiondata->bimanual && data->bimanual_prev);
+  const bool apply_navigation = (do_bimanual ? !(loc_lock && rot_lock && scale_lock) :
+                                               !(loc_lock && rot_lock)) &&
+                                (actiondata->bimanual || !data->bimanual_prev);
+
+  if (apply_navigation) {
+    WM_xr_session_state_nav_location_get(xr, nav_pose.position);
+    WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
+    WM_xr_session_state_nav_scale_get(xr, &nav_scale);
+
+    wm_xr_pose_scale_to_mat(&nav_pose, nav_scale, nav_mat);
+
+    if (do_bimanual) {
+      wm_xr_grab_compute_bimanual(
+          actiondata, data, NULL, true, loc_lock, rot_lock, scale_lock, delta);
+    }
+    else {
+      wm_xr_grab_compute(actiondata, data, NULL, true, loc_lock, rot_lock, delta);
+    }
+
+    mul_m4_m4m4(m, delta, nav_mat);
+
+    if (!loc_lock) {
+      WM_xr_session_state_nav_location_set(xr, m[3]);
+    }
+    if (!rot_lock) {
+      mat4_to_quat(nav_pose.orientation_quat, m);
+      normalize_qt(nav_pose.orientation_quat);
+      WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
+    }
+    if (!scale_lock && do_bimanual) {
+      nav_scale = len_v3(m[0]);
+      WM_xr_session_state_nav_scale_set(xr, nav_scale);
+    }
+  }
+
+  if (actiondata->bimanual) {
+    if (!data->bimanual_prev) {
+      quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
+      copy_v3_v3(data->mat_other_prev[3], actiondata->controll

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list