Blender V5.0
wm_xr_operators.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include "BLI_kdopbvh.hh"
14#include "BLI_listbase.h"
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
18#include "BLI_time.h"
19
20#include "BLT_translation.hh"
21
22#include "BKE_context.hh"
23#include "BKE_global.hh"
24#include "BKE_idprop.hh"
25#include "BKE_main.hh"
26#include "BKE_screen.hh"
27
28#include "DEG_depsgraph.hh"
29
30#include "ED_screen.hh"
31#include "ED_space_api.hh"
33#include "ED_view3d.hh"
34
35#include "GHOST_Types.h"
36
37#include "GPU_immediate.hh"
38#include "GPU_state.hh"
39
40#include "GPU_batch_presets.hh"
41#include "GPU_matrix.hh"
42#include "GPU_xr_defines.hh"
43
44#include "MEM_guardedalloc.h"
45
46#include "RNA_access.hh"
47#include "RNA_define.hh"
48
49#include "WM_api.hh"
50#include "WM_types.hh"
51
52#include "wm_xr_intern.hh"
53
54/* -------------------------------------------------------------------- */
57
58/* `op->poll`. */
64
65static bool wm_xr_operator_test_event(const wmOperator *op, const wmEvent *event)
66{
67 if (event->type != EVT_XR_ACTION) {
68 return false;
69 }
70
71 BLI_assert(event->custom == EVT_DATA_XR);
72 BLI_assert(event->customdata);
73
74 wmXrActionData *actiondata = static_cast<wmXrActionData *>(event->customdata);
75 return (actiondata->ot == op->type &&
76 IDP_EqualsProperties(actiondata->op_properties, op->properties));
77}
78
80
81/* -------------------------------------------------------------------- */
86
87static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
88{
89 const bool session_exists = WM_xr_session_exists(xr_data);
90
91 for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
92 screen = static_cast<bScreen *>(screen->id.next))
93 {
94 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
95 LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) {
96 if (slink->spacetype == SPACE_VIEW3D) {
97 View3D *v3d = (View3D *)slink;
98
99 if (v3d->flag & V3D_XR_SESSION_MIRROR) {
100 ED_view3d_xr_mirror_update(area, v3d, session_exists);
101 }
102
103 if (session_exists) {
104 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
105 const Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
106
107 ED_view3d_xr_shading_update(wm, v3d, scene);
108 }
109 /* Ensure no 3D View is tagged as session root. */
110 else {
112 }
113 }
114 }
115 }
116 }
117
119}
120
122{
123 /* Just use G_MAIN here, storing main isn't reliable enough on file read or exit. */
125}
126
128{
129 Main *bmain = CTX_data_main(C);
131 wmWindow *win = CTX_wm_window(C);
132 View3D *v3d = CTX_wm_view3d(C);
133
134 /* Lazily-create XR context - tries to dynamic-link to the runtime,
135 * reading `active_runtime.json`. */
136 if (wm_xr_init(wm) == false) {
137 return OPERATOR_CANCELLED;
138 }
139
142 wm_xr_session_update_screen(bmain, &wm->xr);
143
145
146 return OPERATOR_FINISHED;
147}
148
150{
151 /* Identifiers. */
152 ot->name = "Toggle VR Session";
153 ot->idname = "WM_OT_xr_session_toggle";
154 ot->description =
155 "Open a view for use with virtual reality headsets, or close it if already "
156 "opened";
157
158 /* Callbacks. */
161
162 /* XXX INTERNAL just to hide it from the search menu by default, an Add-on will expose it in the
163 * UI instead. Not meant as a permanent solution. */
164 ot->flag = OPTYPE_INTERNAL;
165}
166
168
169/* -------------------------------------------------------------------- */
172
179
181{
182 BLI_assert(op->customdata == nullptr);
183
184 op->customdata = MEM_callocN<XrGrabData>(__func__);
185}
186
188{
189 XrGrabData *data = static_cast<XrGrabData *>(op->customdata);
191 op->customdata = nullptr;
192}
193
194static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
195{
196 XrGrabData *data = static_cast<XrGrabData *>(op->customdata);
197
198 quat_to_mat4(data->mat_prev, actiondata->controller_rot);
199 copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
200
201 if (actiondata->bimanual) {
202 quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
203 copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
204 data->bimanual_prev = true;
205 }
206 else {
207 data->bimanual_prev = false;
208 }
209}
210
211static void orient_mat_z_normalized(float R[4][4], const float z_axis[3])
212{
213 const float scale = len_v3(R[0]);
214 float x_axis[3], y_axis[3];
215
216 cross_v3_v3v3(y_axis, z_axis, R[0]);
217 normalize_v3(y_axis);
218 mul_v3_v3fl(R[1], y_axis, scale);
219
220 cross_v3_v3v3(x_axis, R[1], z_axis);
221 normalize_v3(x_axis);
222 mul_v3_v3fl(R[0], x_axis, scale);
223
224 mul_v3_v3fl(R[2], z_axis, scale);
225}
226
227static void wm_xr_navlocks_apply(const float nav_mat[4][4],
228 const float nav_inv[4][4],
229 bool loc_lock,
230 bool locz_lock,
231 bool rotz_lock,
232 float r_prev[4][4],
233 float r_curr[4][4])
234{
235 /* Locked in base pose coordinates. */
236 float prev_base[4][4], curr_base[4][4];
237
238 mul_m4_m4m4(prev_base, nav_inv, r_prev);
239 mul_m4_m4m4(curr_base, nav_inv, r_curr);
240
241 if (rotz_lock) {
242 const float z_axis[3] = {0.0f, 0.0f, 1.0f};
243 orient_mat_z_normalized(prev_base, z_axis);
244 orient_mat_z_normalized(curr_base, z_axis);
245 }
246
247 if (loc_lock) {
248 copy_v3_v3(curr_base[3], prev_base[3]);
249 }
250 else if (locz_lock) {
251 curr_base[3][2] = prev_base[3][2];
252 }
253
254 mul_m4_m4m4(r_prev, nav_mat, prev_base);
255 mul_m4_m4m4(r_curr, nav_mat, curr_base);
256}
257
267static void wm_xr_grab_compute(const wmXrActionData *actiondata,
268 const XrGrabData *data,
269 const float nav_mat[4][4],
270 const float nav_inv[4][4],
271 bool reverse,
272 float r_delta[4][4])
273{
274 const bool nav_lock = (nav_mat && nav_inv);
275 float prev[4][4], curr[4][4];
276
277 if (!data->rot_lock) {
278 copy_m4_m4(prev, data->mat_prev);
279 zero_v3(prev[3]);
280 quat_to_mat4(curr, actiondata->controller_rot);
281 }
282 else {
283 unit_m4(prev);
284 unit_m4(curr);
285 }
286
287 if (!data->loc_lock || nav_lock) {
288 copy_v3_v3(prev[3], data->mat_prev[3]);
289 copy_v3_v3(curr[3], actiondata->controller_loc);
290 }
291
292 if (nav_lock) {
294 nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
295 }
296
297 if (reverse) {
298 invert_m4(curr);
299 mul_m4_m4m4(r_delta, prev, curr);
300 }
301 else {
302 invert_m4(prev);
303 mul_m4_m4m4(r_delta, curr, prev);
304 }
305}
306
319static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
320 const XrGrabData *data,
321 const float nav_mat[4][4],
322 const float nav_inv[4][4],
323 bool reverse,
324 float r_delta[4][4])
325{
326 const bool nav_lock = (nav_mat && nav_inv);
327 float prev[4][4], curr[4][4];
328 unit_m4(prev);
329 unit_m4(curr);
330
331 if (!data->rot_lock) {
332 /* Rotation. */
333 float x_axis_prev[3], x_axis_curr[3], y_axis_prev[3], y_axis_curr[3], z_axis_prev[3],
334 z_axis_curr[3];
335 float m0[3][3], m1[3][3];
336 quat_to_mat3(m0, actiondata->controller_rot);
337 quat_to_mat3(m1, actiondata->controller_rot_other);
338
339 /* X-axis is the base line between the two controllers. */
340 sub_v3_v3v3(x_axis_prev, data->mat_prev[3], data->mat_other_prev[3]);
341 sub_v3_v3v3(x_axis_curr, actiondata->controller_loc, actiondata->controller_loc_other);
342 /* Y-axis is the average of the controllers' y-axes. */
343 add_v3_v3v3(y_axis_prev, data->mat_prev[1], data->mat_other_prev[1]);
344 mul_v3_fl(y_axis_prev, 0.5f);
345 add_v3_v3v3(y_axis_curr, m0[1], m1[1]);
346 mul_v3_fl(y_axis_curr, 0.5f);
347 /* Z-axis is the cross product of the two. */
348 cross_v3_v3v3(z_axis_prev, x_axis_prev, y_axis_prev);
349 cross_v3_v3v3(z_axis_curr, x_axis_curr, y_axis_curr);
350 /* Fix the y-axis to be orthogonal. */
351 cross_v3_v3v3(y_axis_prev, z_axis_prev, x_axis_prev);
352 cross_v3_v3v3(y_axis_curr, z_axis_curr, x_axis_curr);
353 /* Normalize. */
354 normalize_v3_v3(prev[0], x_axis_prev);
355 normalize_v3_v3(prev[1], y_axis_prev);
356 normalize_v3_v3(prev[2], z_axis_prev);
357 normalize_v3_v3(curr[0], x_axis_curr);
358 normalize_v3_v3(curr[1], y_axis_curr);
359 normalize_v3_v3(curr[2], z_axis_curr);
360 }
361
362 if (!data->loc_lock || nav_lock) {
363 /* Translation: translation of the averaged controller locations. */
364 add_v3_v3v3(prev[3], data->mat_prev[3], data->mat_other_prev[3]);
365 mul_v3_fl(prev[3], 0.5f);
366 add_v3_v3v3(curr[3], actiondata->controller_loc, actiondata->controller_loc_other);
367 mul_v3_fl(curr[3], 0.5f);
368 }
369
370 if (!data->scale_lock) {
371 /* Scaling: distance between controllers. */
372 float scale, v[3];
373
374 sub_v3_v3v3(v, data->mat_prev[3], data->mat_other_prev[3]);
375 scale = len_v3(v);
376 mul_v3_fl(prev[0], scale);
377 mul_v3_fl(prev[1], scale);
378 mul_v3_fl(prev[2], scale);
379
380 sub_v3_v3v3(v, actiondata->controller_loc, actiondata->controller_loc_other);
381 scale = len_v3(v);
382 mul_v3_fl(curr[0], scale);
383 mul_v3_fl(curr[1], scale);
384 mul_v3_fl(curr[2], scale);
385 }
386
387 if (nav_lock) {
389 nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
390 }
391
392 if (reverse) {
393 invert_m4(curr);
394 mul_m4_m4m4(r_delta, prev, curr);
395 }
396 else {
397 invert_m4(prev);
398 mul_m4_m4m4(r_delta, curr, prev);
399 }
400}
401
403
404/* -------------------------------------------------------------------- */
409
411 wmOperator *op,
412 const wmEvent *event)
413{
414 if (!wm_xr_operator_test_event(op, event)) {
416 }
417
418 const wmXrActionData *actiondata = static_cast<const wmXrActionData *>(event->customdata);
419
420 wm_xr_grab_init(op);
421 wm_xr_grab_update(op, actiondata);
422
424
426}
427
432
433static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actiondata,
434 const XrGrabData *data)
435{
436 /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both
437 * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second
438 * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to
439 * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas
440 * are calculated). */
441 return (actiondata->bimanual && data->bimanual_prev);
442}
443
444static bool wm_xr_navigation_grab_is_bimanual_ending(const wmXrActionData *actiondata,
445 const XrGrabData *data)
446{
447 return (!actiondata->bimanual && data->bimanual_prev);
448}
449
450static bool wm_xr_navigation_grab_is_locked(const XrGrabData *data, const bool bimanual)
451{
452 if (bimanual) {
453 return data->loc_lock && data->rot_lock && data->scale_lock;
454 }
455 /* Ignore scale lock, as one-handed interaction cannot change navigation scale. */
456 return data->loc_lock && data->rot_lock;
457}
458
460 const wmXrActionData *actiondata,
461 const XrGrabData *data,
462 bool bimanual)
463{
464 GHOST_XrPose nav_pose;
465 float nav_scale;
466 float nav_mat[4][4], nav_inv[4][4], delta[4][4], out[4][4];
467
468 const bool need_navinv = (data->loc_lock || data->locz_lock || data->rotz_lock);
469
470 WM_xr_session_state_nav_location_get(xr, nav_pose.position);
471 WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
472 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
473
474 wm_xr_pose_scale_to_mat(&nav_pose, nav_scale, nav_mat);
475 if (need_navinv) {
476 wm_xr_pose_scale_to_imat(&nav_pose, nav_scale, nav_inv);
477 }
478
479 if (bimanual) {
481 data,
482 need_navinv ? nav_mat : nullptr,
483 need_navinv ? nav_inv : nullptr,
484 true,
485 delta);
486 }
487 else {
488 wm_xr_grab_compute(actiondata,
489 data,
490 need_navinv ? nav_mat : nullptr,
491 need_navinv ? nav_inv : nullptr,
492 true,
493 delta);
494 }
495
496 mul_m4_m4m4(out, delta, nav_mat);
497
498 /* Limit scale to reasonable values. */
499 nav_scale = len_v3(out[0]);
500
501 if (!(nav_scale < xr->session_settings.clip_start || nav_scale > xr->session_settings.clip_end))
502 {
504 if (!data->rot_lock) {
505 mat4_to_quat(nav_pose.orientation_quat, out);
506 normalize_qt(nav_pose.orientation_quat);
507 WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
508 }
509 if (!data->scale_lock && bimanual) {
511 }
512 }
513}
514
515static void wm_xr_navigation_grab_bimanual_state_update(const wmXrActionData *actiondata,
517{
518 if (actiondata->bimanual) {
519 if (!data->bimanual_prev) {
520 quat_to_mat4(data->mat_prev, actiondata->controller_rot);
521 copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
522 quat_to_mat4(data->mat_other_prev, actiondata->controller_rot_other);
523 copy_v3_v3(data->mat_other_prev[3], actiondata->controller_loc_other);
524 }
525 data->bimanual_prev = true;
526 }
527 else {
528 if (data->bimanual_prev) {
529 quat_to_mat4(data->mat_prev, actiondata->controller_rot);
530 copy_v3_v3(data->mat_prev[3], actiondata->controller_loc);
531 }
532 data->bimanual_prev = false;
533 }
534}
535
537{
539}
540
542 wmOperator *op,
543 const wmEvent *event)
544{
545 if (!wm_xr_operator_test_event(op, event)) {
547 }
548
549 const wmXrActionData *actiondata = static_cast<const wmXrActionData *>(event->customdata);
550 XrGrabData *data = static_cast<XrGrabData *>(op->customdata);
552 wmXrData *xr = &wm->xr;
553
555
556 const bool do_bimanual = wm_xr_navigation_grab_can_do_bimanual(actiondata, data);
557
558 data->loc_lock = RNA_boolean_get(op->ptr, "lock_location");
559 data->locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
560 data->rot_lock = RNA_boolean_get(op->ptr, "lock_rotation");
561 data->rotz_lock = RNA_boolean_get(op->ptr, "lock_rotation_z");
562 data->scale_lock = RNA_boolean_get(op->ptr, "lock_scale");
563
564 /* Check if navigation is locked. */
565 if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) {
566 /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from
567 * two-handed to one-handed interaction) at the end of a bimanual interaction. */
569 wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual);
570 }
571 }
572
574
575 /* NOTE: #KM_PRESS and #KM_RELEASE are the only two values supported by XR events during event
576 * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal
577 * handling starts when an input is "pressed" (action state exceeds the action threshold) and
578 * ends when the input is "released" (state falls below the threshold). */
579 switch (event->val) {
580 case KM_PRESS:
582 case KM_RELEASE:
584 return OPERATOR_FINISHED;
585 default:
588 return OPERATOR_CANCELLED;
589 }
590}
591
593{
594 /* Identifiers. */
595 ot->name = "XR Navigation Grab";
596 ot->idname = "WM_OT_xr_navigation_grab";
597 ot->description = "Navigate the VR scene by grabbing with controllers";
598
599 /* Callbacks. */
605
606 /* Properties. */
608 ot->srna, "lock_location", false, "Lock Location", "Prevent changes to viewer location");
610 ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
612 ot->srna, "lock_rotation", false, "Lock Rotation", "Prevent changes to viewer rotation");
613 RNA_def_boolean(ot->srna,
614 "lock_rotation_z",
615 false,
616 "Lock Up Orientation",
617 "Prevent changes to viewer up orientation");
618 RNA_def_boolean(ot->srna, "lock_scale", false, "Lock Scale", "Prevent changes to viewer scale");
619}
620
622
623/* -------------------------------------------------------------------- */
626
627static const float g_xr_default_raycast_axis[3] = {0.0f, 0.0f, -1.0f};
628static const float g_xr_default_raycast_hit_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
629static const float g_xr_default_raycast_miss_color[4] = {1.0f, 0.35f, 0.35f, 1.0f};
630static const float g_xr_default_raycast_fallback_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
631
637
641
645 float points[XR_MAX_RAYCASTS + 1][4];
646 float direction[3];
647
649 float color[4];
653
654 blender::gpu::Batch *raycast_model;
655
657};
658
660{
662
663 blender::gpu::Batch *sphere = GPU_batch_preset_sphere(2);
665 GPU_batch_uniform_4fv(sphere, "color", data->color);
666
668 GPU_matrix_translate_3fv(data->points[data->num_points - 1]);
669 GPU_matrix_scale_1f(data->destination_size);
670 GPU_batch_draw(sphere);
672}
673
674static void wm_xr_raycast_draw(const bContext * /*C*/, ARegion * /*region*/, void *customdata)
675{
676 const XrRaycastData *data = static_cast<const XrRaycastData *>(customdata);
677
678 if (data->result != XR_RAYCAST_MISS) {
680 }
681
683 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
684
685 if (data->from_viewer) {
687 immUniformColor4fv(data->color);
688
690 GPU_point_size(7.0f);
691
692 immBegin(GPU_PRIM_POINTS, data->num_points - 1);
693
694 for (int i = 1; i < data->num_points; ++i) {
695 immVertex3fv(pos, data->points[i]);
696 }
697
698 immEnd();
700 }
701 else {
702 BLI_assert(data->raycast_model != nullptr);
703
704 float forward[3];
705 float right[3];
706
707 sub_v3_v3v3(forward, data->points[data->num_points - 1], data->points[0]);
708 copy_v3_fl3(right, forward[1], -forward[0], 0.0f);
709 normalize_v3(right);
710
712
715 data->raycast_model, "control_points", XR_MAX_RAYCASTS + 1, data->points);
716 GPU_batch_uniform_4fv(data->raycast_model, "color", data->color);
717 GPU_batch_uniform_3fv(data->raycast_model, "right_vector", right);
718 GPU_batch_uniform_1f(data->raycast_model, "width", data->raycast_width);
719 GPU_batch_uniform_1i(data->raycast_model, "control_point_count", data->num_points);
720 GPU_batch_uniform_1i(data->raycast_model, "sample_count", data->sample_count);
721 GPU_batch_draw(data->raycast_model);
722 }
723}
724
726{
727 BLI_assert(op->customdata == nullptr);
728
730
732 if (!st) {
733 return;
734 }
735
737 if (!art) {
738 return;
739 }
740
741 XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
742 data->draw_handle = ED_region_draw_cb_activate(
744}
745
747{
748 if (!op->customdata) {
749 return;
750 }
751
752 XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
753
755 if (st) {
757 if (art) {
758 ED_region_draw_cb_exit(art, data->draw_handle);
759 }
760 }
761
763 op->customdata = nullptr;
764}
765
767 const wmXrData *xr,
768 const wmXrActionData *actiondata)
769{
770 XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
771 float axis[3], nav_scale;
772
773 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
774
775 data->from_viewer = RNA_boolean_get(op->ptr, "from_viewer");
776 data->raycast_width = RNA_float_get(op->ptr, "raycast_scale") * nav_scale;
777 data->sample_count = RNA_int_get(op->ptr, "sample_count");
778 RNA_float_get_array(op->ptr, "axis", axis);
779
780 if (data->from_viewer) {
781 float viewer_rot[4];
784 mul_qt_v3(viewer_rot, axis);
785 }
786 else {
789 GPU_PRIM_TRI_STRIP, 2 * data->sample_count);
790 }
791
792 data->raycast_model = xr->runtime->session_state.raycast_model;
793
794 copy_v3_v3(data->points[0], actiondata->controller_loc);
795 mul_qt_v3(actiondata->controller_rot, axis);
796 }
797
798 copy_v3_v3(data->direction, axis);
799}
800
801static void wm_xr_raycast(Scene *scene,
802 Depsgraph *depsgraph,
803 const float origin[3],
804 const float direction[3],
805 float *ray_dist,
806 bool selectable_only,
807 float r_location[3],
808 float r_normal[3],
809 int *r_index,
810 const Object **r_ob,
811 float r_obmat[4][4])
812{
813 /* Uses same raycast method as Scene.ray_cast(). */
816
818 params.snap_target_select = (selectable_only ? SCE_SNAP_TARGET_ONLY_SELECTABLE :
821 depsgraph,
822 nullptr,
823 &params,
824 origin,
825 direction,
826 ray_dist,
827 r_location,
828 r_normal,
829 r_index,
830 r_ob,
831 r_obmat);
832
834}
835
837
838/* -------------------------------------------------------------------- */
844
860
861struct XrFlyData {
862 float viewer_rot[4];
863 double time_prev;
864
865 /* Only used for snap turn, where the action should be executed only once. */
867};
868
869static void wm_xr_fly_init(wmOperator *op, const wmXrData *xr)
870{
871 BLI_assert(op->customdata == nullptr);
872
874 op->customdata = data;
875
877 data->time_prev = BLI_time_now_seconds();
878}
879
881{
882 XrFlyData *data = static_cast<XrFlyData *>(op->customdata);
884 op->customdata = nullptr;
885}
886
888 float speed,
889 const float ref_quat[4],
890 const float nav_mat[4][4],
891 bool locz_lock,
892 float r_delta[4][4])
893{
894 float ref_axes[3][3];
895 quat_to_mat3(ref_axes, ref_quat);
896
897 unit_m4(r_delta);
898
899 switch (mode) {
900 /* Navigation space reference. */
901 case XR_FLY_FORWARD:
902 madd_v3_v3fl(r_delta[3], ref_axes[1], speed);
903 return;
904 case XR_FLY_BACK:
905 madd_v3_v3fl(r_delta[3], ref_axes[1], -speed);
906 return;
907 case XR_FLY_LEFT:
908 madd_v3_v3fl(r_delta[3], ref_axes[0], -speed);
909 return;
910 case XR_FLY_RIGHT:
911 madd_v3_v3fl(r_delta[3], ref_axes[0], speed);
912 return;
913 case XR_FLY_UP:
914 case XR_FLY_DOWN:
915 if (!locz_lock) {
916 madd_v3_v3fl(r_delta[3], ref_axes[2], (mode == XR_FLY_UP) ? speed : -speed);
917 }
918 return;
919 /* Viewer/controller space reference. */
922 negate_v3_v3(r_delta[3], ref_axes[2]);
923 break;
925 copy_v3_v3(r_delta[3], ref_axes[2]);
926 break;
928 negate_v3_v3(r_delta[3], ref_axes[0]);
929 break;
931 copy_v3_v3(r_delta[3], ref_axes[0]);
932 break;
933 /* Unused. */
934 case XR_FLY_TURNLEFT:
935 case XR_FLY_TURNRIGHT:
937 return;
938 }
939
940 if (locz_lock) {
941 /* Lock elevation in navigation space. */
942 float z_axis[3], projected[3];
943
944 normalize_v3_v3(z_axis, nav_mat[2]);
945 project_v3_v3v3_normalized(projected, r_delta[3], z_axis);
946 sub_v3_v3(r_delta[3], projected);
947
948 normalize_v3(r_delta[3]);
949 }
950
951 mul_v3_fl(r_delta[3], speed);
952}
953
955 float speed,
956 const float viewer_mat[4][4],
957 const float nav_mat[4][4],
958 const float nav_inv[4][4],
959 float r_delta[4][4])
960{
962
963 float z_axis[3], m[3][3], prev[4][4], curr[4][4];
964
965 /* Turn around Z-axis in navigation space. */
966 normalize_v3_v3(z_axis, nav_mat[2]);
967 axis_angle_normalized_to_mat3(m, z_axis, (mode == XR_FLY_TURNLEFT) ? speed : -speed);
968 copy_m4_m3(r_delta, m);
969
970 copy_m4_m4(prev, viewer_mat);
971 mul_m4_m4m4(curr, r_delta, viewer_mat);
972
973 /* Lock location in base pose space. */
974 wm_xr_navlocks_apply(nav_mat, nav_inv, true, false, false, prev, curr);
975
976 invert_m4(prev);
977 mul_m4_m4m4(r_delta, curr, prev);
978}
979
981 const float nav_rotation[4],
982 float r_rotation[4])
983{
984 /* Apply nav rotation to base pose Z-rotation. */
985 float base_eul[3], base_quatz[4];
986 quat_to_eul(base_eul, xr->runtime->session_state.prev_base_pose.orientation_quat);
987 axis_angle_to_quat_single(base_quatz, 'Z', base_eul[2]);
988 mul_qt_qtqt(r_rotation, nav_rotation, base_quatz);
989}
990
992 wmOperator *op,
993 const wmEvent *event)
994{
995 if (!wm_xr_operator_test_event(op, event)) {
997 }
998
1000
1001 wm_xr_fly_init(op, &wm->xr);
1002
1004
1006}
1007
1009{
1010 return OPERATOR_CANCELLED;
1011}
1012
1014{
1015 wm_xr_fly_uninit(op);
1016}
1017
1019 wmOperator *op,
1020 const wmEvent *event)
1021{
1022 if (!wm_xr_operator_test_event(op, event)) {
1023 return OPERATOR_PASS_THROUGH;
1024 }
1025
1026 if (event->val == KM_RELEASE) {
1027 wm_xr_fly_uninit(op);
1028 return OPERATOR_FINISHED;
1029 }
1030
1031 const wmXrActionData *actiondata = static_cast<const wmXrActionData *>(event->customdata);
1032 XrFlyData *data = static_cast<XrFlyData *>(op->customdata);
1034 wmXrData *xr = &wm->xr;
1035 eXrFlyMode mode;
1036 bool turn, snap_turn, invert_rotation, swap_hands, locz_lock, dir_lock, speed_frame_based;
1037 bool speed_interp_cubic = false;
1038 float speed, speed_max, speed_p0[2], speed_p1[2], button_state;
1039 GHOST_XrPose nav_pose;
1040 float nav_mat[4][4], delta[4][4], out[4][4];
1041
1042 const double time_now = BLI_time_now_seconds(), delta_time = time_now - data->time_prev;
1043 data->time_prev = time_now;
1044
1045 swap_hands = xr->runtime->session_state.swap_hands;
1046 mode = (eXrFlyMode)RNA_enum_get(op->ptr, swap_hands ? "alt_mode" : "mode");
1047 turn = ELEM(mode, XR_FLY_TURNLEFT, XR_FLY_TURNRIGHT);
1048 snap_turn = U.xr_navigation.flag & USER_XR_NAV_SNAP_TURN;
1049 invert_rotation = U.xr_navigation.flag & USER_XR_NAV_INVERT_ROTATION;
1050
1051 locz_lock = RNA_boolean_get(op->ptr, swap_hands ? "alt_lock_location_z" : "lock_location_z");
1052 dir_lock = RNA_boolean_get(op->ptr, swap_hands ? "alt_lock_direction" : "lock_direction");
1053
1054 if (turn) {
1055 speed_frame_based = false;
1056
1057 if (snap_turn) {
1058 speed_max = U.xr_navigation.turn_amount;
1059 speed = speed_max;
1060 }
1061 else {
1062 speed_max = U.xr_navigation.turn_speed;
1063 speed = speed_max * RNA_boolean_get(op->ptr, "turn_speed_factor");
1064 }
1065 }
1066 else {
1067 speed_frame_based = RNA_boolean_get(op->ptr, "speed_frame_based");
1068 speed_max = xr->session_settings.fly_speed;
1069 speed = speed_max * RNA_float_get(op->ptr, "fly_speed_factor");
1070 }
1071
1072 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "speed_interpolation0");
1073 if (prop && RNA_property_is_set(op->ptr, prop)) {
1074 RNA_property_float_get_array(op->ptr, prop, speed_p0);
1075 speed_interp_cubic = true;
1076 }
1077 else {
1078 speed_p0[0] = speed_p0[1] = 0.0f;
1079 }
1080
1081 prop = RNA_struct_find_property(op->ptr, "speed_interpolation1");
1082 if (prop && RNA_property_is_set(op->ptr, prop)) {
1083 RNA_property_float_get_array(op->ptr, prop, speed_p1);
1084 speed_interp_cubic = true;
1085 }
1086 else {
1087 speed_p1[0] = speed_p1[1] = 1.0f;
1088 }
1089
1090 /* Ensure valid interpolation. */
1091 if (speed_max < speed) {
1092 speed_max = speed;
1093 }
1094
1095 /* Interpolate between min/max speeds based on button state. */
1096 switch (actiondata->type) {
1097 case XR_BOOLEAN_INPUT:
1098 button_state = 1.0f;
1099 speed = speed_max;
1100 break;
1101 case XR_FLOAT_INPUT:
1102 case XR_VECTOR2F_INPUT: {
1103 button_state = (actiondata->type == XR_FLOAT_INPUT) ? fabsf(actiondata->state[0]) :
1104 len_v2(actiondata->state);
1105 float speed_t = (actiondata->float_threshold < 1.0f) ?
1106 (button_state - actiondata->float_threshold) /
1107 (1.0f - actiondata->float_threshold) :
1108 1.0f;
1109 if (speed_interp_cubic) {
1110 float start[2], end[2], p[2];
1111
1112 start[0] = 0.0f;
1113 start[1] = speed;
1114 speed_p0[1] = speed + speed_p0[1] * (speed_max - speed);
1115 speed_p1[1] = speed + speed_p1[1] * (speed_max - speed);
1116 end[0] = 1.0f;
1117 end[1] = speed_max;
1118
1119 interp_v2_v2v2v2v2_cubic(p, start, speed_p0, speed_p1, end, speed_t);
1120 speed = p[1];
1121 }
1122 else {
1123 speed += speed_t * (speed_max - speed);
1124 }
1125 break;
1126 }
1127 case XR_POSE_INPUT:
1130 break;
1131 }
1132
1133 WM_xr_session_state_nav_location_get(xr, nav_pose.position);
1134 WM_xr_session_state_nav_rotation_get(xr, nav_pose.orientation_quat);
1135 wm_xr_pose_to_mat(&nav_pose, nav_mat);
1136
1137 if (turn) {
1138 if (dir_lock || (snap_turn && data->is_finished) ||
1139 (snap_turn && button_state < RNA_float_get(op->ptr, "snap_turn_threshold")))
1140 {
1141 unit_m4(delta);
1142 }
1143 else {
1144 if (!snap_turn) {
1146 speed *= delta_time;
1147 }
1148 else {
1149 data->is_finished = true;
1150 }
1151
1152 if (invert_rotation) {
1153 speed *= -1.0f;
1154 }
1155
1156 GHOST_XrPose viewer_pose;
1157 float viewer_mat[4][4], nav_inv[4][4];
1158
1159 WM_xr_session_state_viewer_pose_location_get(xr, viewer_pose.position);
1160 WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_pose.orientation_quat);
1161 wm_xr_pose_to_mat(&viewer_pose, viewer_mat);
1162 wm_xr_pose_to_imat(&nav_pose, nav_inv);
1163
1164 wm_xr_fly_compute_turn(mode, speed, viewer_mat, nav_mat, nav_inv, delta);
1165 }
1166 }
1167 else {
1168 float nav_scale, ref_quat[4];
1169
1171
1172 /* Adjust speed for base and navigation scale. */
1173 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
1174 speed *= xr->session_settings.base_scale * nav_scale;
1175
1176 if (!speed_frame_based) {
1177 speed *= delta_time;
1178 }
1179
1180 switch (mode) {
1181 /* Move relative to navigation space. */
1182 case XR_FLY_FORWARD:
1183 case XR_FLY_BACK:
1184 case XR_FLY_LEFT:
1185 case XR_FLY_RIGHT:
1186 case XR_FLY_UP:
1187 case XR_FLY_DOWN:
1188 wm_xr_basenav_rotation_calc(xr, nav_pose.orientation_quat, ref_quat);
1189 break;
1190 /* Move relative to viewer. */
1192 case XR_FLY_VIEWER_BACK:
1193 case XR_FLY_VIEWER_LEFT:
1195 if (dir_lock) {
1196 copy_qt_qt(ref_quat, data->viewer_rot);
1197 }
1198 else {
1200 }
1201 break;
1202 /* Move relative to controller. */
1204 copy_qt_qt(ref_quat, actiondata->controller_rot);
1205 break;
1206 /* Unused. */
1207 case XR_FLY_TURNLEFT:
1208 case XR_FLY_TURNRIGHT:
1210 break;
1211 }
1212
1213 wm_xr_fly_compute_move(mode, speed, ref_quat, nav_mat, locz_lock, delta);
1214 }
1215
1216 mul_m4_m4m4(out, delta, nav_mat);
1217
1219 if (turn) {
1220 mat4_to_quat(nav_pose.orientation_quat, out);
1221 WM_xr_session_state_nav_rotation_set(xr, nav_pose.orientation_quat);
1222 }
1223
1224 if (event->val == KM_PRESS) {
1226 }
1227
1228 /* XR events currently only support press and release. */
1230 wm_xr_fly_uninit(op);
1231 return OPERATOR_CANCELLED;
1232}
1233
1235{
1236 PropertyRNA *prop;
1237
1238 /* Identifiers. */
1239 ot->name = "XR Navigation Fly";
1240 ot->idname = "WM_OT_xr_navigation_fly";
1241 ot->description = "Move/turn relative to the VR viewer or controller";
1242
1243 /* Callbacks. */
1249
1250 /* Properties. */
1251 static const EnumPropertyItem fly_modes[] = {
1252 {XR_FLY_FORWARD, "FORWARD", 0, "Forward", "Move along navigation forward axis"},
1253 {XR_FLY_BACK, "BACK", 0, "Back", "Move along navigation back axis"},
1254 {XR_FLY_LEFT, "LEFT", 0, "Left", "Move along navigation left axis"},
1255 {XR_FLY_RIGHT, "RIGHT", 0, "Right", "Move along navigation right axis"},
1256 {XR_FLY_UP, "UP", 0, "Up", "Move along navigation up axis"},
1257 {XR_FLY_DOWN, "DOWN", 0, "Down", "Move along navigation down axis"},
1259 "TURNLEFT",
1260 0,
1261 "Turn Left",
1262 "Turn counter-clockwise around navigation up axis"},
1263 {XR_FLY_TURNRIGHT, "TURNRIGHT", 0, "Turn Right", "Turn clockwise around navigation up axis"},
1265 "VIEWER_FORWARD",
1266 0,
1267 "Viewer Forward",
1268 "Move along viewer's forward axis"},
1269 {XR_FLY_VIEWER_BACK, "VIEWER_BACK", 0, "Viewer Back", "Move along viewer's back axis"},
1270 {XR_FLY_VIEWER_LEFT, "VIEWER_LEFT", 0, "Viewer Left", "Move along viewer's left axis"},
1271 {XR_FLY_VIEWER_RIGHT, "VIEWER_RIGHT", 0, "Viewer Right", "Move along viewer's right axis"},
1273 "CONTROLLER_FORWARD",
1274 0,
1275 "Controller Forward",
1276 "Move along controller's forward axis"},
1277 {0, nullptr, 0, nullptr, nullptr},
1278 };
1279
1280 static const float default_speed_p0[2] = {0.0f, 0.0f};
1281 static const float default_speed_p1[2] = {1.0f, 1.0f};
1282
1283 prop = RNA_def_enum(ot->srna, "mode", fly_modes, XR_FLY_VIEWER_FORWARD, "Mode", "Fly mode");
1285
1286 RNA_def_float(ot->srna,
1287 "snap_turn_threshold",
1288 0.95f,
1289 0.0f,
1290 1.0f,
1291 "Snap Turn Threshold",
1292 "Input state threshold when using snap turn",
1293 0.0f,
1294 1.0f);
1296 ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
1297 RNA_def_boolean(ot->srna,
1298 "lock_direction",
1299 false,
1300 "Lock Direction",
1301 "Limit movement to viewer's initial direction");
1302 RNA_def_boolean(ot->srna,
1303 "speed_frame_based",
1304 false,
1305 "Frame Based Speed",
1306 "Apply fixed movement deltas every update");
1307 RNA_def_float(ot->srna,
1308 "turn_speed_factor",
1309 1.0 / 3.0f,
1310 0.0f,
1311 1.0f,
1312 "Turn Speed Factor",
1313 "Ratio between the min and max turn speed",
1314 0.0f,
1315 1.0f);
1316 RNA_def_float(ot->srna,
1317 "fly_speed_factor",
1318 1.0 / 3.0f,
1319 0.0f,
1320 1.0f,
1321 "Fly Speed Factor",
1322 "Ratio between the min and max fly speed",
1323 0.0f,
1324 1.0f);
1326 "speed_interpolation0",
1327 2,
1328 default_speed_p0,
1329 0.0f,
1330 1.0f,
1331 "Speed Interpolation 0",
1332 "First cubic spline control point between min/max speeds",
1333 0.0f,
1334 1.0f);
1336 "speed_interpolation1",
1337 2,
1338 default_speed_p1,
1339 0.0f,
1340 1.0f,
1341 "Speed Interpolation 1",
1342 "Second cubic spline control point between min/max speeds",
1343 0.0f,
1344 1.0f);
1345
1346 RNA_def_enum(ot->srna,
1347 "alt_mode",
1348 fly_modes,
1350 "Mode (Alt)",
1351 "Fly mode when hands are swapped");
1352 RNA_def_boolean(ot->srna,
1353 "alt_lock_location_z",
1354 false,
1355 "Lock Elevation (Alt)",
1356 "When hands are swapped, prevent changes to viewer elevation");
1357 RNA_def_boolean(ot->srna,
1358 "alt_lock_direction",
1359 false,
1360 "Lock Direction (Alt)",
1361 "When hands are swapped, limit movement to viewer's initial direction");
1362}
1363
1365
1366/* -------------------------------------------------------------------- */
1371
1373 float nav_destination[3],
1374 const float destination[4],
1375 const float normal[3],
1376 const bool teleport_axes[3],
1377 float teleport_t,
1378 float teleport_ofs,
1379 float vertical_ofs)
1380{
1381 float nav_location[3], nav_rotation[4], viewer_location[3];
1382 WM_xr_session_state_nav_location_get(xr, nav_location);
1383 WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
1385
1386 float nav_axes[3][3], projected[3], v0[3], v1[3], destination_with_ofs[3];
1387
1388 copy_v3_fl(nav_destination, 0.0f);
1389 copy_v3_v3(destination_with_ofs, destination);
1390 destination_with_ofs[2] += vertical_ofs;
1391
1392 wm_xr_basenav_rotation_calc(xr, nav_rotation, nav_rotation);
1393 quat_to_mat3(nav_axes, nav_rotation);
1394
1395 /* Project locations onto navigation axes. */
1396 for (int a = 0; a < 3; ++a) {
1397 project_v3_v3v3_normalized(projected, nav_location, nav_axes[a]);
1398 if (teleport_axes[a]) {
1399 /* Interpolate between projected locations. */
1400 project_v3_v3v3_normalized(v0, destination_with_ofs, nav_axes[a]);
1401 project_v3_v3v3_normalized(v1, viewer_location, nav_axes[a]);
1402 sub_v3_v3(v0, v1);
1403 madd_v3_v3fl(projected, v0, teleport_t);
1404 /* Subtract offset. */
1405 project_v3_v3v3_normalized(v0, normal, nav_axes[a]);
1406 madd_v3_v3fl(projected, v0, teleport_ofs);
1407 }
1408 /* Add to final location. */
1409 add_v3_v3(nav_destination, projected);
1410 }
1411
1412 return len_v3v3(viewer_location, destination);
1413}
1414
1416 int *num_points,
1417 float *ray_dist)
1418{
1419 constexpr uint z = 2;
1420 for (int i = 1; i < *num_points; ++i) {
1421 float *startpoint = points[i - 1], *endpoint = points[i];
1422
1423 if ((startpoint[z] < 0) == (endpoint[z] < 0)) {
1424 continue;
1425 }
1426
1427 if (startpoint[z] == endpoint[z]) {
1428 break;
1429 }
1430
1431 float segment_ray_dist = len_v3v3(startpoint, endpoint);
1432 float alpha = startpoint[z] / (startpoint[z] - endpoint[z]);
1433 interp_v3_v3v3(endpoint, startpoint, endpoint, alpha);
1434
1435 *ray_dist = segment_ray_dist * (i - 1) + len_v3v3(startpoint, endpoint);
1436 *num_points = i + 1;
1437 return true;
1438 }
1439
1440 return false;
1441}
1442
1444 wmXrData *xr,
1445 float nav_destination[3],
1446 float points[XR_MAX_RAYCASTS + 1][4],
1447 const float direction[3],
1448 int *num_points,
1449 float *ray_dist,
1450 float *destination_dist,
1451 bool selectable_only,
1452 const bool teleport_axes[3],
1453 float teleport_t,
1454 float teleport_ofs,
1455 float gravity,
1456 float head_height)
1457{
1458 Scene *scene = CTX_data_scene(C);
1460 int index;
1461 const Object *ob = nullptr;
1462 float obmat[4][4];
1463
1464 float normal[3], segment_direction[3];
1465 float vertical_ofs = 0;
1467
1468 copy_v3_v3(segment_direction, direction);
1469 copy_v3_fl3(normal, 0, 1, 0);
1470
1471 /* When ray_dist == 0 or -1, the raycast is a line of infinite length. */
1472 if (*ray_dist <= 0.0f) {
1473 *num_points = 2;
1474 }
1475
1476 const float segment_length = *ray_dist / (*num_points - 1);
1477 float segment_ray_dist = 0.0f;
1478 *ray_dist = 0.0f;
1479
1480 for (int i = 1; i < *num_points; ++i) {
1481 segment_ray_dist = segment_length;
1482 wm_xr_raycast(scene,
1483 depsgraph,
1484 points[i - 1],
1485 segment_direction,
1486 &segment_ray_dist,
1487 selectable_only,
1488 points[i],
1489 normal,
1490 &index,
1491 &ob,
1492 obmat);
1493
1494 *ray_dist += segment_ray_dist;
1495
1496 if (ob) {
1497 *num_points = i + 1;
1498
1500 if (dot_v3v3(segment_direction, normal) > 0) {
1501 mul_v3_fl(normal, -1.0f);
1502 }
1503
1505 break;
1506 }
1507
1508 madd_v3_v3v3fl(points[i], points[i - 1], segment_direction, segment_length);
1509
1510 /* Apply gravity */
1511 segment_direction[2] -= gravity;
1512 normalize_v3(segment_direction);
1513 }
1514
1516 if (result == XR_RAYCAST_MISS) {
1517 vertical_ofs = head_height;
1518
1519 if (wm_xr_navigation_teleport_ground_plane(points, num_points, ray_dist)) {
1521 }
1522 }
1523
1524 if (result != XR_RAYCAST_MISS) {
1525 float origin[3], dummy_dest[3], dummy_normal[3];
1526
1527 /* Raycast downward to see if we're on the floor */
1528 copy_v3_fl3(segment_direction, 0, 0, -1);
1529
1530 copy_v3_v3(origin, points[*num_points - 1]);
1531 madd_v3_v3fl(origin, normal, teleport_ofs);
1532 madd_v3_v3fl(origin, segment_direction, -vertical_ofs);
1533
1534 segment_ray_dist = head_height;
1535 ob = nullptr;
1536 wm_xr_raycast(scene,
1537 depsgraph,
1538 origin,
1539 segment_direction,
1540 &segment_ray_dist,
1541 selectable_only,
1542 dummy_dest,
1543 dummy_normal,
1544 &index,
1545 &ob,
1546 obmat);
1547
1548 /* Raycast upward to make sure we don't clip through the ceiling */
1549 if (ob) {
1550 vertical_ofs = head_height - segment_ray_dist;
1551 copy_v3_fl3(segment_direction, 0, 0, 1);
1552
1553 copy_v3_v3(origin, points[*num_points - 1]);
1554 madd_v3_v3fl(origin, normal, teleport_ofs);
1555
1556 segment_ray_dist = vertical_ofs;
1557 ob = nullptr;
1558 wm_xr_raycast(scene,
1559 depsgraph,
1560 origin,
1561 segment_direction,
1562 &segment_ray_dist,
1563 selectable_only,
1564 dummy_dest,
1565 dummy_normal,
1566 &index,
1567 &ob,
1568 obmat);
1569
1570 if (ob) {
1571 vertical_ofs = max_ff(0.0f, segment_ray_dist - teleport_ofs);
1572 }
1573 }
1574
1575 /* Calculate teleportation destination in navigation space */
1576 *destination_dist = wm_xr_navigation_teleport_pose_calc(xr,
1577 nav_destination,
1578 points[*num_points - 1],
1579 normal,
1580 teleport_axes,
1581 teleport_t,
1582 teleport_ofs,
1583 vertical_ofs);
1584 }
1585
1586 return result;
1587}
1588
1590 wmOperator *op,
1591 const wmEvent *event)
1592{
1593 if (!wm_xr_operator_test_event(op, event)) {
1594 return OPERATOR_PASS_THROUGH;
1595 }
1596
1598
1599 const wmOperatorStatus retval = op->type->modal(C, op, event);
1600 OPERATOR_RETVAL_CHECK(retval);
1601
1602 if (retval & OPERATOR_RUNNING_MODAL) {
1604 }
1605
1606 return retval;
1607}
1608
1613
1615{
1617}
1618
1620 wmOperator *op,
1621 const wmEvent *event)
1622{
1623 if (!wm_xr_operator_test_event(op, event)) {
1624 return OPERATOR_PASS_THROUGH;
1625 }
1626
1627 const wmXrActionData *actiondata = static_cast<const wmXrActionData *>(event->customdata);
1629 wmXrData *xr = &wm->xr;
1630
1632 wm_xr_raycast_update(op, xr, actiondata);
1633
1634 XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
1635 float nav_scale, ray_dist, destination_dist, nav_destination[3];
1636 bool teleport_axes[3];
1637
1638 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
1639
1640 RNA_boolean_get_array(op->ptr, "teleport_axes", teleport_axes);
1641 const float teleport_t = RNA_float_get(op->ptr, "interpolation");
1642 const float teleport_ofs = RNA_float_get(op->ptr, "offset") * nav_scale;
1643 const float gravity = RNA_float_get(op->ptr, "gravity");
1644 const float head_height = xr->runtime->session_state.prev_local_pose.position[1] * nav_scale;
1645 const bool selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
1646 ray_dist = RNA_float_get(op->ptr, "distance") * nav_scale;
1647
1648 data->num_points = XR_MAX_RAYCASTS + 1;
1650 xr,
1651 nav_destination,
1652 data->points,
1653 data->direction,
1654 &data->num_points,
1655 &ray_dist,
1656 &destination_dist,
1657 selectable_only,
1658 teleport_axes,
1659 teleport_t,
1660 teleport_ofs,
1661 gravity,
1662 head_height);
1663
1664 data->destination_size = RNA_float_get(op->ptr, "destination_scale") *
1665 sqrt(destination_dist / nav_scale) * nav_scale;
1666
1667 switch (data->result) {
1668 case XR_RAYCAST_MISS:
1669 RNA_float_get_array(op->ptr, "miss_color", data->color);
1670 break;
1671 case XR_RAYCAST_HIT:
1672 RNA_float_get_array(op->ptr, "hit_color", data->color);
1673 break;
1675 RNA_float_get_array(op->ptr, "fallback_color", data->color);
1676 break;
1677 default:
1679 break;
1680 }
1681
1682 switch (event->val) {
1683 case KM_PRESS:
1685 case KM_RELEASE: {
1686 if (data->result != XR_RAYCAST_MISS) {
1687 WM_xr_session_state_nav_location_set(xr, nav_destination);
1688 }
1689
1692
1693 return OPERATOR_FINISHED;
1694 }
1695 default:
1696 /* XR events currently only support press and release. */
1699 return OPERATOR_CANCELLED;
1700 }
1701}
1702
1704{
1705 /* Identifiers. */
1706 ot->name = "XR Navigation Teleport";
1707 ot->idname = "WM_OT_xr_navigation_teleport";
1708 ot->description = "Set VR viewer location to controller raycast hit location";
1709
1710 /* Callbacks. */
1716
1717 /* Properties. */
1718 static const bool default_teleport_axes[3] = {true, true, true};
1719
1721 "teleport_axes",
1722 3,
1723 default_teleport_axes,
1724 "Teleport Axes",
1725 "Enabled teleport axes in navigation space");
1726 RNA_def_float(ot->srna,
1727 "interpolation",
1728 1.0f,
1729 0.0f,
1730 1.0f,
1731 "Interpolation",
1732 "Interpolation factor between viewer and hit locations",
1733 0.0f,
1734 1.0f);
1735 RNA_def_float(ot->srna,
1736 "offset",
1737 0.25f,
1738 0.0f,
1739 FLT_MAX,
1740 "Offset",
1741 "Offset along hit normal to subtract from final location",
1742 0.0f,
1743 FLT_MAX);
1744 RNA_def_boolean(ot->srna,
1745 "selectable_only",
1746 true,
1747 "Selectable Only",
1748 "Only allow selectable objects to influence raycast result");
1749 RNA_def_float(ot->srna,
1750 "distance",
1751 80.0,
1752 0.0,
1754 "",
1755 "Maximum raycast distance",
1756 0.0,
1758 RNA_def_float(ot->srna,
1759 "gravity",
1760 0.1,
1761 0.0,
1762 FLT_MAX,
1763 "Gravity",
1764 "Downward curvature applied to raycast",
1765 0.0,
1766 FLT_MAX);
1767 RNA_def_float(ot->srna,
1768 "raycast_scale",
1769 0.02f,
1770 0.0f,
1771 FLT_MAX,
1772 "Raycast Scale",
1773 "Width of the raycast visualization",
1774 0.0f,
1775 FLT_MAX);
1776 RNA_def_float(ot->srna,
1777 "destination_scale",
1778 0.05f,
1779 0.0f,
1780 FLT_MAX,
1781 "Destination Scale",
1782 "Width of the destination visualization",
1783 0.0f,
1784 FLT_MAX);
1785 RNA_def_int(ot->srna,
1786 "sample_count",
1787 48,
1788 2,
1789 INT_MAX,
1790 "Sample Count",
1791 "Number of interpolation samples for the raycast visualization",
1792 2,
1793 INT_MAX);
1795 ot->srna, "from_viewer", false, "From Viewer", "Use viewer pose as raycast origin");
1797 "axis",
1798 3,
1800 -1.0f,
1801 1.0f,
1802 "Axis",
1803 "Raycast axis in controller/viewer space",
1804 -1.0f,
1805 1.0f);
1806 RNA_def_float_color(ot->srna,
1807 "hit_color",
1808 4,
1810 0.0f,
1811 1.0f,
1812 "Hit Color",
1813 "Color of raycast when it succeeds",
1814 0.0f,
1815 1.0f);
1816 RNA_def_float_color(ot->srna,
1817 "miss_color",
1818 4,
1820 0.0f,
1821 1.0f,
1822 "Miss Color",
1823 "Color of raycast when it misses",
1824 0.0f,
1825 1.0f);
1826 RNA_def_float_color(ot->srna,
1827 "fallback_color",
1828 4,
1830 0.0f,
1831 1.0f,
1832 "Fallback Color",
1833 "Color of raycast when a fallback case succeeds",
1834 0.0f,
1835 1.0f);
1836}
1837
1839
1840/* -------------------------------------------------------------------- */
1845
1847{
1849 wmXrData *xr = &wm->xr;
1850 bool reset_loc, reset_rot, reset_scale;
1851
1852 reset_loc = RNA_boolean_get(op->ptr, "location");
1853 reset_rot = RNA_boolean_get(op->ptr, "rotation");
1854 reset_scale = RNA_boolean_get(op->ptr, "scale");
1855
1856 if (reset_loc) {
1857 float loc[3];
1858 if (!reset_scale) {
1859 float nav_rotation[4], nav_scale;
1860
1861 WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
1862 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
1863
1864 /* Adjust location based on scale. */
1865 mul_v3_v3fl(loc, xr->runtime->session_state.prev_base_pose.position, nav_scale);
1866 sub_v3_v3(loc, xr->runtime->session_state.prev_base_pose.position);
1867 mul_qt_v3(nav_rotation, loc);
1868 negate_v3(loc);
1869 }
1870 else {
1871 zero_v3(loc);
1872 }
1874 }
1875
1876 if (reset_rot) {
1877 float rot[4];
1878 unit_qt(rot);
1880 }
1881
1882 if (reset_scale) {
1883 if (!reset_loc) {
1884 float nav_location[3], nav_rotation[4], nav_scale;
1885 float nav_axes[3][3], v[3];
1886
1887 WM_xr_session_state_nav_location_get(xr, nav_location);
1888 WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
1889 WM_xr_session_state_nav_scale_get(xr, &nav_scale);
1890
1891 /* Offset any location changes when changing scale. */
1892 mul_v3_v3fl(v, xr->runtime->session_state.prev_base_pose.position, nav_scale);
1894 mul_qt_v3(nav_rotation, v);
1895 add_v3_v3(nav_location, v);
1896
1897 /* Reset elevation to base pose value. */
1898 quat_to_mat3(nav_axes, nav_rotation);
1899 project_v3_v3v3_normalized(v, nav_location, nav_axes[2]);
1900 sub_v3_v3(nav_location, v);
1901
1902 WM_xr_session_state_nav_location_set(xr, nav_location);
1903 }
1905 }
1906
1907 return OPERATOR_FINISHED;
1908}
1909
1911{
1912 /* Identifiers. */
1913 ot->name = "XR Navigation Reset";
1914 ot->idname = "WM_OT_xr_navigation_reset";
1915 ot->description = "Reset VR navigation deltas relative to session base pose";
1916
1917 /* Callbacks. */
1920
1921 /* Properties. */
1922 RNA_def_boolean(ot->srna, "location", true, "Location", "Reset location deltas");
1923 RNA_def_boolean(ot->srna, "rotation", true, "Rotation", "Reset rotation deltas");
1924 RNA_def_boolean(ot->srna, "scale", true, "Scale", "Reset scale deltas");
1925}
1926
1928
1929/* -------------------------------------------------------------------- */
1934
1936 wmOperator *op,
1937 const wmEvent *event)
1938{
1939 if (!wm_xr_operator_test_event(op, event)) {
1940 return OPERATOR_PASS_THROUGH;
1941 }
1942
1944
1946 wmXrData *xr = &wm->xr;
1947
1948 xr->runtime->session_state.swap_hands = true;
1949
1951}
1952
1957
1959 wmOperator *op,
1960 const wmEvent *event)
1961{
1962 if (!wm_xr_operator_test_event(op, event)) {
1963 return OPERATOR_PASS_THROUGH;
1964 }
1965
1967 wmXrData *xr = &wm->xr;
1968
1969 switch (event->val) {
1970 case KM_PRESS:
1972 case KM_RELEASE:
1973 xr->runtime->session_state.swap_hands = false;
1974 return OPERATOR_FINISHED;
1975 default:
1977 return OPERATOR_CANCELLED;
1978 }
1979}
1980
1982{
1983 /* Identifiers. */
1984 ot->name = "XR Navigation Swap Hands";
1985 ot->idname = "WM_OT_xr_navigation_swap_hands";
1986 ot->description = "Swap VR navigation controls between left / right controllers";
1987
1988 /* Callbacks. */
1993}
1994
1996
1997/* -------------------------------------------------------------------- */
2000
2010
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
#define G_MAIN
bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:1004
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:257
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:267
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BVH_RAYCAST_DIST_MAX
#define LISTBASE_FOREACH(type, var, list)
MINLINE float max_ff(float a, float b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4(float mat[4][4])
void unit_m4(float m[4][4])
void quat_to_mat3(float m[3][3], const float q[4])
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle)
void axis_angle_to_quat_single(float q[4], char axis, float angle)
float normalize_qt(float q[4])
void quat_to_mat4(float m[4][4], const float q[4])
void mul_qt_v3(const float q[4], float r[3])
void unit_qt(float q[4])
void quat_to_eul(float eul[3], const float quat[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void mat4_to_quat(float q[4], const float mat[4][4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
void interp_v2_v2v2v2v2_cubic(float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2], float u)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3])
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.cc:113
#define ELEM(...)
#define BLT_I18NCONTEXT_NAVIGATION
@ SCE_SNAP_TARGET_ONLY_SELECTABLE
@ SCE_SNAP_TARGET_ALL
@ RGN_TYPE_XR
@ SPACE_VIEW3D
@ USER_XR_NAV_SNAP_TURN
@ USER_XR_NAV_INVERT_ROTATION
@ V3D_RUNTIME_XR_SESSION_ROOT
@ V3D_XR_SESSION_MIRROR
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define OPERATOR_RETVAL_CHECK(ret)
@ XR_FLOAT_INPUT
@ XR_BOOLEAN_INPUT
@ XR_VECTOR2F_INPUT
@ XR_POSE_INPUT
@ XR_VIBRATION_OUTPUT
bool ED_operator_view3d_active(bContext *C)
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define GPU_batch_uniform_1f(batch, name, x)
Definition GPU_batch.hh:271
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
#define GPU_batch_uniform_4fv_array(batch, name, len, val)
Definition GPU_batch.hh:282
#define GPU_batch_uniform_3fv(batch, name, val)
Definition GPU_batch.hh:278
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:279
blender::gpu::Batch * GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count)
Definition gpu_batch.cc:83
#define GPU_batch_uniform_1i(batch, name, x)
Definition GPU_batch.hh:269
blender::gpu::Batch * GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void GPU_matrix_push()
void GPU_matrix_scale_1f(float factor)
void GPU_matrix_translate_3fv(const float vec[3])
void GPU_matrix_pop()
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRI_STRIP
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_XR_RAYCAST
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
void GPU_point_size(float size)
Definition gpu_state.cc:172
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
#define XR_MAX_RAYCASTS
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition RandGen.cpp:29
#define NC_WM
Definition WM_types.hh:374
@ KM_PRESS
Definition WM_types.hh:311
@ KM_RELEASE
Definition WM_types.hh:312
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
#define ND_XR_DATA_CHANGED
Definition WM_types.hh:418
#define U
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
#define rot(x, k)
uint pos
#define out
#define sqrt
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define R
bool snap_object_project_ray_ex(SnapObjectContext *sctx, Depsgraph *depsgraph, const View3D *v3d, const SnapObjectParams *params, const float ray_start[3], const float ray_normal[3], float *ray_depth, float r_loc[3], float r_no[3], int *r_index, const Object **r_ob, float r_obmat[4][4])
void snap_object_context_destroy(SnapObjectContext *sctx)
SnapObjectContext * snap_object_context_create(Scene *scene, int flag)
#define fabsf
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
void RNA_boolean_get_array(PointerRNA *ptr, const char *name, bool *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_color(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const bool *default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
#define FLT_MAX
Definition stdcycles.h:14
void * first
ListBase wm
Definition BKE_main.hh:307
ListBase screens
Definition BKE_main.hh:292
View3D_Runtime runtime
float viewer_rot[4]
float mat_other_prev[4][4]
float mat_prev[4][4]
XrRaycastResult result
blender::gpu::Batch * raycast_model
float points[XR_MAX_RAYCASTS+1][4]
wmEventType type
Definition WM_types.hh:757
short custom
Definition WM_types.hh:793
short val
Definition WM_types.hh:759
void * customdata
Definition WM_types.hh:807
wmOperatorStatus(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1081
IDProperty * properties
struct wmOperatorType * type
struct PointerRNA * ptr
XrSessionSettings session_settings
struct wmXrRuntimeData * runtime
wmXrSessionState session_state
GHOST_XrPose prev_local_pose
blender::gpu::Batch * raycast_model
GHOST_XrPose prev_base_pose
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_DATA_XR
@ EVT_XR_ACTION
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
Scene * WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
bool wm_xr_init(wmWindowManager *wm)
Definition wm_xr.cc:56
void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4])
Definition wm_xr_draw.cc:39
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4])
Definition wm_xr_draw.cc:45
void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4])
Definition wm_xr_draw.cc:63
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4])
Definition wm_xr_draw.cc:55
static void orient_mat_z_normalized(float R[4][4], const float z_axis[3])
static void wm_xr_grab_init(wmOperator *op)
static void wm_xr_fly_init(wmOperator *op, const wmXrData *xr)
static void wm_xr_navigation_grab_bimanual_state_update(const wmXrActionData *actiondata, XrGrabData *data)
static void wm_xr_basenav_rotation_calc(const wmXrData *xr, const float nav_rotation[4], float r_rotation[4])
static wmOperatorStatus wm_xr_navigation_swap_hands_exec(bContext *, wmOperator *)
static wmOperatorStatus wm_xr_navigation_reset_exec(bContext *C, wmOperator *op)
static wmOperatorStatus wm_xr_navigation_swap_hands_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void wm_xr_grab_uninit(wmOperator *op)
static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
static wmOperatorStatus wm_xr_navigation_teleport_exec(bContext *, wmOperator *)
static void wm_xr_navigation_grab_apply(wmXrData *xr, const wmXrActionData *actiondata, const XrGrabData *data, bool bimanual)
static void wm_xr_navlocks_apply(const float nav_mat[4][4], const float nav_inv[4][4], bool loc_lock, bool locz_lock, bool rotz_lock, float r_prev[4][4], float r_curr[4][4])
static bool wm_xr_navigation_grab_is_bimanual_ending(const wmXrActionData *actiondata, const XrGrabData *data)
static wmOperatorStatus wm_xr_navigation_fly_exec(bContext *, wmOperator *)
static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata, const XrGrabData *data, const float nav_mat[4][4], const float nav_inv[4][4], bool reverse, float r_delta[4][4])
static float wm_xr_navigation_teleport_pose_calc(wmXrData *xr, float nav_destination[3], const float destination[4], const float normal[3], const bool teleport_axes[3], float teleport_t, float teleport_ofs, float vertical_ofs)
static void wm_xr_fly_uninit(wmOperator *op)
XrRaycastResult
@ XR_RAYCAST_MISS
@ XR_RAYCAST_HIT
@ XR_RAYCAST_FALLBACK
static bool wm_xr_operator_sessionactive(bContext *C)
static void wm_xr_raycast_uninit(wmOperator *op)
static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void wm_xr_navigation_fly_cancel(bContext *, wmOperator *op)
void wm_xr_operatortypes_register()
static void WM_OT_xr_navigation_swap_hands(wmOperatorType *ot)
static void wm_xr_raycast_update(wmOperator *op, const wmXrData *xr, const wmXrActionData *actiondata)
static bool wm_xr_navigation_grab_is_locked(const XrGrabData *data, const bool bimanual)
static const float g_xr_default_raycast_miss_color[4]
static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data)
static wmOperatorStatus wm_xr_session_toggle_exec(bContext *C, wmOperator *)
static const float g_xr_default_raycast_hit_color[4]
static const float g_xr_default_raycast_fallback_color[4]
static wmOperatorStatus wm_xr_navigation_swap_hands_modal(bContext *C, wmOperator *op, const wmEvent *event)
static XrRaycastResult wm_xr_navigation_teleport(bContext *C, wmXrData *xr, float nav_destination[3], float points[XR_MAX_RAYCASTS+1][4], const float direction[3], int *num_points, float *ray_dist, float *destination_dist, bool selectable_only, const bool teleport_axes[3], float teleport_t, float teleport_ofs, float gravity, float head_height)
static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data)
static bool wm_xr_operator_test_event(const wmOperator *op, const wmEvent *event)
static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actiondata, const XrGrabData *data)
static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
static void wm_xr_raycast_destination_draw(const XrRaycastData *data)
static void wm_xr_raycast(Scene *scene, Depsgraph *depsgraph, const float origin[3], const float direction[3], float *ray_dist, bool selectable_only, float r_location[3], float r_normal[3], int *r_index, const Object **r_ob, float r_obmat[4][4])
static void wm_xr_navigation_teleport_cancel(bContext *, wmOperator *op)
static bool wm_xr_navigation_teleport_ground_plane(float points[XR_MAX_RAYCASTS+1][4], int *num_points, float *ray_dist)
static wmOperatorStatus wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus wm_xr_navigation_teleport_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus wm_xr_navigation_fly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
static void wm_xr_navigation_grab_cancel(bContext *, wmOperator *op)
static wmOperatorStatus wm_xr_navigation_teleport_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static const float g_xr_default_raycast_axis[3]
static wmOperatorStatus wm_xr_navigation_grab_exec(bContext *, wmOperator *)
static void WM_OT_xr_navigation_grab(wmOperatorType *ot)
@ XR_FLY_VIEWER_FORWARD
@ XR_FLY_FORWARD
@ XR_FLY_RIGHT
@ XR_FLY_TURNLEFT
@ XR_FLY_CONTROLLER_FORWARD
@ XR_FLY_VIEWER_BACK
@ XR_FLY_VIEWER_RIGHT
@ XR_FLY_BACK
@ XR_FLY_DOWN
@ XR_FLY_UP
@ XR_FLY_TURNRIGHT
@ XR_FLY_LEFT
@ XR_FLY_VIEWER_LEFT
static void wm_xr_raycast_init(wmOperator *op)
static void wm_xr_raycast_draw(const bContext *, ARegion *, void *customdata)
static void wm_xr_grab_compute(const wmXrActionData *actiondata, const XrGrabData *data, const float nav_mat[4][4], const float nav_inv[4][4], bool reverse, float r_delta[4][4])
static void wm_xr_fly_compute_move(eXrFlyMode mode, float speed, const float ref_quat[4], const float nav_mat[4][4], bool locz_lock, float r_delta[4][4])
static void WM_OT_xr_session_toggle(wmOperatorType *ot)
static wmOperatorStatus wm_xr_navigation_grab_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void wm_xr_fly_compute_turn(eXrFlyMode mode, float speed, const float viewer_mat[4][4], const float nav_mat[4][4], const float nav_inv[4][4], float r_delta[4][4])
void WM_xr_session_state_vignette_activate(wmXrData *xr)
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale)
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale)
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *session_root_win, wmXrSessionExitFn session_exit_fn)
bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3])
void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3])
bool WM_xr_session_is_ready(const wmXrData *xr)
bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3])
bool WM_xr_session_exists(const wmXrData *xr)
void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4])
bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4])