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:
committed by
Julian Eisel
parent
1df4a09539
commit
dde9d21b91
@@ -208,6 +208,14 @@ const UserDef U_default = {
|
||||
.flag = 0,
|
||||
},
|
||||
|
||||
.xr_navigation =
|
||||
{
|
||||
.vignette_intensity = 60.0f,
|
||||
.turn_amount = DEG2RAD(30),
|
||||
.turn_speed = DEG2RAD(60),
|
||||
.flag = USER_XR_NAV_SNAP_TURN,
|
||||
},
|
||||
|
||||
.space_data =
|
||||
{
|
||||
.section_active = USER_SECTION_INTERFACE,
|
||||
@@ -246,4 +254,12 @@ const UserDef U_default = {
|
||||
{
|
||||
.is_dirty = 0,
|
||||
},
|
||||
|
||||
.xr_navigation =
|
||||
{
|
||||
.vignette_intensity = 60.0f,
|
||||
.turn_amount = DEG2RAD(30),
|
||||
.turn_speed = DEG2RAD(60),
|
||||
.flag = USER_XR_NAV_SNAP_TURN,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'}),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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):
|
||||
|
||||
67
scripts/addons_core/viewport_vr_preview/preferences.py
Normal file
67
scripts/addons_core/viewport_vr_preview/preferences.py
Normal 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)
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 98
|
||||
#define BLENDER_FILE_SUBVERSION 99
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -3772,6 +3772,12 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 99)) {
|
||||
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
|
||||
wm->xr.session_settings.fly_speed = 3.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
||||
@@ -381,6 +381,11 @@ static void blo_update_defaults_paint(Paint *paint)
|
||||
}
|
||||
}
|
||||
|
||||
static void blo_update_defaults_windowmanager(wmWindowManager *wm)
|
||||
{
|
||||
wm->xr.session_settings.fly_speed = 3.0f;
|
||||
}
|
||||
|
||||
static void blo_update_defaults_scene(Main *bmain, Scene *scene)
|
||||
{
|
||||
ToolSettings *ts = scene->toolsettings;
|
||||
@@ -618,6 +623,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
|
||||
|
||||
/* Work-spaces. */
|
||||
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
|
||||
blo_update_defaults_windowmanager(wm);
|
||||
|
||||
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
||||
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
|
||||
WorkSpaceLayout *layout = BKE_workspace_active_layout_for_workspace_get(
|
||||
|
||||
@@ -1691,6 +1691,13 @@ void blo_do_versions_userdef(UserDef *userdef)
|
||||
}
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(500, 99)) {
|
||||
userdef->xr_navigation.vignette_intensity = 50.0f;
|
||||
userdef->xr_navigation.turn_amount = DEG2RAD(30);
|
||||
userdef->xr_navigation.turn_speed = DEG2RAD(60);
|
||||
userdef->xr_navigation.flag = USER_XR_NAV_SNAP_TURN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a USER_VERSION_ATLEAST check.
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace blender::draw::overlay {
|
||||
class Background : Overlay {
|
||||
private:
|
||||
PassSimple bg_ps_ = {"Background"};
|
||||
PassSimple bg_vignette_ps_ = {"Background Vignette"};
|
||||
|
||||
gpu::FrameBuffer *framebuffer_ref_ = nullptr;
|
||||
|
||||
@@ -31,6 +32,7 @@ class Background : Overlay {
|
||||
DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND;
|
||||
float4 color_override(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
int background_type;
|
||||
const float vignette_aperture = state.v3d->vignette_aperture, vignette_falloff = 0.15f;
|
||||
|
||||
if (state.is_viewport_image_render && !state.draw_background) {
|
||||
background_type = BG_SOLID;
|
||||
@@ -96,7 +98,26 @@ class Background : Overlay {
|
||||
bg_ps_.bind_texture("depth_buffer", &res.depth_tx);
|
||||
bg_ps_.push_constant("color_override", color_override);
|
||||
bg_ps_.push_constant("bg_type", background_type);
|
||||
bg_ps_.push_constant("vignette_enabled", false);
|
||||
bg_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
|
||||
if (state.vignette_enabled) {
|
||||
bg_vignette_ps_.init();
|
||||
bg_vignette_ps_.framebuffer_set(&framebuffer_ref_);
|
||||
|
||||
bg_vignette_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
|
||||
bg_vignette_ps_.shader_set(res.shaders->background_fill.get());
|
||||
bg_vignette_ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &res.globals_buf);
|
||||
bg_vignette_ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &res.clip_planes_buf);
|
||||
bg_vignette_ps_.bind_texture("color_buffer", &res.color_render_tx);
|
||||
bg_vignette_ps_.bind_texture("depth_buffer", &res.depth_tx);
|
||||
bg_vignette_ps_.push_constant("color_override", color_override);
|
||||
bg_vignette_ps_.push_constant("bg_type", background_type);
|
||||
bg_vignette_ps_.push_constant("vignette_enabled", true);
|
||||
bg_vignette_ps_.push_constant("vignette_aperture", vignette_aperture);
|
||||
bg_vignette_ps_.push_constant("vignette_falloff", vignette_falloff);
|
||||
bg_vignette_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_output(Framebuffer &framebuffer, Manager &manager, View &view) final
|
||||
@@ -104,6 +125,12 @@ class Background : Overlay {
|
||||
framebuffer_ref_ = framebuffer;
|
||||
manager.submit(bg_ps_, view);
|
||||
}
|
||||
|
||||
void draw_vignette(Framebuffer &framebuffer, Manager &manager, View &view)
|
||||
{
|
||||
framebuffer_ref_ = framebuffer;
|
||||
manager.submit(bg_vignette_ps_, view);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::draw::overlay
|
||||
|
||||
@@ -66,6 +66,8 @@ void Instance::init()
|
||||
state.xray_opacity = state.xray_enabled ? XRAY_ALPHA(state.v3d) : 1.0f;
|
||||
state.xray_flag_enabled = SHADING_XRAY_FLAG_ENABLED(state.v3d->shading) &&
|
||||
!state.is_depth_only_drawing;
|
||||
state.vignette_enabled = ctx->mode == DRWContext::VIEWPORT_XR &&
|
||||
state.v3d->vignette_aperture < M_SQRT1_2;
|
||||
|
||||
const bool viewport_uses_workbench = state.v3d->shading.type <= OB_SOLID ||
|
||||
BKE_scene_uses_blender_workbench(state.scene);
|
||||
@@ -962,6 +964,10 @@ void Instance::draw_v3d(Manager &manager, View &view)
|
||||
cursor.draw_output(resources.overlay_output_color_only_fb, manager, view);
|
||||
|
||||
draw_text(resources.overlay_output_color_only_fb);
|
||||
|
||||
if (state.vignette_enabled) {
|
||||
background.draw_vignette(resources.overlay_output_color_only_fb, manager, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,8 @@ struct State {
|
||||
bool draw_background = false;
|
||||
/** True if the render engine outputs satisfactory depth information to the depth buffer. */
|
||||
bool is_render_depth_available = false;
|
||||
/** Whether we should render a vignette over the scene. */
|
||||
bool vignette_enabled = false;
|
||||
/** Should text draw in this mode? */
|
||||
bool show_text = false;
|
||||
bool hide_overlays = false;
|
||||
|
||||
@@ -22,6 +22,9 @@ SAMPLER(0, sampler2D, color_buffer)
|
||||
SAMPLER(1, sampler2DDepth, depth_buffer)
|
||||
PUSH_CONSTANT(int, bg_type)
|
||||
PUSH_CONSTANT(float4, color_override)
|
||||
PUSH_CONSTANT(float, vignette_aperture)
|
||||
PUSH_CONSTANT(float, vignette_falloff)
|
||||
PUSH_CONSTANT(bool, vignette_enabled)
|
||||
FRAGMENT_SOURCE("overlay_background_frag.glsl")
|
||||
FRAGMENT_OUT(0, float4, frag_color)
|
||||
ADDITIONAL_INFO(gpu_fullscreen)
|
||||
|
||||
@@ -31,8 +31,19 @@ void main()
|
||||
* This removes the alpha channel and put the background behind reference images
|
||||
* while masking the reference images by the render alpha.
|
||||
*/
|
||||
float alpha = texture(color_buffer, screen_uv).a;
|
||||
float depth = texture(depth_buffer, screen_uv).r;
|
||||
|
||||
float alpha;
|
||||
float depth;
|
||||
|
||||
if (vignette_enabled) {
|
||||
const float dist = length(screen_uv - 0.5f);
|
||||
alpha = smoothstep(vignette_aperture, vignette_aperture + vignette_falloff, dist);
|
||||
depth = 0.0f;
|
||||
}
|
||||
else {
|
||||
alpha = texture(color_buffer, screen_uv).a;
|
||||
depth = texture(depth_buffer, screen_uv).r;
|
||||
}
|
||||
|
||||
float3 bg_col;
|
||||
float3 col_high;
|
||||
@@ -90,11 +101,16 @@ void main()
|
||||
|
||||
bg_col = mix(bg_col, color_override.rgb, color_override.a);
|
||||
|
||||
/* Mimic alpha under behavior. Result is premultiplied. */
|
||||
frag_color = float4(bg_col, 1.0f) * (1.0f - alpha);
|
||||
if (vignette_enabled) {
|
||||
frag_color = float4(bg_col, alpha);
|
||||
}
|
||||
else {
|
||||
/* Mimic alpha under behavior. Result is premultiplied. */
|
||||
frag_color = float4(bg_col, 1.0f) * (1.0f - alpha);
|
||||
|
||||
/* Special case: If the render is not transparent, do not clear alpha values. */
|
||||
if (depth == 1.0f && alpha == 1.0f) {
|
||||
frag_color.a = 1.0f;
|
||||
/* Special case: If the render is not transparent, do not clear alpha values. */
|
||||
if (depth == 1.0f && alpha == 1.0f) {
|
||||
frag_color.a = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
const float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
float vignette_aperture,
|
||||
bool is_xr_surface,
|
||||
bool is_image_render,
|
||||
bool draw_background,
|
||||
|
||||
@@ -1884,6 +1884,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
const float winmat[4][4],
|
||||
float clip_start,
|
||||
float clip_end,
|
||||
float vignette_aperture,
|
||||
bool is_xr_surface,
|
||||
bool is_image_render,
|
||||
bool draw_background,
|
||||
@@ -1965,6 +1966,7 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
|
||||
v3d.clip_end = clip_end;
|
||||
/* Actually not used since we pass in the projection matrix. */
|
||||
v3d.lens = 0;
|
||||
v3d.vignette_aperture = vignette_aperture;
|
||||
|
||||
/* WORKAROUND: Disable overscan because it is not supported for arbitrary input matrices.
|
||||
* The proper fix to this would be to support arbitrary matrices in `eevee::Camera::sync()`. */
|
||||
|
||||
@@ -486,6 +486,7 @@ set(GLSL_SRC
|
||||
shaders/infos/gpu_shader_sequencer_infos.hh
|
||||
shaders/infos/gpu_shader_simple_lighting_infos.hh
|
||||
shaders/infos/gpu_shader_text_infos.hh
|
||||
shaders/infos/gpu_shader_xr_raycast_infos.hh
|
||||
shaders/infos/gpu_srgb_to_framebuffer_space_infos.hh
|
||||
|
||||
shaders/gpu_shader_depth_only_frag.glsl
|
||||
@@ -540,6 +541,7 @@ set(GLSL_SRC
|
||||
|
||||
shaders/gpu_shader_text_vert.glsl
|
||||
shaders/gpu_shader_text_frag.glsl
|
||||
shaders/gpu_shader_xr_raycast_vert.glsl
|
||||
shaders/gpu_shader_keyframe_shape_vert.glsl
|
||||
shaders/gpu_shader_keyframe_shape_frag.glsl
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ enum GPUBuiltinShader {
|
||||
/** Draw sequencer zebra pattern (overexposed regions). */
|
||||
GPU_SHADER_SEQUENCER_ZEBRA,
|
||||
|
||||
/** Draw xr raycast as a ruled spline surface. */
|
||||
GPU_SHADER_XR_RAYCAST,
|
||||
|
||||
/** Compute shaders to generate 2d index buffers (mainly for curve drawing). */
|
||||
GPU_SHADER_INDEXBUF_POINTS,
|
||||
GPU_SHADER_INDEXBUF_LINES,
|
||||
|
||||
11
source/blender/gpu/GPU_xr_defines.hh
Normal file
11
source/blender/gpu/GPU_xr_defines.hh
Normal file
@@ -0,0 +1,11 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define XR_MAX_RAYCASTS 8
|
||||
@@ -119,6 +119,8 @@ static const char *builtin_shader_create_info_name(GPUBuiltinShader shader)
|
||||
return "gpu_shader_index_2d_array_lines";
|
||||
case GPU_SHADER_INDEXBUF_TRIS:
|
||||
return "gpu_shader_index_2d_array_tris";
|
||||
case GPU_SHADER_XR_RAYCAST:
|
||||
return "gpu_shader_xr_raycast";
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return "";
|
||||
|
||||
43
source/blender/gpu/shaders/gpu_shader_xr_raycast_vert.glsl
Normal file
43
source/blender/gpu/shaders/gpu_shader_xr_raycast_vert.glsl
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-FileCopyrightText: 2016-2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_xr_raycast_infos.hh"
|
||||
|
||||
VERTEX_SHADER_CREATE_INFO(gpu_shader_xr_raycast)
|
||||
|
||||
vec3 catmull_rom(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t)
|
||||
{
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
return 0.5 * ((2.0 * p1) + (-p0 + p2) * t + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
|
||||
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
|
||||
}
|
||||
|
||||
vec3 get_control_point(int idx)
|
||||
{
|
||||
idx = clamp(idx, 0, control_point_count - 1);
|
||||
return control_points[idx].xyz;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int sample_idx = gl_VertexID >> 1;
|
||||
float side = ((gl_VertexID & 1) != 0) ? -1.0 : 1.0;
|
||||
|
||||
/** Interpolate within the range: [0, segment_count] */
|
||||
float sample_value = float(sample_idx) * float(control_point_count - 1) /
|
||||
float(sample_count - 1);
|
||||
|
||||
int segment_idx = int(sample_value);
|
||||
float t = sample_value - float(segment_idx);
|
||||
|
||||
vec3 p0 = get_control_point(segment_idx - 1);
|
||||
vec3 p1 = get_control_point(segment_idx + 0);
|
||||
vec3 p2 = get_control_point(segment_idx + 1);
|
||||
vec3 p3 = get_control_point(segment_idx + 2);
|
||||
|
||||
vec3 pos = catmull_rom(p0, p1, p2, p3, t) + 0.5 * width * side * right_vector;
|
||||
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#ifdef GPU_SHADER
|
||||
# pragma once
|
||||
# include "gpu_glsl_cpp_stubs.hh"
|
||||
|
||||
# include "GPU_shader_shared.hh"
|
||||
#endif
|
||||
|
||||
#include "GPU_xr_defines.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_xr_raycast)
|
||||
DEFINE_VALUE("XR_MAX_RAYCASTS", STRINGIFY(XR_MAX_RAYCASTS))
|
||||
FRAGMENT_OUT(0, float4, fragColor)
|
||||
PUSH_CONSTANT_ARRAY(float4, control_points, XR_MAX_RAYCASTS + 1)
|
||||
PUSH_CONSTANT(float4x4, ModelViewProjectionMatrix)
|
||||
PUSH_CONSTANT(float4, color)
|
||||
PUSH_CONSTANT(float3, right_vector)
|
||||
PUSH_CONSTANT(float, width)
|
||||
PUSH_CONSTANT(int, control_point_count)
|
||||
PUSH_CONSTANT(int, sample_count)
|
||||
VERTEX_SOURCE("gpu_shader_xr_raycast_vert.glsl")
|
||||
FRAGMENT_SOURCE("gpu_shader_uniform_color_frag.glsl")
|
||||
ADDITIONAL_INFO(gpu_srgb_to_framebuffer_space)
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
@@ -167,6 +167,14 @@ typedef struct WalkNavigation {
|
||||
char _pad0[6];
|
||||
} WalkNavigation;
|
||||
|
||||
typedef struct XrNavigation {
|
||||
float vignette_intensity;
|
||||
float turn_speed;
|
||||
float turn_amount;
|
||||
short flag;
|
||||
char _pad0[2];
|
||||
} XrNavigation;
|
||||
|
||||
typedef struct UserDef_Runtime {
|
||||
/** Mark as changed so the preferences are saved on exit. */
|
||||
char is_dirty;
|
||||
@@ -619,6 +627,7 @@ typedef struct UserDef {
|
||||
char statusbar_flag; /* eUserpref_StatusBar_Flag */
|
||||
|
||||
struct WalkNavigation walk_navigation;
|
||||
struct XrNavigation xr_navigation;
|
||||
|
||||
/** The UI for the user preferences. */
|
||||
UserDef_SpaceData space_data;
|
||||
@@ -1108,6 +1117,12 @@ typedef enum eUserpref_FactorDisplay {
|
||||
USER_FACTOR_AS_PERCENTAGE = 1,
|
||||
} eUserpref_FactorDisplay;
|
||||
|
||||
/** #UserDef.xr_navigation_flag */
|
||||
typedef enum eUserpref_XrNavigationFlags {
|
||||
USER_XR_NAV_SNAP_TURN = (1 << 0),
|
||||
USER_XR_NAV_INVERT_ROTATION = (1 << 1),
|
||||
} eUserpref_XrNavigationFlags;
|
||||
|
||||
typedef enum eUserpref_RenderDisplayType {
|
||||
USER_RENDER_DISPLAY_NONE = 0,
|
||||
USER_RENDER_DISPLAY_SCREEN = 1,
|
||||
|
||||
@@ -350,7 +350,8 @@ typedef struct View3D {
|
||||
|
||||
float lens, grid;
|
||||
float clip_start, clip_end;
|
||||
float ofs[3] DNA_DEPRECATED;
|
||||
float vignette_aperture;
|
||||
float ofs[2] DNA_DEPRECATED;
|
||||
|
||||
char _pad[1];
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@ typedef struct XrSessionSettings {
|
||||
/** Object type settings to apply to VR view (unlike shading, not shared with window 3D-View). */
|
||||
int object_type_exclude_viewport;
|
||||
int object_type_exclude_select;
|
||||
|
||||
/** Fly speed. */
|
||||
float fly_speed;
|
||||
float padding;
|
||||
} XrSessionSettings;
|
||||
|
||||
typedef enum eXrSessionFlag {
|
||||
|
||||
@@ -531,6 +531,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||
SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data),
|
||||
SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data),
|
||||
SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation),
|
||||
SDNA_DEFAULT_DECL_EX(XrNavigation, UserDef.xr_navigation),
|
||||
SDNA_DEFAULT_DECL(bUserAssetLibrary),
|
||||
SDNA_DEFAULT_DECL(bUserExtensionRepo),
|
||||
SDNA_DEFAULT_DECL(bUserAssetShelfSettings),
|
||||
|
||||
@@ -4754,6 +4754,43 @@ static void rna_def_userdef_walk_navigation(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the vertical movement of the mouse");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_xr_navigation(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "XrNavigation", nullptr);
|
||||
RNA_def_struct_sdna(srna, "XrNavigation");
|
||||
RNA_def_struct_ui_text(srna, "VR Navigation", "VR navigation settings");
|
||||
|
||||
prop = RNA_def_property(srna, "vignette_intensity", PROP_FLOAT, PROP_PERCENTAGE);
|
||||
RNA_def_property_range(prop, 0, 100.0);
|
||||
RNA_def_property_ui_range(prop, 0, 100.0, 1000, 0);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Vignette Intensity", "Intensity of vignette that appears when moving");
|
||||
|
||||
prop = RNA_def_property(srna, "turn_speed", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_range(prop, 0, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0, FLT_MAX, 1000, 0);
|
||||
RNA_def_property_ui_text(prop, "Turn Speed", "Turn speed in degrees per second");
|
||||
|
||||
prop = RNA_def_property(srna, "turn_amount", PROP_FLOAT, PROP_ANGLE);
|
||||
RNA_def_property_range(prop, 0, DEG2RAD(360));
|
||||
RNA_def_property_ui_range(prop, 0, DEG2RAD(360), 1000, 0);
|
||||
RNA_def_property_ui_text(prop, "Turn Amount", "Amount in degrees per turn when using snap turn");
|
||||
|
||||
prop = RNA_def_property(srna, "snap_turn", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_XR_NAV_SNAP_TURN);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Snap Turn",
|
||||
"Instantly rotates the camera by a fixed angle instead of smoothly turning");
|
||||
|
||||
prop = RNA_def_property(srna, "invert_rotation", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", USER_XR_NAV_INVERT_ROTATION);
|
||||
RNA_def_property_ui_text(prop, "Invert Rotation", "Reverses the direction of rotation input");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_view(BlenderRNA *brna)
|
||||
{
|
||||
static const EnumPropertyItem timecode_styles[] = {
|
||||
@@ -6493,6 +6530,12 @@ static void rna_def_userdef_input(BlenderRNA *brna)
|
||||
"restarting Blender for changes to take effect)");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_input_devices");
|
||||
|
||||
prop = RNA_def_property(srna, "xr_navigation", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, nullptr, "xr_navigation");
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_struct_type(prop, "XrNavigation");
|
||||
RNA_def_property_ui_text(prop, "XR Navigation", "Settings for navigation in XR");
|
||||
|
||||
# ifdef WITH_INPUT_NDOF
|
||||
/* 3D mouse settings */
|
||||
/* global options */
|
||||
@@ -7439,6 +7482,7 @@ void RNA_def_userdef(BlenderRNA *brna)
|
||||
rna_def_userdef_dothemes(brna);
|
||||
rna_def_userdef_solidlight(brna);
|
||||
rna_def_userdef_walk_navigation(brna);
|
||||
rna_def_userdef_xr_navigation(brna);
|
||||
|
||||
srna = RNA_def_struct(brna, "Preferences", nullptr);
|
||||
RNA_def_struct_sdna(srna, "UserDef");
|
||||
|
||||
@@ -2035,16 +2035,22 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 0.1 * 100, 3);
|
||||
RNA_def_property_ui_text(prop, "Clip Start", "VR viewport near clipping distance");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10 * 100, 3);
|
||||
RNA_def_property_ui_text(prop, "Clip End", "VR viewport far clipping distance");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "fly_speed", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 1e-6f, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 0.5 * 100, 3);
|
||||
RNA_def_property_ui_text(prop, "Fly Speed", "Fly speed in meters per second");
|
||||
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "use_positional_tracking", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_funcs(prop,
|
||||
"rna_XrSessionSettings_use_positional_tracking_get",
|
||||
|
||||
@@ -8,6 +8,7 @@ set(INC
|
||||
gizmo/intern
|
||||
../compositor
|
||||
../editors/include
|
||||
../gpu
|
||||
../makesrna
|
||||
../../../intern/memutil
|
||||
|
||||
|
||||
@@ -2180,6 +2180,9 @@ void WM_xr_session_state_nav_rotation_set(wmXrData *xr, const float rotation[4])
|
||||
bool WM_xr_session_state_nav_scale_get(const wmXrData *xr, float *r_scale);
|
||||
void WM_xr_session_state_nav_scale_set(wmXrData *xr, float scale);
|
||||
void WM_xr_session_state_navigation_reset(wmXrSessionState *state);
|
||||
void WM_xr_session_state_vignette_reset(wmXrSessionState *state);
|
||||
void WM_xr_session_state_vignette_activate(wmXrData *xr);
|
||||
void WM_xr_session_state_vignette_update(wmXrSessionState *state);
|
||||
|
||||
ARegionType *WM_xr_surface_controller_region_type_get();
|
||||
|
||||
|
||||
@@ -184,6 +184,8 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
|
||||
if ((*runtime)->area) {
|
||||
wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
|
||||
wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, (*runtime));
|
||||
|
||||
WM_event_remove_handlers_by_area(&win->handlers, (*runtime)->area);
|
||||
ED_area_offscreen_free(wm, win, (*runtime)->area);
|
||||
(*runtime)->area = nullptr;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_viewport.hh"
|
||||
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#include "wm_xr_intern.hh"
|
||||
@@ -180,6 +182,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata)
|
||||
winmat,
|
||||
settings->clip_start,
|
||||
settings->clip_end,
|
||||
session_state->vignette_data->aperture,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
@@ -337,7 +340,7 @@ static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSes
|
||||
break;
|
||||
case XR_CONTROLLER_DRAW_DARK_RAY:
|
||||
case XR_CONTROLLER_DRAW_LIGHT_RAY:
|
||||
draw_ray = true;
|
||||
draw_ray = !state->is_raycast_shown;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ struct wmXrSessionState {
|
||||
|
||||
bool force_reset_to_base_pose;
|
||||
bool is_view_data_set;
|
||||
bool swap_hands;
|
||||
bool is_raycast_shown;
|
||||
|
||||
/** Current navigation transforms. */
|
||||
GHOST_XrPose nav_pose;
|
||||
@@ -72,6 +74,12 @@ struct wmXrSessionState {
|
||||
struct wmXrActionSet *active_action_set;
|
||||
/* Name of the action set (if any) to activate before the next actions sync. */
|
||||
char active_action_set_next[64]; /* #MAX_NAME. */
|
||||
|
||||
/** The current state and parameters of the vignette that appears while moving. */
|
||||
struct wmXrVignetteData *vignette_data;
|
||||
|
||||
/** Model used to draw teleportation raycast. */
|
||||
blender::gpu::Batch *raycast_model;
|
||||
};
|
||||
|
||||
struct wmXrRuntimeData {
|
||||
@@ -200,6 +208,22 @@ struct wmXrActionSet {
|
||||
ListBase active_haptic_actions;
|
||||
};
|
||||
|
||||
struct wmXrVignetteData {
|
||||
/** Vignette state. */
|
||||
float aperture;
|
||||
float aperture_velocity;
|
||||
|
||||
/** Vignette parameters. */
|
||||
float initial_aperture;
|
||||
float initial_aperture_velocity;
|
||||
|
||||
float aperture_min;
|
||||
float aperture_max;
|
||||
|
||||
float aperture_velocity_max;
|
||||
float aperture_velocity_delta;
|
||||
};
|
||||
|
||||
/* `wm_xr.cc` */
|
||||
|
||||
wmXrRuntimeData *wm_xr_runtime_data_create();
|
||||
|
||||
@@ -37,6 +37,10 @@
|
||||
#include "GPU_immediate.hh"
|
||||
#include "GPU_state.hh"
|
||||
|
||||
#include "GPU_batch_presets.hh"
|
||||
#include "GPU_matrix.hh"
|
||||
#include "GPU_xr_defines.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
@@ -529,6 +533,11 @@ static void wm_xr_navigation_grab_bimanual_state_update(const wmXrActionData *ac
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_navigation_grab_cancel(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
wm_xr_grab_uninit(op);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_grab_modal(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
@@ -542,6 +551,8 @@ static wmOperatorStatus wm_xr_navigation_grab_modal(bContext *C,
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
|
||||
WM_xr_session_state_vignette_activate(xr);
|
||||
|
||||
const bool do_bimanual = wm_xr_navigation_grab_can_do_bimanual(actiondata, data);
|
||||
|
||||
data->loc_lock = RNA_boolean_get(op->ptr, "lock_location");
|
||||
@@ -588,6 +599,7 @@ static void WM_OT_xr_navigation_grab(wmOperatorType *ot)
|
||||
/* Callbacks. */
|
||||
ot->invoke = wm_xr_navigation_grab_invoke;
|
||||
ot->exec = wm_xr_navigation_grab_exec;
|
||||
ot->cancel = wm_xr_navigation_grab_cancel;
|
||||
ot->modal = wm_xr_navigation_grab_modal;
|
||||
ot->poll = wm_xr_operator_sessionactive;
|
||||
|
||||
@@ -613,21 +625,60 @@ static void WM_OT_xr_navigation_grab(wmOperatorType *ot)
|
||||
* \{ */
|
||||
|
||||
static const float g_xr_default_raycast_axis[3] = {0.0f, 0.0f, -1.0f};
|
||||
static const float g_xr_default_raycast_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
|
||||
static const float g_xr_default_raycast_hit_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
|
||||
static const float g_xr_default_raycast_miss_color[4] = {1.0f, 0.35f, 0.35f, 1.0f};
|
||||
static const float g_xr_default_raycast_fallback_color[4] = {0.35f, 0.35f, 1.0f, 1.0f};
|
||||
|
||||
enum XrRaycastResult : uint8_t {
|
||||
XR_RAYCAST_MISS,
|
||||
XR_RAYCAST_HIT,
|
||||
XR_RAYCAST_FALLBACK,
|
||||
};
|
||||
|
||||
struct XrRaycastData {
|
||||
/** Raycast info */
|
||||
bool from_viewer;
|
||||
float origin[3];
|
||||
|
||||
/** Raycast results */
|
||||
XrRaycastResult result;
|
||||
int num_points;
|
||||
float points[XR_MAX_RAYCASTS + 1][4];
|
||||
float direction[3];
|
||||
float end[3];
|
||||
|
||||
/** Raycast visualization parameters */
|
||||
float color[4];
|
||||
float raycast_width;
|
||||
float destination_size;
|
||||
int sample_count;
|
||||
|
||||
blender::gpu::Batch *raycast_model;
|
||||
|
||||
void *draw_handle;
|
||||
};
|
||||
|
||||
static void wm_xr_raycast_destination_draw(const XrRaycastData *data)
|
||||
{
|
||||
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
|
||||
|
||||
blender::gpu::Batch *sphere = GPU_batch_preset_sphere(2);
|
||||
GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
GPU_batch_uniform_4fv(sphere, "color", data->color);
|
||||
|
||||
GPU_matrix_push();
|
||||
GPU_matrix_translate_3fv(data->points[data->num_points - 1]);
|
||||
GPU_matrix_scale_1f(data->destination_size);
|
||||
GPU_batch_draw(sphere);
|
||||
GPU_matrix_pop();
|
||||
}
|
||||
|
||||
static void wm_xr_raycast_draw(const bContext * /*C*/, ARegion * /*region*/, void *customdata)
|
||||
{
|
||||
const XrRaycastData *data = static_cast<const XrRaycastData *>(customdata);
|
||||
|
||||
if (data->result != XR_RAYCAST_MISS) {
|
||||
wm_xr_raycast_destination_draw(data);
|
||||
}
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
|
||||
|
||||
@@ -638,32 +689,37 @@ static void wm_xr_raycast_draw(const bContext * /*C*/, ARegion * /*region*/, voi
|
||||
GPU_depth_test(GPU_DEPTH_NONE);
|
||||
GPU_point_size(7.0f);
|
||||
|
||||
immBegin(GPU_PRIM_POINTS, 1);
|
||||
immVertex3fv(pos, data->end);
|
||||
immBegin(GPU_PRIM_POINTS, data->num_points - 1);
|
||||
|
||||
for (int i = 1; i < data->num_points; ++i) {
|
||||
immVertex3fv(pos, data->points[i]);
|
||||
}
|
||||
|
||||
immEnd();
|
||||
immUnbindProgram();
|
||||
}
|
||||
else {
|
||||
uint col = GPU_vertformat_attr_add(
|
||||
format, "color", blender::gpu::VertAttrType::SFLOAT_32_32_32_32);
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
|
||||
BLI_assert(data->raycast_model != nullptr);
|
||||
|
||||
float viewport[4];
|
||||
GPU_viewport_size_get_f(viewport);
|
||||
immUniform2fv("viewportSize", &viewport[2]);
|
||||
float forward[3];
|
||||
float right[3];
|
||||
|
||||
immUniform1f("lineWidth", 3.0f * U.pixelsize);
|
||||
sub_v3_v3v3(forward, data->points[data->num_points - 1], data->points[0]);
|
||||
copy_v3_fl3(right, forward[1], -forward[0], 0.0f);
|
||||
normalize_v3(right);
|
||||
|
||||
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
|
||||
|
||||
immBegin(GPU_PRIM_LINES, 2);
|
||||
immAttrSkip(col);
|
||||
immVertex3fv(pos, data->origin);
|
||||
immAttr4fv(col, data->color);
|
||||
immVertex3fv(pos, data->end);
|
||||
immEnd();
|
||||
GPU_batch_program_set_builtin(data->raycast_model, GPU_SHADER_XR_RAYCAST);
|
||||
GPU_batch_uniform_4fv_array(
|
||||
data->raycast_model, "control_points", XR_MAX_RAYCASTS + 1, data->points);
|
||||
GPU_batch_uniform_4fv(data->raycast_model, "color", data->color);
|
||||
GPU_batch_uniform_3fv(data->raycast_model, "right_vector", right);
|
||||
GPU_batch_uniform_1f(data->raycast_model, "width", data->raycast_width);
|
||||
GPU_batch_uniform_1i(data->raycast_model, "control_point_count", data->num_points);
|
||||
GPU_batch_uniform_1i(data->raycast_model, "sample_count", data->sample_count);
|
||||
GPU_batch_draw(data->raycast_model);
|
||||
}
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
|
||||
static void wm_xr_raycast_init(wmOperator *op)
|
||||
@@ -712,27 +768,34 @@ static void wm_xr_raycast_update(wmOperator *op,
|
||||
const wmXrActionData *actiondata)
|
||||
{
|
||||
XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
|
||||
float ray_length, axis[3];
|
||||
float axis[3], nav_scale;
|
||||
|
||||
WM_xr_session_state_nav_scale_get(xr, &nav_scale);
|
||||
|
||||
data->from_viewer = RNA_boolean_get(op->ptr, "from_viewer");
|
||||
data->raycast_width = RNA_float_get(op->ptr, "raycast_scale") * nav_scale;
|
||||
data->sample_count = RNA_int_get(op->ptr, "sample_count");
|
||||
RNA_float_get_array(op->ptr, "axis", axis);
|
||||
RNA_float_get_array(op->ptr, "color", data->color);
|
||||
|
||||
if (data->from_viewer) {
|
||||
float viewer_rot[4];
|
||||
WM_xr_session_state_viewer_pose_location_get(xr, data->origin);
|
||||
WM_xr_session_state_viewer_pose_location_get(xr, data->points[0]);
|
||||
WM_xr_session_state_viewer_pose_rotation_get(xr, viewer_rot);
|
||||
mul_qt_v3(viewer_rot, axis);
|
||||
ray_length = (xr->session_settings.clip_start + xr->session_settings.clip_end) / 2.0f;
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(data->origin, actiondata->controller_loc);
|
||||
if (!xr->runtime->session_state.raycast_model) {
|
||||
xr->runtime->session_state.raycast_model = GPU_batch_create_procedural(
|
||||
GPU_PRIM_TRI_STRIP, 2 * data->sample_count);
|
||||
}
|
||||
|
||||
data->raycast_model = xr->runtime->session_state.raycast_model;
|
||||
|
||||
copy_v3_v3(data->points[0], actiondata->controller_loc);
|
||||
mul_qt_v3(actiondata->controller_rot, axis);
|
||||
ray_length = xr->session_settings.clip_end;
|
||||
}
|
||||
|
||||
copy_v3_v3(data->direction, axis);
|
||||
madd_v3_v3v3fl(data->end, data->origin, data->direction, ray_length);
|
||||
}
|
||||
|
||||
static void wm_xr_raycast(Scene *scene,
|
||||
@@ -779,8 +842,6 @@ static void wm_xr_raycast(Scene *scene,
|
||||
* controller.
|
||||
* \{ */
|
||||
|
||||
#define XR_DEFAULT_FLY_SPEED_MOVE 0.054f
|
||||
|
||||
enum eXrFlyMode {
|
||||
XR_FLY_FORWARD = 0,
|
||||
XR_FLY_BACK = 1,
|
||||
@@ -800,6 +861,9 @@ enum eXrFlyMode {
|
||||
struct XrFlyData {
|
||||
float viewer_rot[4];
|
||||
double time_prev;
|
||||
|
||||
/* Only used for snap turn, where the action should be executed only once. */
|
||||
bool is_finished;
|
||||
};
|
||||
|
||||
static void wm_xr_fly_init(wmOperator *op, const wmXrData *xr)
|
||||
@@ -946,6 +1010,11 @@ static wmOperatorStatus wm_xr_navigation_fly_exec(bContext * /*C*/, wmOperator *
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void wm_xr_navigation_fly_cancel(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
wm_xr_fly_uninit(op);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
@@ -964,22 +1033,41 @@ static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C,
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
eXrFlyMode mode;
|
||||
bool turn, locz_lock, dir_lock, speed_frame_based;
|
||||
bool turn, snap_turn, invert_rotation, swap_hands, locz_lock, dir_lock, speed_frame_based;
|
||||
bool speed_interp_cubic = false;
|
||||
float speed, speed_max, speed_p0[2], speed_p1[2];
|
||||
float speed, speed_max, speed_p0[2], speed_p1[2], button_state;
|
||||
GHOST_XrPose nav_pose;
|
||||
float nav_mat[4][4], delta[4][4], out[4][4];
|
||||
|
||||
const double time_now = BLI_time_now_seconds();
|
||||
const double time_now = BLI_time_now_seconds(), delta_time = time_now - data->time_prev;
|
||||
data->time_prev = time_now;
|
||||
|
||||
mode = (eXrFlyMode)RNA_enum_get(op->ptr, "mode");
|
||||
swap_hands = xr->runtime->session_state.swap_hands;
|
||||
mode = (eXrFlyMode)RNA_enum_get(op->ptr, swap_hands ? "alt_mode" : "mode");
|
||||
turn = ELEM(mode, XR_FLY_TURNLEFT, XR_FLY_TURNRIGHT);
|
||||
snap_turn = U.xr_navigation.flag & USER_XR_NAV_SNAP_TURN;
|
||||
invert_rotation = U.xr_navigation.flag & USER_XR_NAV_INVERT_ROTATION;
|
||||
|
||||
locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
|
||||
dir_lock = RNA_boolean_get(op->ptr, "lock_direction");
|
||||
speed_frame_based = RNA_boolean_get(op->ptr, "speed_frame_based");
|
||||
speed = RNA_float_get(op->ptr, "speed_min");
|
||||
speed_max = RNA_float_get(op->ptr, "speed_max");
|
||||
locz_lock = RNA_boolean_get(op->ptr, swap_hands ? "alt_lock_location_z" : "lock_location_z");
|
||||
dir_lock = RNA_boolean_get(op->ptr, swap_hands ? "alt_lock_direction" : "lock_direction");
|
||||
|
||||
if (turn) {
|
||||
speed_frame_based = false;
|
||||
|
||||
if (snap_turn) {
|
||||
speed_max = U.xr_navigation.turn_amount;
|
||||
speed = speed_max;
|
||||
}
|
||||
else {
|
||||
speed_max = U.xr_navigation.turn_speed;
|
||||
speed = speed_max * RNA_boolean_get(op->ptr, "turn_speed_factor");
|
||||
}
|
||||
}
|
||||
else {
|
||||
speed_frame_based = RNA_boolean_get(op->ptr, "speed_frame_based");
|
||||
speed_max = xr->session_settings.fly_speed;
|
||||
speed = speed_max * RNA_float_get(op->ptr, "fly_speed_factor");
|
||||
}
|
||||
|
||||
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "speed_interpolation0");
|
||||
if (prop && RNA_property_is_set(op->ptr, prop)) {
|
||||
@@ -1007,14 +1095,15 @@ static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C,
|
||||
/* Interpolate between min/max speeds based on button state. */
|
||||
switch (actiondata->type) {
|
||||
case XR_BOOLEAN_INPUT:
|
||||
button_state = 1.0f;
|
||||
speed = speed_max;
|
||||
break;
|
||||
case XR_FLOAT_INPUT:
|
||||
case XR_VECTOR2F_INPUT: {
|
||||
float state = (actiondata->type == XR_FLOAT_INPUT) ? fabsf(actiondata->state[0]) :
|
||||
len_v2(actiondata->state);
|
||||
button_state = (actiondata->type == XR_FLOAT_INPUT) ? fabsf(actiondata->state[0]) :
|
||||
len_v2(actiondata->state);
|
||||
float speed_t = (actiondata->float_threshold < 1.0f) ?
|
||||
(state - actiondata->float_threshold) /
|
||||
(button_state - actiondata->float_threshold) /
|
||||
(1.0f - actiondata->float_threshold) :
|
||||
1.0f;
|
||||
if (speed_interp_cubic) {
|
||||
@@ -1041,21 +1130,29 @@ static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!speed_frame_based) {
|
||||
/* Adjust speed based on last update time. */
|
||||
speed *= time_now - data->time_prev;
|
||||
}
|
||||
data->time_prev = time_now;
|
||||
|
||||
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_pose_to_mat(&nav_pose, nav_mat);
|
||||
|
||||
if (turn) {
|
||||
if (dir_lock) {
|
||||
if (dir_lock || (snap_turn && data->is_finished) ||
|
||||
(snap_turn && button_state < RNA_float_get(op->ptr, "snap_turn_threshold")))
|
||||
{
|
||||
unit_m4(delta);
|
||||
}
|
||||
else {
|
||||
if (!snap_turn) {
|
||||
WM_xr_session_state_vignette_activate(xr);
|
||||
speed *= delta_time;
|
||||
}
|
||||
else {
|
||||
data->is_finished = true;
|
||||
}
|
||||
|
||||
if (invert_rotation) {
|
||||
speed *= -1.0f;
|
||||
}
|
||||
|
||||
GHOST_XrPose viewer_pose;
|
||||
float viewer_mat[4][4], nav_inv[4][4];
|
||||
|
||||
@@ -1070,10 +1167,16 @@ static wmOperatorStatus wm_xr_navigation_fly_modal(bContext *C,
|
||||
else {
|
||||
float nav_scale, ref_quat[4];
|
||||
|
||||
WM_xr_session_state_vignette_activate(xr);
|
||||
|
||||
/* Adjust speed for base and navigation scale. */
|
||||
WM_xr_session_state_nav_scale_get(xr, &nav_scale);
|
||||
speed *= xr->session_settings.base_scale * nav_scale;
|
||||
|
||||
if (!speed_frame_based) {
|
||||
speed *= delta_time;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
/* Move relative to navigation space. */
|
||||
case XR_FLY_FORWARD:
|
||||
@@ -1140,6 +1243,7 @@ static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
|
||||
/* Callbacks. */
|
||||
ot->invoke = wm_xr_navigation_fly_invoke;
|
||||
ot->exec = wm_xr_navigation_fly_exec;
|
||||
ot->cancel = wm_xr_navigation_fly_cancel;
|
||||
ot->modal = wm_xr_navigation_fly_modal;
|
||||
ot->poll = wm_xr_operator_sessionactive;
|
||||
|
||||
@@ -1179,6 +1283,15 @@ static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
|
||||
prop = RNA_def_enum(ot->srna, "mode", fly_modes, XR_FLY_VIEWER_FORWARD, "Mode", "Fly mode");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_NAVIGATION);
|
||||
|
||||
RNA_def_float(ot->srna,
|
||||
"snap_turn_threshold",
|
||||
0.95f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
"Snap Turn Threshold",
|
||||
"Input state threshold when using snap turn",
|
||||
0.0f,
|
||||
1.0f);
|
||||
RNA_def_boolean(
|
||||
ot->srna, "lock_location_z", false, "Lock Elevation", "Prevent changes to viewer elevation");
|
||||
RNA_def_boolean(ot->srna,
|
||||
@@ -1188,27 +1301,27 @@ static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
|
||||
"Limit movement to viewer's initial direction");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"speed_frame_based",
|
||||
true,
|
||||
false,
|
||||
"Frame Based Speed",
|
||||
"Apply fixed movement deltas every update");
|
||||
RNA_def_float(ot->srna,
|
||||
"speed_min",
|
||||
XR_DEFAULT_FLY_SPEED_MOVE / 3.0f,
|
||||
"turn_speed_factor",
|
||||
1.0 / 3.0f,
|
||||
0.0f,
|
||||
1000.0f,
|
||||
"Minimum Speed",
|
||||
"Minimum move (turn) speed in meters (radians) per second or frame",
|
||||
1.0f,
|
||||
"Turn Speed Factor",
|
||||
"Ratio between the min and max turn speed",
|
||||
0.0f,
|
||||
1000.0f);
|
||||
1.0f);
|
||||
RNA_def_float(ot->srna,
|
||||
"speed_max",
|
||||
XR_DEFAULT_FLY_SPEED_MOVE,
|
||||
"fly_speed_factor",
|
||||
1.0 / 3.0f,
|
||||
0.0f,
|
||||
1000.0f,
|
||||
"Maximum Speed",
|
||||
"Maximum move (turn) speed in meters (radians) per second or frame",
|
||||
1.0f,
|
||||
"Fly Speed Factor",
|
||||
"Ratio between the min and max fly speed",
|
||||
0.0f,
|
||||
1000.0f);
|
||||
1.0f);
|
||||
RNA_def_float_vector(ot->srna,
|
||||
"speed_interpolation0",
|
||||
2,
|
||||
@@ -1229,6 +1342,23 @@ static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
|
||||
"Second cubic spline control point between min/max speeds",
|
||||
0.0f,
|
||||
1.0f);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"alt_mode",
|
||||
fly_modes,
|
||||
XR_FLY_VIEWER_FORWARD,
|
||||
"Mode (Alt)",
|
||||
"Fly mode when hands are swapped");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"alt_lock_location_z",
|
||||
false,
|
||||
"Lock Elevation (Alt)",
|
||||
"When hands are swapped, prevent changes to viewer elevation");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"alt_lock_direction",
|
||||
false,
|
||||
"Lock Direction (Alt)",
|
||||
"When hands are swapped, limit movement to viewer's initial direction");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1239,68 +1369,221 @@ static void WM_OT_xr_navigation_fly(wmOperatorType *ot)
|
||||
* Casts a ray from an XR controller's pose and teleports to any hit geometry.
|
||||
* \{ */
|
||||
|
||||
static void wm_xr_navigation_teleport(bContext *C,
|
||||
wmXrData *xr,
|
||||
const float origin[3],
|
||||
const float direction[3],
|
||||
float *ray_dist,
|
||||
bool selectable_only,
|
||||
const bool teleport_axes[3],
|
||||
float teleport_t,
|
||||
float teleport_ofs)
|
||||
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)
|
||||
{
|
||||
float nav_location[3], nav_rotation[4], viewer_location[3];
|
||||
WM_xr_session_state_nav_location_get(xr, nav_location);
|
||||
WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
|
||||
WM_xr_session_state_viewer_pose_location_get(xr, viewer_location);
|
||||
|
||||
float nav_axes[3][3], projected[3], v0[3], v1[3], destination_with_ofs[3];
|
||||
|
||||
copy_v3_fl(nav_destination, 0.0f);
|
||||
copy_v3_v3(destination_with_ofs, destination);
|
||||
destination_with_ofs[2] += vertical_ofs;
|
||||
|
||||
wm_xr_basenav_rotation_calc(xr, nav_rotation, nav_rotation);
|
||||
quat_to_mat3(nav_axes, nav_rotation);
|
||||
|
||||
/* Project locations onto navigation axes. */
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
project_v3_v3v3_normalized(projected, nav_location, nav_axes[a]);
|
||||
if (teleport_axes[a]) {
|
||||
/* Interpolate between projected locations. */
|
||||
project_v3_v3v3_normalized(v0, destination_with_ofs, nav_axes[a]);
|
||||
project_v3_v3v3_normalized(v1, viewer_location, nav_axes[a]);
|
||||
sub_v3_v3(v0, v1);
|
||||
madd_v3_v3fl(projected, v0, teleport_t);
|
||||
/* Subtract offset. */
|
||||
project_v3_v3v3_normalized(v0, normal, nav_axes[a]);
|
||||
madd_v3_v3fl(projected, v0, teleport_ofs);
|
||||
}
|
||||
/* Add to final location. */
|
||||
add_v3_v3(nav_destination, projected);
|
||||
}
|
||||
|
||||
return len_v3v3(viewer_location, destination);
|
||||
}
|
||||
|
||||
static bool wm_xr_navigation_teleport_ground_plane(float points[XR_MAX_RAYCASTS + 1][4],
|
||||
int *num_points,
|
||||
float *ray_dist)
|
||||
{
|
||||
constexpr uint z = 2;
|
||||
for (int i = 1; i < *num_points; ++i) {
|
||||
float *startpoint = points[i - 1], *endpoint = points[i];
|
||||
|
||||
if ((startpoint[z] < 0) == (endpoint[z] < 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startpoint[z] == endpoint[z]) {
|
||||
break;
|
||||
}
|
||||
|
||||
float segment_ray_dist = len_v3v3(startpoint, endpoint);
|
||||
float alpha = startpoint[z] / (startpoint[z] - endpoint[z]);
|
||||
interp_v3_v3v3(endpoint, startpoint, endpoint, alpha);
|
||||
|
||||
*ray_dist = segment_ray_dist * (i - 1) + len_v3v3(startpoint, endpoint);
|
||||
*num_points = i + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
float location[3];
|
||||
float normal[3];
|
||||
int index;
|
||||
const Object *ob = nullptr;
|
||||
float obmat[4][4];
|
||||
|
||||
wm_xr_raycast(scene,
|
||||
depsgraph,
|
||||
origin,
|
||||
direction,
|
||||
ray_dist,
|
||||
selectable_only,
|
||||
location,
|
||||
normal,
|
||||
&index,
|
||||
&ob,
|
||||
obmat);
|
||||
float normal[3], segment_direction[3];
|
||||
float vertical_ofs = 0;
|
||||
XrRaycastResult result = XR_RAYCAST_MISS;
|
||||
|
||||
/* Teleport. */
|
||||
if (ob) {
|
||||
float nav_location[3], nav_rotation[4], viewer_location[3];
|
||||
float nav_axes[3][3], projected[3], v0[3], v1[3];
|
||||
float out[3] = {0.0f, 0.0f, 0.0f};
|
||||
copy_v3_v3(segment_direction, direction);
|
||||
copy_v3_fl3(normal, 0, 1, 0);
|
||||
|
||||
WM_xr_session_state_nav_location_get(xr, nav_location);
|
||||
WM_xr_session_state_nav_rotation_get(xr, nav_rotation);
|
||||
WM_xr_session_state_viewer_pose_location_get(xr, viewer_location);
|
||||
/* When ray_dist == 0 or -1, the raycast is a line of infinite length. */
|
||||
if (*ray_dist <= 0.0f) {
|
||||
*num_points = 2;
|
||||
}
|
||||
|
||||
wm_xr_basenav_rotation_calc(xr, nav_rotation, nav_rotation);
|
||||
quat_to_mat3(nav_axes, nav_rotation);
|
||||
const float segment_length = *ray_dist / (*num_points - 1);
|
||||
float segment_ray_dist = 0.0f;
|
||||
*ray_dist = 0.0f;
|
||||
|
||||
/* Project locations onto navigation axes. */
|
||||
for (int a = 0; a < 3; ++a) {
|
||||
project_v3_v3v3_normalized(projected, nav_location, nav_axes[a]);
|
||||
if (teleport_axes[a]) {
|
||||
/* Interpolate between projected locations. */
|
||||
project_v3_v3v3_normalized(v0, location, nav_axes[a]);
|
||||
project_v3_v3v3_normalized(v1, viewer_location, nav_axes[a]);
|
||||
sub_v3_v3(v0, v1);
|
||||
madd_v3_v3fl(projected, v0, teleport_t);
|
||||
/* Subtract offset. */
|
||||
project_v3_v3v3_normalized(v0, normal, nav_axes[a]);
|
||||
madd_v3_v3fl(projected, v0, teleport_ofs);
|
||||
for (int i = 1; i < *num_points; ++i) {
|
||||
segment_ray_dist = segment_length;
|
||||
wm_xr_raycast(scene,
|
||||
depsgraph,
|
||||
points[i - 1],
|
||||
segment_direction,
|
||||
&segment_ray_dist,
|
||||
selectable_only,
|
||||
points[i],
|
||||
normal,
|
||||
&index,
|
||||
&ob,
|
||||
obmat);
|
||||
|
||||
*ray_dist += segment_ray_dist;
|
||||
|
||||
if (ob) {
|
||||
*num_points = i + 1;
|
||||
|
||||
/** Ensure normal faces the correct direction */
|
||||
if (dot_v3v3(segment_direction, normal) > 0) {
|
||||
mul_v3_fl(normal, -1.0f);
|
||||
}
|
||||
/* Add to final location. */
|
||||
add_v3_v3(out, projected);
|
||||
|
||||
result = XR_RAYCAST_HIT;
|
||||
break;
|
||||
}
|
||||
|
||||
WM_xr_session_state_nav_location_set(xr, out);
|
||||
madd_v3_v3v3fl(points[i], points[i - 1], segment_direction, segment_length);
|
||||
|
||||
/* Apply gravity */
|
||||
segment_direction[2] -= gravity;
|
||||
normalize_v3(segment_direction);
|
||||
}
|
||||
|
||||
/** Fall back to raycast intersecting with the ground plane. */
|
||||
if (result == XR_RAYCAST_MISS) {
|
||||
vertical_ofs = head_height;
|
||||
|
||||
if (wm_xr_navigation_teleport_ground_plane(points, num_points, ray_dist)) {
|
||||
result = XR_RAYCAST_FALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != XR_RAYCAST_MISS) {
|
||||
float origin[3], dummy_dest[3], dummy_normal[3];
|
||||
|
||||
/* Raycast downward to see if we're on the floor */
|
||||
copy_v3_fl3(segment_direction, 0, 0, -1);
|
||||
|
||||
copy_v3_v3(origin, points[*num_points - 1]);
|
||||
madd_v3_v3fl(origin, normal, teleport_ofs);
|
||||
madd_v3_v3fl(origin, segment_direction, -vertical_ofs);
|
||||
|
||||
segment_ray_dist = head_height;
|
||||
ob = nullptr;
|
||||
wm_xr_raycast(scene,
|
||||
depsgraph,
|
||||
origin,
|
||||
segment_direction,
|
||||
&segment_ray_dist,
|
||||
selectable_only,
|
||||
dummy_dest,
|
||||
dummy_normal,
|
||||
&index,
|
||||
&ob,
|
||||
obmat);
|
||||
|
||||
/* Raycast upward to make sure we don't clip through the ceiling */
|
||||
if (ob) {
|
||||
vertical_ofs = head_height - segment_ray_dist;
|
||||
copy_v3_fl3(segment_direction, 0, 0, 1);
|
||||
|
||||
copy_v3_v3(origin, points[*num_points - 1]);
|
||||
madd_v3_v3fl(origin, normal, teleport_ofs);
|
||||
|
||||
segment_ray_dist = vertical_ofs;
|
||||
ob = nullptr;
|
||||
wm_xr_raycast(scene,
|
||||
depsgraph,
|
||||
origin,
|
||||
segment_direction,
|
||||
&segment_ray_dist,
|
||||
selectable_only,
|
||||
dummy_dest,
|
||||
dummy_normal,
|
||||
&index,
|
||||
&ob,
|
||||
obmat);
|
||||
|
||||
if (ob) {
|
||||
vertical_ofs = max_ff(0.0f, segment_ray_dist - teleport_ofs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate teleportation destination in navigation space */
|
||||
*destination_dist = wm_xr_navigation_teleport_pose_calc(xr,
|
||||
nav_destination,
|
||||
points[*num_points - 1],
|
||||
normal,
|
||||
teleport_axes,
|
||||
teleport_t,
|
||||
teleport_ofs,
|
||||
vertical_ofs);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_teleport_invoke(bContext *C,
|
||||
@@ -1328,6 +1611,11 @@ static wmOperatorStatus wm_xr_navigation_teleport_exec(bContext * /*C*/, wmOpera
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void wm_xr_navigation_teleport_cancel(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
wm_xr_raycast_uninit(op);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_teleport_modal(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
@@ -1340,32 +1628,66 @@ static wmOperatorStatus wm_xr_navigation_teleport_modal(bContext *C,
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
|
||||
xr->runtime->session_state.is_raycast_shown = true;
|
||||
wm_xr_raycast_update(op, xr, actiondata);
|
||||
|
||||
XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
|
||||
float nav_scale, ray_dist, destination_dist, nav_destination[3];
|
||||
bool teleport_axes[3];
|
||||
|
||||
WM_xr_session_state_nav_scale_get(xr, &nav_scale);
|
||||
|
||||
RNA_boolean_get_array(op->ptr, "teleport_axes", teleport_axes);
|
||||
const float teleport_t = RNA_float_get(op->ptr, "interpolation");
|
||||
const float teleport_ofs = RNA_float_get(op->ptr, "offset") * nav_scale;
|
||||
const float gravity = RNA_float_get(op->ptr, "gravity");
|
||||
const float head_height = xr->runtime->session_state.prev_local_pose.position[1] * nav_scale;
|
||||
const bool selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
|
||||
ray_dist = RNA_float_get(op->ptr, "distance") * nav_scale;
|
||||
|
||||
data->num_points = XR_MAX_RAYCASTS + 1;
|
||||
data->result = wm_xr_navigation_teleport(C,
|
||||
xr,
|
||||
nav_destination,
|
||||
data->points,
|
||||
data->direction,
|
||||
&data->num_points,
|
||||
&ray_dist,
|
||||
&destination_dist,
|
||||
selectable_only,
|
||||
teleport_axes,
|
||||
teleport_t,
|
||||
teleport_ofs,
|
||||
gravity,
|
||||
head_height);
|
||||
|
||||
data->destination_size = RNA_float_get(op->ptr, "destination_scale") *
|
||||
sqrt(destination_dist / nav_scale) * nav_scale;
|
||||
|
||||
switch (data->result) {
|
||||
case XR_RAYCAST_MISS:
|
||||
RNA_float_get_array(op->ptr, "miss_color", data->color);
|
||||
break;
|
||||
case XR_RAYCAST_HIT:
|
||||
RNA_float_get_array(op->ptr, "hit_color", data->color);
|
||||
break;
|
||||
case XR_RAYCAST_FALLBACK:
|
||||
RNA_float_get_array(op->ptr, "fallback_color", data->color);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event->val) {
|
||||
case KM_PRESS:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
case KM_RELEASE: {
|
||||
XrRaycastData *data = static_cast<XrRaycastData *>(op->customdata);
|
||||
bool selectable_only, teleport_axes[3];
|
||||
float teleport_t, teleport_ofs, ray_dist;
|
||||
|
||||
RNA_boolean_get_array(op->ptr, "teleport_axes", teleport_axes);
|
||||
teleport_t = RNA_float_get(op->ptr, "interpolation");
|
||||
teleport_ofs = RNA_float_get(op->ptr, "offset");
|
||||
selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
|
||||
ray_dist = RNA_float_get(op->ptr, "distance");
|
||||
|
||||
wm_xr_navigation_teleport(C,
|
||||
xr,
|
||||
data->origin,
|
||||
data->direction,
|
||||
&ray_dist,
|
||||
selectable_only,
|
||||
teleport_axes,
|
||||
teleport_t,
|
||||
teleport_ofs);
|
||||
if (data->result != XR_RAYCAST_MISS) {
|
||||
WM_xr_session_state_nav_location_set(xr, nav_destination);
|
||||
}
|
||||
|
||||
xr->runtime->session_state.is_raycast_shown = false;
|
||||
wm_xr_raycast_uninit(op);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -1388,6 +1710,7 @@ static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
|
||||
/* Callbacks. */
|
||||
ot->invoke = wm_xr_navigation_teleport_invoke;
|
||||
ot->exec = wm_xr_navigation_teleport_exec;
|
||||
ot->cancel = wm_xr_navigation_teleport_cancel;
|
||||
ot->modal = wm_xr_navigation_teleport_modal;
|
||||
ot->poll = wm_xr_operator_sessionactive;
|
||||
|
||||
@@ -1411,7 +1734,7 @@ static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
|
||||
1.0f);
|
||||
RNA_def_float(ot->srna,
|
||||
"offset",
|
||||
0.0f,
|
||||
0.25f,
|
||||
0.0f,
|
||||
FLT_MAX,
|
||||
"Offset",
|
||||
@@ -1425,13 +1748,49 @@ static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
|
||||
"Only allow selectable objects to influence raycast result");
|
||||
RNA_def_float(ot->srna,
|
||||
"distance",
|
||||
BVH_RAYCAST_DIST_MAX,
|
||||
80.0,
|
||||
0.0,
|
||||
BVH_RAYCAST_DIST_MAX,
|
||||
"",
|
||||
"Maximum raycast distance",
|
||||
0.0,
|
||||
BVH_RAYCAST_DIST_MAX);
|
||||
RNA_def_float(ot->srna,
|
||||
"gravity",
|
||||
0.1,
|
||||
0.0,
|
||||
FLT_MAX,
|
||||
"Gravity",
|
||||
"Downward curvature applied to raycast",
|
||||
0.0,
|
||||
FLT_MAX);
|
||||
RNA_def_float(ot->srna,
|
||||
"raycast_scale",
|
||||
0.02f,
|
||||
0.0f,
|
||||
FLT_MAX,
|
||||
"Raycast Scale",
|
||||
"Width of the raycast visualization",
|
||||
0.0f,
|
||||
FLT_MAX);
|
||||
RNA_def_float(ot->srna,
|
||||
"destination_scale",
|
||||
0.05f,
|
||||
0.0f,
|
||||
FLT_MAX,
|
||||
"Destination Scale",
|
||||
"Width of the destination visualization",
|
||||
0.0f,
|
||||
FLT_MAX);
|
||||
RNA_def_int(ot->srna,
|
||||
"sample_count",
|
||||
48,
|
||||
2,
|
||||
INT_MAX,
|
||||
"Sample Count",
|
||||
"Number of interpolation samples for the raycast visualization",
|
||||
2,
|
||||
INT_MAX);
|
||||
RNA_def_boolean(
|
||||
ot->srna, "from_viewer", false, "From Viewer", "Use viewer pose as raycast origin");
|
||||
RNA_def_float_vector(ot->srna,
|
||||
@@ -1445,13 +1804,33 @@ static void WM_OT_xr_navigation_teleport(wmOperatorType *ot)
|
||||
-1.0f,
|
||||
1.0f);
|
||||
RNA_def_float_color(ot->srna,
|
||||
"color",
|
||||
"hit_color",
|
||||
4,
|
||||
g_xr_default_raycast_color,
|
||||
g_xr_default_raycast_hit_color,
|
||||
0.0f,
|
||||
1.0f,
|
||||
"Color",
|
||||
"Raycast color",
|
||||
"Hit Color",
|
||||
"Color of raycast when it succeeds",
|
||||
0.0f,
|
||||
1.0f);
|
||||
RNA_def_float_color(ot->srna,
|
||||
"miss_color",
|
||||
4,
|
||||
g_xr_default_raycast_miss_color,
|
||||
0.0f,
|
||||
1.0f,
|
||||
"Miss Color",
|
||||
"Color of raycast when it misses",
|
||||
0.0f,
|
||||
1.0f);
|
||||
RNA_def_float_color(ot->srna,
|
||||
"fallback_color",
|
||||
4,
|
||||
g_xr_default_raycast_fallback_color,
|
||||
0.0f,
|
||||
1.0f,
|
||||
"Fallback Color",
|
||||
"Color of raycast when a fallback case succeeds",
|
||||
0.0f,
|
||||
1.0f);
|
||||
}
|
||||
@@ -1547,6 +1926,74 @@ static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name XR Navigation Swap Hands
|
||||
*
|
||||
* Resets XR navigation deltas relative to session base pose.
|
||||
* \{ */
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_swap_hands_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
if (!wm_xr_operator_test_event(op, event)) {
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
|
||||
xr->runtime->session_state.swap_hands = true;
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_swap_hands_exec(bContext * /*C*/, wmOperator * /*op*/)
|
||||
{
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_xr_navigation_swap_hands_modal(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
if (!wm_xr_operator_test_event(op, event)) {
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wmXrData *xr = &wm->xr;
|
||||
|
||||
switch (event->val) {
|
||||
case KM_PRESS:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
case KM_RELEASE:
|
||||
xr->runtime->session_state.swap_hands = false;
|
||||
return OPERATOR_FINISHED;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
static void WM_OT_xr_navigation_swap_hands(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "XR Navigation Swap Hands";
|
||||
ot->idname = "WM_OT_xr_navigation_swap_hands";
|
||||
ot->description = "Swap VR navigation controls between left / right controllers";
|
||||
|
||||
/* Callbacks. */
|
||||
ot->invoke = wm_xr_navigation_swap_hands_invoke;
|
||||
ot->exec = wm_xr_navigation_swap_hands_exec;
|
||||
ot->modal = wm_xr_navigation_swap_hands_modal;
|
||||
ot->poll = wm_xr_operator_sessionactive;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Operator Registration
|
||||
* \{ */
|
||||
@@ -1558,6 +2005,7 @@ void wm_xr_operatortypes_register()
|
||||
WM_operatortype_append(WM_OT_xr_navigation_fly);
|
||||
WM_operatortype_append(WM_OT_xr_navigation_teleport);
|
||||
WM_operatortype_append(WM_OT_xr_navigation_reset);
|
||||
WM_operatortype_append(WM_OT_xr_navigation_swap_hands);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -71,6 +71,10 @@ static void wm_xr_session_create_cb()
|
||||
settings->base_scale = 1.0f;
|
||||
}
|
||||
state->prev_base_scale = settings->base_scale;
|
||||
|
||||
/* Initialize vignette. */
|
||||
state->vignette_data = MEM_callocN<wmXrVignetteData>(__func__);
|
||||
WM_xr_session_state_vignette_reset(state);
|
||||
}
|
||||
|
||||
static void wm_xr_session_controller_data_free(wmXrSessionState *state)
|
||||
@@ -84,9 +88,27 @@ static void wm_xr_session_controller_data_free(wmXrSessionState *state)
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_session_vignette_data_free(wmXrSessionState *state)
|
||||
{
|
||||
if (state->vignette_data) {
|
||||
MEM_freeN(state->vignette_data);
|
||||
state->vignette_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_xr_session_raycast_model_free(wmXrSessionState *state)
|
||||
{
|
||||
if (state->raycast_model) {
|
||||
GPU_batch_discard(state->raycast_model);
|
||||
state->raycast_model = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void wm_xr_session_data_free(wmXrSessionState *state)
|
||||
{
|
||||
wm_xr_session_controller_data_free(state);
|
||||
wm_xr_session_vignette_data_free(state);
|
||||
wm_xr_session_raycast_model_free(state);
|
||||
}
|
||||
|
||||
static void wm_xr_session_exit_cb(void *customdata)
|
||||
@@ -384,6 +406,8 @@ void wm_xr_session_state_update(const XrSessionSettings *settings,
|
||||
state->is_view_data_set = true;
|
||||
/* Assume this was already done through wm_xr_session_draw_data_update(). */
|
||||
state->force_reset_to_base_pose = false;
|
||||
|
||||
WM_xr_session_state_vignette_update(state);
|
||||
}
|
||||
|
||||
wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr)
|
||||
@@ -572,6 +596,52 @@ void WM_xr_session_state_navigation_reset(wmXrSessionState *state)
|
||||
unit_qt(state->nav_pose.orientation_quat);
|
||||
state->nav_scale = 1.0f;
|
||||
state->is_navigation_dirty = true;
|
||||
state->swap_hands = false;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_vignette_reset(wmXrSessionState *state)
|
||||
{
|
||||
wmXrVignetteData *data = state->vignette_data;
|
||||
|
||||
/* Reset vignette state */
|
||||
data->aperture = 1.0f;
|
||||
data->aperture_velocity = 0.0f;
|
||||
|
||||
/* Set default vignette parameters */
|
||||
data->initial_aperture = 0.25f;
|
||||
data->initial_aperture_velocity = -0.03f;
|
||||
|
||||
data->aperture_min = 0.08f;
|
||||
data->aperture_max = 0.3f;
|
||||
|
||||
data->aperture_velocity_max = 0.002f;
|
||||
data->aperture_velocity_delta = 0.01f;
|
||||
}
|
||||
|
||||
void WM_xr_session_state_vignette_activate(wmXrData *xr)
|
||||
{
|
||||
if (WM_xr_session_exists(xr)) {
|
||||
wmXrVignetteData *data = xr->runtime->session_state.vignette_data;
|
||||
data->aperture_velocity = data->initial_aperture_velocity;
|
||||
data->aperture = min_ff(data->aperture, data->initial_aperture);
|
||||
}
|
||||
}
|
||||
|
||||
void WM_xr_session_state_vignette_update(wmXrSessionState *state)
|
||||
{
|
||||
wmXrVignetteData *data = state->vignette_data;
|
||||
|
||||
const float vignette_intensity = U.xr_navigation.vignette_intensity;
|
||||
const float aperture_min = interpf(
|
||||
data->aperture_min, data->aperture_max, vignette_intensity * 0.01f);
|
||||
data->aperture_velocity = min_ff(data->aperture_velocity_max,
|
||||
data->aperture_velocity + data->aperture_velocity_delta);
|
||||
|
||||
if (data->aperture == aperture_min) {
|
||||
data->aperture_velocity = data->aperture_velocity_max;
|
||||
}
|
||||
|
||||
data->aperture = clamp_f(data->aperture + data->aperture_velocity, aperture_min, 1.0f);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
Reference in New Issue
Block a user