OpenXR: VR Advanced Locomotion Phase 1

Includes the following changes to the existing Locomotion system for VR Scene Inspection:
 * new VR Navigation Preferences and VR Session Settings
 * changes to XR raycast logic and its visualization
 * new XR vignette that appears when moving
 * snap turning

Pull Request: https://projects.blender.org/blender/blender/pulls/144241
This commit is contained in:
hogan.mastanduno
2025-10-01 22:16:12 +02:00
committed by Julian Eisel
parent 1df4a09539
commit dde9d21b91
36 changed files with 1146 additions and 169 deletions

View File

@@ -24,8 +24,9 @@ if "bpy" in locals():
importlib.reload(gui)
importlib.reload(operators)
importlib.reload(properties)
importlib.reload(preferences)
else:
from . import action_map, gui, operators, properties
from . import action_map, gui, operators, properties, preferences
import bpy
@@ -39,6 +40,7 @@ def register():
gui.register()
operators.register()
properties.register()
preferences.register()
def unregister():
@@ -50,3 +52,4 @@ def unregister():
gui.unregister()
operators.unregister()
properties.unregister()
preferences.unregister()

View File

@@ -37,7 +37,8 @@ actionconfig_data = \
("teleport", {"type": 'FLOAT', "user_paths": ['/user/hand/left', '/user/hand/right'], "op": 'wm.xr_navigation_teleport', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("interpolation", 0.9),
("color", (0.0, 1.0, 1.0, 1.0)),
("hit_color", (0.0, 1.0, 1.0, 1.0)),
("miss_color", (1.0, 0.0, 0.0, 1.0)),
],
},
{"bindings":
@@ -74,6 +75,7 @@ actionconfig_data = \
("fly_forward", {"type": 'FLOAT', "user_paths": ['/user/hand/left'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_FORWARD'),
("alt_mode", 'UP'),
("lock_location_z", True),
],
},
@@ -92,6 +94,7 @@ actionconfig_data = \
("fly_back", {"type": 'FLOAT', "user_paths": ['/user/hand/left'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_BACK'),
("alt_mode", 'DOWN'),
("lock_location_z", True),
],
},
@@ -110,6 +113,7 @@ actionconfig_data = \
("fly_left", {"type": 'FLOAT', "user_paths": ['/user/hand/left'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_LEFT'),
("alt_mode", 'TURNLEFT'),
("lock_location_z", True),
],
},
@@ -128,6 +132,7 @@ actionconfig_data = \
("fly_right", {"type": 'FLOAT', "user_paths": ['/user/hand/left'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_RIGHT'),
("alt_mode", 'TURNRIGHT'),
("lock_location_z", True),
],
},
@@ -146,8 +151,8 @@ actionconfig_data = \
("fly_up", {"type": 'FLOAT', "user_paths": ['/user/hand/right'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'UP'),
("speed_min", 0.014),
("speed_max", 0.042),
("alt_mode", 'VIEWER_FORWARD'),
("alt_lock_location_z", True),
],
},
{"bindings":
@@ -165,8 +170,8 @@ actionconfig_data = \
("fly_down", {"type": 'FLOAT', "user_paths": ['/user/hand/right'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'DOWN'),
("speed_min", 0.014),
("speed_max", 0.042),
("alt_mode", 'VIEWER_BACK'),
("alt_lock_location_z", True),
],
},
{"bindings":
@@ -184,8 +189,8 @@ actionconfig_data = \
("fly_turnleft", {"type": 'FLOAT', "user_paths": ['/user/hand/right'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'TURNLEFT'),
("speed_min", 0.01),
("speed_max", 0.03),
("alt_mode", 'VIEWER_LEFT'),
("alt_lock_location_z", True),
],
},
{"bindings":
@@ -203,8 +208,8 @@ actionconfig_data = \
("fly_turnright", {"type": 'FLOAT', "user_paths": ['/user/hand/right'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'TURNRIGHT'),
("speed_min", 0.01),
("speed_max", 0.03),
("alt_mode", 'VIEWER_RIGHT'),
("alt_lock_location_z", True),
],
},
{"bindings":
@@ -261,7 +266,8 @@ actionconfig_data = \
{"op_properties":
[("interpolation", 0.9),
("from_viewer", True),
("color", (0.0, 1.0, 1.0, 1.0)),
("hit_color", (0.0, 1.0, 1.0, 1.0)),
("miss_color", (1.0, 0.0, 0.0, 1.0)),
],
},
{"bindings":
@@ -278,6 +284,7 @@ actionconfig_data = \
("fly_forward", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_FORWARD'),
("alt_mode", 'UP'),
("lock_location_z", True),
],
},
@@ -289,6 +296,7 @@ actionconfig_data = \
("fly_back", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_BACK'),
("alt_mode", 'DOWN'),
("lock_location_z", True),
],
},
@@ -300,6 +308,7 @@ actionconfig_data = \
("fly_left", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_LEFT'),
("alt_mode", 'TURNLEFT'),
("lock_location_z", True),
],
},
@@ -311,6 +320,7 @@ actionconfig_data = \
("fly_right", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'VIEWER_RIGHT'),
("alt_mode", 'TURNRIGHT'),
("lock_location_z", True),
],
},
@@ -322,9 +332,9 @@ actionconfig_data = \
("fly_up", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'UP'),
("speed_min", 0.014),
("speed_max", 0.042),
],
("alt_mode", 'VIEWER_FORWARD'),
("alt_lock_location_z", True),
]
},
{"bindings":
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_paths": ['/input/thumbstick_right/y'], "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
@@ -334,9 +344,9 @@ actionconfig_data = \
("fly_down", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'DOWN'),
("speed_min", 0.014),
("speed_max", 0.042),
],
("alt_mode", 'VIEWER_BACK'),
("alt_lock_location_z", True),
]
},
{"bindings":
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_paths": ['/input/thumbstick_right/y'], "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
@@ -346,9 +356,9 @@ actionconfig_data = \
("fly_turnleft", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'TURNLEFT'),
("speed_min", 0.01),
("speed_max", 0.03),
],
("alt_mode", 'VIEWER_LEFT'),
("alt_lock_location_z", True),
]
},
{"bindings":
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_paths": ['/input/thumbstick_right/x'], "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
@@ -358,9 +368,9 @@ actionconfig_data = \
("fly_turnright", {"type": 'FLOAT', "user_paths": ['/user/gamepad'], "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
{"op_properties":
[("mode", 'TURNRIGHT'),
("speed_min", 0.01),
("speed_max", 0.03),
],
("alt_mode", 'VIEWER_RIGHT'),
("alt_lock_location_z", True),
]
},
{"bindings":
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_paths": ['/input/thumbstick_right/x'], "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),

View File

@@ -37,6 +37,7 @@ class VRDefaultActions(Enum):
FLY_TURNLEFT = "fly_turnleft"
FLY_TURNRIGHT = "fly_turnright"
NAV_RESET = "nav_reset"
SWAP_HANDS = "swap_hands"
HAPTIC = "haptic"
HAPTIC_LEFT = "haptic_left"
HAPTIC_RIGHT = "haptic_right"
@@ -1146,6 +1147,91 @@ def vr_defaults_create_default(session_state):
'ANY',
'ANY')
ami = vr_defaults_action_add(am,
VRDefaultActions.SWAP_HANDS.value,
["/user/hand/left",
"/user/hand/right"],
"wm.xr_navigation_swap_hands",
'PRESS',
False,
"haptic",
True,
0.3,
3000.0,
0.5,
'PRESS')
if ami:
"""
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.HUAWEI.value,
VRDefaultActionprofiles.HUAWEI.value,
["/input/back/click",
"/input/back/click"],
0.3,
'ANY',
'ANY')
"""
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.INDEX.value,
VRDefaultActionprofiles.INDEX.value,
["/input/b/click",
"/input/b/click"],
0.3,
'ANY',
'ANY')
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.OCULUS.value,
VRDefaultActionprofiles.OCULUS.value,
["/input/y/click",
"/input/b/click"],
0.3,
'ANY',
'ANY')
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.REVERB_G2.value,
VRDefaultActionprofiles.REVERB_G2.value,
["/input/y/click",
"/input/b/click"],
0.3,
'ANY',
'ANY')
"""
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.VIVE.value,
VRDefaultActionprofiles.VIVE.value,
["/input/menu/click",
"/input/menu/click"],
0.3,
'ANY',
'ANY')
"""
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.VIVE_COSMOS.value,
VRDefaultActionprofiles.VIVE_COSMOS.value,
["/input/y/click",
"/input/b/click"],
0.3,
'ANY',
'ANY')
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.VIVE_FOCUS.value,
VRDefaultActionprofiles.VIVE_FOCUS.value,
["/input/y/click",
"/input/b/click"],
0.3,
'ANY',
'ANY')
"""
vr_defaults_actionbinding_add(ami,
VRDefaultActionbindings.WMR.value,
VRDefaultActionprofiles.WMR.value,
["/input/menu/click",
"/input/menu/click"],
0.3,
'ANY',
'ANY')
"""
ami = vr_defaults_haptic_action_add(am,
VRDefaultActions.HAPTIC.value,
["/user/hand/left",

View File

@@ -97,7 +97,9 @@ class VIEW3D_PT_vr_session_view(Panel):
col = layout.column(align=True)
col.prop(session_settings, "clip_start", text="Clip Start")
col.prop(session_settings, "clip_end", text="End", text_ctxt=i18n_contexts.id_camera)
col = layout.column(align=True)
col.prop(session_settings, "fly_speed", text="Fly Speed")
class VIEW3D_PT_vr_session_view_object_type_visibility(VIEW3D_PT_object_type_visibility):
def draw(self, context):

View File

@@ -0,0 +1,67 @@
# SPDX-FileCopyrightText: 2023 Blender Foundation
#
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import (
Panel,
)
class USERPREF_PT_vr_navigation(Panel):
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
bl_context = "navigation"
bl_label = "VR Navigation"
def draw(self, context):
layout = self.layout
width = context.region.width
ui_scale = context.preferences.system.ui_scale
# No horizontal margin if region is rather small.
is_wide = width > (350 * ui_scale)
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
row = layout.row()
if is_wide:
row.label() # Needed so col below is centered.
col = row.column()
col.ui_units_x = 50
# Implemented by sub-classes.
self.draw_centered(context, col)
if is_wide:
row.label() # Needed so col above is centered.
def draw_centered(self, context, layout):
prefs = context.preferences
nav = prefs.inputs.xr_navigation
col = layout.column()
col.row().prop(nav, "vignette_intensity", text="Vignette Intensity")
if nav.snap_turn:
col.row().prop(nav, "turn_amount", text="Turn Amount")
else:
col.row().prop(nav, "turn_speed", text="Turn Speed")
col.row().prop(nav, "snap_turn", text="Snap Turn")
col.row().prop(nav, "invert_rotation", text="Invert Rotation")
classes = (
USERPREF_PT_vr_navigation,
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in classes:
unregister_class(cls)