VR: Split code into more focused modules
Reflects changes from D11271.
This commit is contained in:
parent
f02773d5ed
commit
7a45dbeda2
|
@ -36,156 +36,36 @@ bl_info = {
|
|||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(action_map)
|
||||
importlib.reload(defaults)
|
||||
importlib.reload(main)
|
||||
importlib.reload(gui)
|
||||
importlib.reload(operators)
|
||||
importlib.reload(properties)
|
||||
else:
|
||||
from . import defaults, main
|
||||
from . import action_map, defaults, gui, operators, properties
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
classes = (
|
||||
main.VIEW3D_PT_vr_session,
|
||||
main.VIEW3D_PT_vr_session_view,
|
||||
main.VIEW3D_PT_vr_landmarks,
|
||||
main.VIEW3D_PT_vr_actions_actionmaps,
|
||||
main.VIEW3D_PT_vr_actions_actions,
|
||||
main.VIEW3D_PT_vr_actions_haptics,
|
||||
main.VIEW3D_PT_vr_actions_bindings,
|
||||
main.VIEW3D_PT_vr_actions_extensions,
|
||||
main.VIEW3D_PT_vr_motion_capture,
|
||||
main.VIEW3D_PT_vr_viewport_feedback,
|
||||
|
||||
main.VRLandmark,
|
||||
main.VIEW3D_UL_vr_landmarks,
|
||||
main.VIEW3D_MT_vr_landmark_menu,
|
||||
|
||||
main.VIEW3D_OT_vr_landmark_add,
|
||||
main.VIEW3D_OT_vr_landmark_remove,
|
||||
main.VIEW3D_OT_vr_landmark_activate,
|
||||
main.VIEW3D_OT_vr_landmark_from_session,
|
||||
main.VIEW3D_OT_add_camera_from_vr_landmark,
|
||||
main.VIEW3D_OT_camera_to_vr_landmark,
|
||||
main.VIEW3D_OT_vr_landmark_from_camera,
|
||||
main.VIEW3D_OT_cursor_to_vr_landmark,
|
||||
main.VIEW3D_OT_update_vr_landmark,
|
||||
|
||||
main.VIEW3D_UL_vr_actionmaps,
|
||||
main.VIEW3D_MT_vr_actionmap_menu,
|
||||
main.VIEW3D_UL_vr_actions,
|
||||
main.VIEW3D_MT_vr_action_menu,
|
||||
main.VIEW3D_UL_vr_actionbindings,
|
||||
main.VIEW3D_MT_vr_actionbinding_menu,
|
||||
|
||||
main.VIEW3D_OT_vr_actionmap_add,
|
||||
main.VIEW3D_OT_vr_actionmap_remove,
|
||||
main.VIEW3D_OT_vr_actionmap_activate,
|
||||
main.VIEW3D_OT_vr_actionmaps_defaults_load,
|
||||
main.VIEW3D_OT_vr_actionmaps_import,
|
||||
main.VIEW3D_OT_vr_actionmaps_export,
|
||||
main.VIEW3D_OT_vr_actionmap_copy,
|
||||
main.VIEW3D_OT_vr_actionmaps_clear,
|
||||
main.VIEW3D_OT_vr_action_add,
|
||||
main.VIEW3D_OT_vr_action_remove,
|
||||
main.VIEW3D_OT_vr_action_copy,
|
||||
main.VIEW3D_OT_vr_actions_clear,
|
||||
main.VIEW3D_OT_vr_actionbinding_add,
|
||||
main.VIEW3D_OT_vr_actionbinding_remove,
|
||||
main.VIEW3D_OT_vr_actionbinding_copy,
|
||||
main.VIEW3D_OT_vr_actionbindings_clear,
|
||||
|
||||
main.VRMotionCaptureObject,
|
||||
main.VIEW3D_UL_vr_mocap_objects,
|
||||
main.VIEW3D_MT_vr_mocap_object_menu,
|
||||
|
||||
main.VIEW3D_OT_vr_mocap_object_add,
|
||||
main.VIEW3D_OT_vr_mocap_object_remove,
|
||||
main.VIEW3D_OT_vr_mocap_object_help,
|
||||
|
||||
main.VIEW3D_GT_vr_camera_cone,
|
||||
main.VIEW3D_GT_vr_controller_grip,
|
||||
main.VIEW3D_GT_vr_controller_aim,
|
||||
main.VIEW3D_GGT_vr_viewer_pose,
|
||||
main.VIEW3D_GGT_vr_controller_poses,
|
||||
main.VIEW3D_GGT_vr_landmarks,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
if not bpy.app.build_options.xr_openxr:
|
||||
bpy.utils.register_class(main.VIEW3D_PT_vr_info)
|
||||
bpy.utils.register_class(gui.VIEW3D_PT_vr_info)
|
||||
return
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.vr_landmarks = bpy.props.CollectionProperty(
|
||||
name="Landmark",
|
||||
type=main.VRLandmark,
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_selected = bpy.props.IntProperty(
|
||||
name="Selected Landmark"
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_active = bpy.props.IntProperty(
|
||||
update=main.vr_landmark_active_update,
|
||||
)
|
||||
bpy.types.Scene.vr_actions_enable_cosmos = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the HTC Vive Cosmos controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
bpy.types.Scene.vr_actions_enable_huawei = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the Huawei controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
bpy.types.Scene.vr_actions_enable_reverb_g2 = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the HP Reverb G2 controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
# This scene collection property is needed instead of directly accessing
|
||||
# XrSessionSettings.mocap_objects in the UI to avoid invalid pointers when
|
||||
# deleting objects.
|
||||
bpy.types.Scene.vr_mocap_objects = bpy.props.CollectionProperty(
|
||||
name="Motion Capture Object",
|
||||
type=main.VRMotionCaptureObject,
|
||||
)
|
||||
# View3DShading is the only per 3D-View struct with custom property
|
||||
# support, so "abusing" that to get a per 3D-View option.
|
||||
bpy.types.View3DShading.vr_show_virtual_camera = bpy.props.BoolProperty(
|
||||
name="Show VR Camera"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_controllers = bpy.props.BoolProperty(
|
||||
name="Show VR Controllers"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_landmarks = bpy.props.BoolProperty(
|
||||
name="Show Landmarks"
|
||||
)
|
||||
|
||||
bpy.app.handlers.load_post.append(main.vr_ensure_default_landmark)
|
||||
bpy.app.handlers.load_post.append(defaults.vr_init_default_actionconfig)
|
||||
bpy.app.handlers.load_post.append(main.vr_activate_user_actionconfig)
|
||||
bpy.app.handlers.xr_session_start_pre.append(main.vr_create_actions)
|
||||
defaults.register() # Register before action_map to load defaults before activating user action config.
|
||||
action_map.register()
|
||||
gui.register()
|
||||
operators.register()
|
||||
properties.register()
|
||||
|
||||
|
||||
def unregister():
|
||||
if not bpy.app.build_options.xr_openxr:
|
||||
bpy.utils.unregister_class(main.VIEW3D_PT_vr_info)
|
||||
bpy.utils.unregister_class(gui.VIEW3D_PT_vr_info)
|
||||
return
|
||||
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
del bpy.types.Scene.vr_landmarks
|
||||
del bpy.types.Scene.vr_landmarks_selected
|
||||
del bpy.types.Scene.vr_landmarks_active
|
||||
del bpy.types.Scene.vr_actions_enable_cosmos
|
||||
del bpy.types.Scene.vr_actions_enable_huawei
|
||||
del bpy.types.Scene.vr_actions_enable_reverb_g2
|
||||
del bpy.types.Scene.vr_mocap_objects
|
||||
del bpy.types.View3DShading.vr_show_virtual_camera
|
||||
del bpy.types.View3DShading.vr_show_controllers
|
||||
del bpy.types.View3DShading.vr_show_landmarks
|
||||
|
||||
bpy.app.handlers.load_post.remove(main.vr_ensure_default_landmark)
|
||||
bpy.app.handlers.load_post.remove(defaults.vr_init_default_actionconfig)
|
||||
bpy.app.handlers.load_post.remove(main.vr_activate_user_actionconfig)
|
||||
bpy.app.handlers.xr_session_start_pre.remove(main.vr_create_actions)
|
||||
defaults.unregister()
|
||||
action_map.unregister()
|
||||
gui.unregister()
|
||||
operators.unregister()
|
||||
properties.unregister()
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(defaults)
|
||||
else:
|
||||
from . import action_map_io, defaults
|
||||
|
||||
import bpy
|
||||
from bpy.app.handlers import persistent
|
||||
from bpy_extras.io_utils import ExportHelper, ImportHelper
|
||||
import importlib.util
|
||||
import os.path
|
||||
|
||||
|
||||
def vr_actionconfig_active_get(context):
|
||||
if not context.window_manager.xr_session_settings.actionconfigs:
|
||||
return None
|
||||
return context.window_manager.xr_session_settings.actionconfigs.active
|
||||
|
||||
|
||||
def vr_actionmap_selected_get(ac):
|
||||
actionmaps = ac.actionmaps
|
||||
return (
|
||||
None if (len(actionmaps) <
|
||||
1) else actionmaps[ac.selected_actionmap]
|
||||
)
|
||||
|
||||
|
||||
def vr_actionmap_active_get(ac):
|
||||
actionmaps = ac.actionmaps
|
||||
return (
|
||||
None if (len(actionmaps) <
|
||||
1) else actionmaps[ac.active_actionmap]
|
||||
)
|
||||
|
||||
|
||||
def vr_actionmap_item_selected_get(am):
|
||||
actionmap_items = am.actionmap_items
|
||||
return (
|
||||
None if (len(actionmap_items) <
|
||||
1) else actionmap_items[am.selected_item]
|
||||
)
|
||||
|
||||
|
||||
def vr_actionmap_binding_selected_get(ami):
|
||||
actionmap_bindings = ami.bindings
|
||||
return (
|
||||
None if (len(actionmap_bindings) <
|
||||
1) else actionmap_bindings[ami.selected_binding]
|
||||
)
|
||||
|
||||
|
||||
@persistent
|
||||
def vr_activate_user_actionconfig(context: bpy.context):
|
||||
# Set user config as active.
|
||||
actionconfigs = bpy.context.window_manager.xr_session_settings.actionconfigs
|
||||
if actionconfigs:
|
||||
actionconfigs.active = actionconfigs.user
|
||||
|
||||
|
||||
@persistent
|
||||
def vr_create_actions(context: bpy.context):
|
||||
# Create all vr action sets and actions.
|
||||
context = bpy.context
|
||||
ac = vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
session_state = context.window_manager.xr_session_state
|
||||
if not session_state:
|
||||
return
|
||||
|
||||
scene = context.scene
|
||||
|
||||
for am in ac.actionmaps:
|
||||
if len(am.actionmap_items) < 1:
|
||||
continue
|
||||
|
||||
ok = session_state.action_set_create(context, am)
|
||||
if not ok:
|
||||
return
|
||||
|
||||
controller_grip_name = ""
|
||||
controller_aim_name = ""
|
||||
|
||||
for ami in am.actionmap_items:
|
||||
if len(ami.bindings) < 1:
|
||||
continue
|
||||
|
||||
ok = session_state.action_create(context, am, ami)
|
||||
if not ok:
|
||||
return
|
||||
|
||||
if ami.type == 'POSE':
|
||||
if ami.pose_is_controller_grip:
|
||||
controller_grip_name = ami.name
|
||||
if ami.pose_is_controller_aim:
|
||||
controller_aim_name = ami.name
|
||||
|
||||
for amb in ami.bindings:
|
||||
# Check for bindings that require OpenXR extensions.
|
||||
if amb.name == defaults.VRDefaultActionbindings.REVERB_G2.value:
|
||||
if not scene.vr_actions_enable_reverb_g2:
|
||||
continue
|
||||
elif amb.name == defaults.VRDefaultActionbindings.COSMOS.value:
|
||||
if not scene.vr_actions_enable_cosmos:
|
||||
continue
|
||||
elif amb.name == defaults.VRDefaultActionbindings.HUAWEI.value:
|
||||
if not scene.vr_actions_enable_huawei:
|
||||
continue
|
||||
|
||||
ok = session_state.action_binding_create(context, am, ami, amb)
|
||||
if not ok:
|
||||
return
|
||||
|
||||
# Set controller pose actions.
|
||||
if controller_grip_name and controller_aim_name:
|
||||
session_state.controller_pose_actions_set(context, am.name, controller_grip_name, controller_aim_name)
|
||||
|
||||
# Set active action set.
|
||||
am = vr_actionmap_active_get(ac)
|
||||
if am:
|
||||
session_state.active_action_set_set(context, am.name)
|
||||
|
||||
|
||||
def vr_load_actionmaps(context, filepath):
|
||||
# Import all actionmaps for active actionconfig.
|
||||
actionconfigs = context.window_manager.xr_session_settings.actionconfigs
|
||||
if not actionconfigs:
|
||||
return False
|
||||
ac = actionconfigs.active
|
||||
if not ac:
|
||||
return False
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
return False
|
||||
|
||||
spec = importlib.util.spec_from_file_location(os.path.basename(filepath), filepath)
|
||||
file = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(file)
|
||||
|
||||
action_map_io.actionconfig_init_from_data(ac, file.actionconfig_data, file.actionconfig_version)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def vr_save_actionmaps(context, filepath, sort=False):
|
||||
# Export all actionmaps for active actionconfig.
|
||||
actionconfigs = context.window_manager.xr_session_settings.actionconfigs
|
||||
if not actionconfigs:
|
||||
return False
|
||||
ac = actionconfigs.active
|
||||
if not ac:
|
||||
return False
|
||||
|
||||
action_map_io.actionconfig_export_as_data(ac, filepath, sort=sort)
|
||||
|
||||
print("Saved XR actionmaps: " + filepath)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.vr_actions_enable_cosmos = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the HTC Vive Cosmos controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
bpy.types.Scene.vr_actions_enable_huawei = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the Huawei controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
bpy.types.Scene.vr_actions_enable_reverb_g2 = bpy.props.BoolProperty(
|
||||
description="Enable bindings for the HP Reverb G2 controllers. Note that this may not be supported by all OpenXR runtimes",
|
||||
default=False,
|
||||
)
|
||||
|
||||
bpy.app.handlers.load_post.append(vr_activate_user_actionconfig)
|
||||
bpy.app.handlers.xr_session_start_pre.append(vr_create_actions)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.vr_actions_enable_cosmos
|
||||
del bpy.types.Scene.vr_actions_enable_huawei
|
||||
del bpy.types.Scene.vr_actions_enable_reverb_g2
|
||||
|
||||
bpy.app.handlers.load_post.remove(vr_activate_user_actionconfig)
|
||||
bpy.app.handlers.xr_session_start_pre.remove(vr_create_actions)
|
|
@ -282,7 +282,7 @@ def actionconfig_export_as_data(ac, filepath, *, all_actionmaps=True, sort=False
|
|||
# -----------------------------------------------------------------------------
|
||||
# Import Functions
|
||||
|
||||
def _ami_props_setattr(ami_props, attr, value):
|
||||
def _ami_props_setattr(ami_name, ami_props, attr, value):
|
||||
if type(value) is list:
|
||||
ami_subprop = getattr(ami_props, attr)
|
||||
for subattr, subvalue in value:
|
||||
|
@ -292,7 +292,7 @@ def _ami_props_setattr(ami_props, attr, value):
|
|||
try:
|
||||
setattr(ami_props, attr, value)
|
||||
except AttributeError:
|
||||
print(f"Warning: property '{attr}' not found in actionmap item '{ami_props.__class__.__name__}'")
|
||||
print(f"Warning: property '{attr}' not found in actionmap item '{ami_name}'")
|
||||
except Exception as ex:
|
||||
print(f"Warning: {ex!r}")
|
||||
|
||||
|
@ -315,7 +315,7 @@ def actionmap_init_from_data(am, am_items):
|
|||
ami_props = ami.op_properties
|
||||
assert type(ami_props_data) is list
|
||||
for attr, value in ami_props_data:
|
||||
_ami_props_setattr(ami_props, attr, value)
|
||||
_ami_props_setattr(ami_name, ami_props, attr, value)
|
||||
ami_bindings = ami_content["bindings"]
|
||||
assert type(ami_bindings) is list
|
||||
actionmap_item_init_from_data(ami, ami_bindings)
|
|
@ -1,4 +1,4 @@
|
|||
actionconfig_version = (3, 0, 18)
|
||||
actionconfig_version = (3, 0, 20)
|
||||
actionconfig_data = \
|
||||
[("blender_default",
|
||||
{"items":
|
||||
|
@ -213,7 +213,7 @@ actionconfig_data = \
|
|||
},
|
||||
),
|
||||
("nav_reset",
|
||||
{"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_navigation_reset', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_reset', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"op_properties":
|
||||
[("location", False),
|
||||
("rotation", False),
|
||||
|
@ -222,28 +222,24 @@ actionconfig_data = \
|
|||
},
|
||||
{"bindings":
|
||||
[("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
),
|
||||
("toggle_matview",
|
||||
{"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'view3d.toggle_shading', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'view3d.toggle_shading', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"op_properties":
|
||||
[("type", 'MATERIAL'),
|
||||
],
|
||||
},
|
||||
{"bindings":
|
||||
[("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
|
@ -277,9 +273,11 @@ actionconfig_data = \
|
|||
("undo", {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'ed.undo', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'}, None,
|
||||
{"bindings":
|
||||
[("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/y/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/y/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/y/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
|
@ -287,9 +285,11 @@ actionconfig_data = \
|
|||
("redo", {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'ed.redo', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'}, None,
|
||||
{"bindings":
|
||||
[("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/trackpad/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
|
@ -440,18 +440,29 @@ actionconfig_data = \
|
|||
],
|
||||
},
|
||||
{"bindings":
|
||||
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/shoulder_right/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/y/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
),
|
||||
("toggle_solidview",
|
||||
{"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'view3d.toggle_shading', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic_left', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"op_properties":
|
||||
[("type", 'SOLID'),
|
||||
],
|
||||
},
|
||||
{"bindings":
|
||||
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/shoulder_left/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
),
|
||||
("toggle_matview",
|
||||
{"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'view3d.toggle_shading', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic_left', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'view3d.toggle_shading', "op_mode": 'PRESS', "bimanual": 'False', "haptic_name": 'haptic_right', "haptic_match_user_paths": 'True', "haptic_duration": '0.30000001192092896', "haptic_frequency": '3000.0', "haptic_amplitude": '0.5', "haptic_mode": 'PRESS'},
|
||||
{"op_properties":
|
||||
[("type", 'MATERIAL'),
|
||||
],
|
||||
},
|
||||
{"bindings":
|
||||
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/shoulder_left/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
[("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/shoulder_right/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
|
||||
],
|
||||
},
|
||||
),
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(main)
|
||||
importlib.reload(action_map)
|
||||
else:
|
||||
from . import main
|
||||
from . import action_map
|
||||
|
||||
import bpy
|
||||
from bpy.app.handlers import persistent
|
||||
from enum import Enum
|
||||
import math
|
||||
import os.path
|
||||
|
||||
|
||||
# Default action maps.
|
||||
|
@ -52,6 +53,7 @@ class VRDefaultActions(Enum):
|
|||
FLY_TURNLEFT = "fly_turnleft"
|
||||
FLY_TURNRIGHT = "fly_turnright"
|
||||
NAV_RESET = "nav_reset"
|
||||
TOGGLE_SOLIDVIEW = "toggle_solidview"
|
||||
TOGGLE_MATVIEW = "toggle_matview"
|
||||
RAYCAST_SELECT = "raycast_select"
|
||||
GRAB = "grab"
|
||||
|
@ -63,6 +65,7 @@ class VRDefaultActions(Enum):
|
|||
HAPTIC_LEFTTRIGGER = "haptic_lefttrigger"
|
||||
HAPTIC_RIGHTTRIGGER = "haptic_righttrigger"
|
||||
|
||||
|
||||
# Default action bindings.
|
||||
class VRDefaultActionbindings(Enum):
|
||||
COSMOS = "cosmos"
|
||||
|
@ -1064,7 +1067,7 @@ def vr_defaults_create_default(ac):
|
|||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.NAV_RESET.value,
|
||||
"/user/hand/right",
|
||||
"/user/hand/left",
|
||||
"",
|
||||
"wm.xr_navigation_reset",
|
||||
'PRESS',
|
||||
|
@ -1084,14 +1087,6 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
|
@ -1116,14 +1111,6 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
|
@ -1135,7 +1122,7 @@ def vr_defaults_create_default(ac):
|
|||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.TOGGLE_MATVIEW.value,
|
||||
"/user/hand/left",
|
||||
"/user/hand/right",
|
||||
"",
|
||||
"view3d.toggle_shading",
|
||||
'PRESS',
|
||||
|
@ -1155,14 +1142,6 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
|
@ -1187,14 +1166,6 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
|
@ -1384,6 +1355,14 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
|
@ -1408,6 +1387,14 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
|
@ -1439,6 +1426,14 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.HUAWEI.value,
|
||||
VRDefaultActionprofiles.HUAWEI.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.INDEX.value,
|
||||
VRDefaultActionprofiles.INDEX.value,
|
||||
|
@ -1463,6 +1458,14 @@ def vr_defaults_create_default(ac):
|
|||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.VIVE.value,
|
||||
VRDefaultActionprofiles.VIVE.value,
|
||||
"/input/trackpad/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.WMR.value,
|
||||
VRDefaultActionprofiles.WMR.value,
|
||||
|
@ -1770,14 +1773,14 @@ def vr_defaults_create_default_gamepad(ac):
|
|||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.GAMEPAD.value,
|
||||
VRDefaultActionprofiles.GAMEPAD.value,
|
||||
"/input/shoulder_right/click",
|
||||
"/input/y/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.TOGGLE_MATVIEW.value,
|
||||
VRDefaultActions.TOGGLE_SOLIDVIEW.value,
|
||||
"/user/gamepad",
|
||||
"",
|
||||
"view3d.toggle_shading",
|
||||
|
@ -1799,6 +1802,29 @@ def vr_defaults_create_default_gamepad(ac):
|
|||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.TOGGLE_MATVIEW.value,
|
||||
"/user/gamepad",
|
||||
"",
|
||||
"view3d.toggle_shading",
|
||||
'PRESS',
|
||||
False,
|
||||
"haptic_right",
|
||||
True,
|
||||
0.3,
|
||||
3000.0,
|
||||
0.5,
|
||||
'PRESS')
|
||||
if ami:
|
||||
vr_defaults_actionbinding_add(ami,
|
||||
VRDefaultActionbindings.GAMEPAD.value,
|
||||
VRDefaultActionprofiles.GAMEPAD.value,
|
||||
"/input/shoulder_right/click",
|
||||
"",
|
||||
0.3,
|
||||
'ANY',
|
||||
'ANY')
|
||||
|
||||
ami = vr_defaults_action_add(am,
|
||||
VRDefaultActions.RAYCAST_SELECT.value,
|
||||
"/user/gamepad",
|
||||
|
@ -1913,6 +1939,11 @@ def vr_defaults_create_default_gamepad(ac):
|
|||
"")
|
||||
|
||||
|
||||
def vr_get_default_config_path():
|
||||
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "configs")
|
||||
return os.path.join(filepath, "default.py")
|
||||
|
||||
|
||||
@persistent
|
||||
def vr_init_default_actionconfig(context: bpy.context):
|
||||
context = bpy.context
|
||||
|
@ -1928,13 +1959,21 @@ def vr_init_default_actionconfig(context: bpy.context):
|
|||
actionconfigs.active = ac
|
||||
|
||||
# Load default actionmaps.
|
||||
filepath = main.vr_get_default_config_path()
|
||||
filepath = vr_get_default_config_path()
|
||||
|
||||
loaded = main.vr_load_actionmaps(context, filepath)
|
||||
loaded = action_map.vr_load_actionmaps(context, filepath)
|
||||
|
||||
if not loaded:
|
||||
# Create and save default actionmaps.
|
||||
vr_defaults_create_default(ac)
|
||||
vr_defaults_create_default_gamepad(ac)
|
||||
|
||||
main.vr_save_actionmaps(context, filepath, sort=False)
|
||||
action_map.vr_save_actionmaps(context, filepath, sort=False)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.app.handlers.load_post.append(vr_init_default_actionconfig)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.app.handlers.load_post.remove(vr_init_default_actionconfig)
|
||||
|
|
|
@ -0,0 +1,642 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
importlib.reload(action_map)
|
||||
importlib.reload(properties)
|
||||
else:
|
||||
from . import action_map, properties
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
Menu,
|
||||
Panel,
|
||||
UIList,
|
||||
)
|
||||
|
||||
|
||||
### Session.
|
||||
class VIEW3D_PT_vr_session(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "VR Session"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
is_session_running = bpy.types.XrSessionState.is_running(context)
|
||||
|
||||
# Using SNAP_FACE because it looks like a stop icon -- I shouldn't
|
||||
# have commit rights...
|
||||
toggle_info = (
|
||||
("Start VR Session", 'PLAY') if not is_session_running else (
|
||||
"Stop VR Session", 'SNAP_FACE')
|
||||
)
|
||||
layout.operator("wm.xr_session_toggle",
|
||||
text=toggle_info[0], icon=toggle_info[1])
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.prop(session_settings, "use_positional_tracking")
|
||||
layout.prop(session_settings, "use_absolute_tracking")
|
||||
|
||||
|
||||
### View.
|
||||
class VIEW3D_PT_vr_session_view(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "View"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
col = layout.column(align=True, heading="Show")
|
||||
col.prop(session_settings, "show_floor", text="Floor")
|
||||
col.prop(session_settings, "show_annotation", text="Annotations")
|
||||
col.prop(session_settings, "show_selection", text="Selection")
|
||||
col.prop(session_settings, "show_controllers", text="Controllers")
|
||||
col.prop(session_settings, "show_custom_overlays", text="Custom Overlays")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(session_settings, "controller_draw_style", text="Controller Style")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(session_settings, "selection_eye", text="Selection Eye")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(session_settings, "clip_start", text="Clip Start")
|
||||
col.prop(session_settings, "clip_end", text="End")
|
||||
|
||||
|
||||
### Landmarks.
|
||||
class VIEW3D_MT_vr_landmark_menu(Menu):
|
||||
bl_label = "Landmark Controls"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.vr_landmark_from_camera")
|
||||
layout.operator("view3d.update_vr_landmark")
|
||||
layout.separator()
|
||||
layout.operator("view3d.cursor_to_vr_landmark")
|
||||
layout.operator("view3d.camera_to_vr_landmark")
|
||||
layout.operator("view3d.add_camera_from_vr_landmark")
|
||||
|
||||
|
||||
class VIEW3D_UL_vr_landmarks(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data,
|
||||
_active_propname, index):
|
||||
landmark = item
|
||||
landmark_active_idx = context.scene.vr_landmarks_active
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
layout.prop(landmark, "name", text="")
|
||||
|
||||
icon = (
|
||||
'RADIOBUT_ON' if (index == landmark_active_idx) else 'RADIOBUT_OFF'
|
||||
)
|
||||
props = layout.operator(
|
||||
"view3d.vr_landmark_activate", text="", icon=icon)
|
||||
props.index = index
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_landmarks(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "Landmarks"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
landmark_selected = properties.VRLandmark.get_selected_landmark(context)
|
||||
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
row = layout.row()
|
||||
|
||||
row.template_list("VIEW3D_UL_vr_landmarks", "", scene, "vr_landmarks",
|
||||
scene, "vr_landmarks_selected", rows=3)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("view3d.vr_landmark_add", icon='ADD', text="")
|
||||
col.operator("view3d.vr_landmark_remove", icon='REMOVE', text="")
|
||||
col.operator("view3d.vr_landmark_from_session", icon='PLUS', text="")
|
||||
|
||||
col.menu("VIEW3D_MT_vr_landmark_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
if landmark_selected:
|
||||
layout.prop(landmark_selected, "type")
|
||||
|
||||
if landmark_selected.type == 'OBJECT':
|
||||
layout.prop(landmark_selected, "base_pose_object")
|
||||
layout.prop(landmark_selected, "base_scale", text="Scale")
|
||||
elif landmark_selected.type == 'CUSTOM':
|
||||
layout.prop(landmark_selected,
|
||||
"base_pose_location", text="Location")
|
||||
layout.prop(landmark_selected,
|
||||
"base_pose_angle", text="Angle")
|
||||
layout.prop(landmark_selected,
|
||||
"base_scale", text="Scale")
|
||||
|
||||
|
||||
### Actions.
|
||||
def vr_indented_layout(layout, level):
|
||||
# Same as _indented_layout() from rna_keymap_ui.py.
|
||||
indentpx = 16
|
||||
if level == 0:
|
||||
level = 0.0001 # Tweak so that a percentage of 0 won't split by half
|
||||
indent = level * indentpx / bpy.context.region.width
|
||||
|
||||
split = layout.split(factor=indent)
|
||||
col = split.column()
|
||||
col = split.column()
|
||||
return col
|
||||
|
||||
|
||||
def vr_draw_ami(ami, layout, level):
|
||||
# Similar to draw_kmi() from rna_keymap_ui.py.
|
||||
col = vr_indented_layout(layout, level)
|
||||
|
||||
if ami.op:
|
||||
col = col.column(align=True)
|
||||
box = col.box()
|
||||
else:
|
||||
box = col.column()
|
||||
|
||||
split = box.split()
|
||||
|
||||
# Header bar.
|
||||
row = split.row(align=True)
|
||||
#row.prop(ami, "show_expanded", text="", emboss=False)
|
||||
|
||||
row.label(text="Operator Properties")
|
||||
row.label(text=ami.op_name)
|
||||
|
||||
# Expanded, additional event settings.
|
||||
if ami.op:
|
||||
box = col.box()
|
||||
|
||||
# Operator properties.
|
||||
box.template_xr_actionmap_item_properties(ami)
|
||||
|
||||
|
||||
class VIEW3D_UL_vr_actionmaps(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data,
|
||||
_active_propname, index):
|
||||
ac = action_map.vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
am_active_idx = ac.active_actionmap
|
||||
am = item
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
layout.prop(am, "name", text="")
|
||||
|
||||
icon = (
|
||||
'RADIOBUT_ON' if (index == am_active_idx) else 'RADIOBUT_OFF'
|
||||
)
|
||||
props = layout.operator(
|
||||
"view3d.vr_actionmap_activate", text="", icon=icon)
|
||||
props.index = index
|
||||
|
||||
|
||||
class VIEW3D_MT_vr_actionmap_menu(Menu):
|
||||
bl_label = "Action Map Controls"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.vr_actionmaps_defaults_load")
|
||||
layout.operator("view3d.vr_actionmaps_import")
|
||||
layout.operator("view3d.vr_actionmaps_export")
|
||||
layout.operator("view3d.vr_actionmap_copy")
|
||||
layout.operator("view3d.vr_actionmaps_clear")
|
||||
|
||||
|
||||
class VIEW3D_UL_vr_actions(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data,
|
||||
_active_propname, index):
|
||||
action = item
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
layout.prop(action, "name", text="")
|
||||
|
||||
|
||||
class VIEW3D_MT_vr_action_menu(Menu):
|
||||
bl_label = "Action Controls"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.vr_action_copy")
|
||||
layout.operator("view3d.vr_actions_clear")
|
||||
|
||||
|
||||
class VIEW3D_UL_vr_actionbindings(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data,
|
||||
_active_propname, index):
|
||||
amb = item
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
layout.prop(amb, "name", text="")
|
||||
|
||||
|
||||
class VIEW3D_MT_vr_actionbinding_menu(Menu):
|
||||
bl_label = "Action Binding Controls"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.vr_actionbinding_copy")
|
||||
layout.operator("view3d.vr_actionbindings_clear")
|
||||
|
||||
|
||||
class VRActionsPanel:
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_actions_actionmaps(VRActionsPanel, Panel):
|
||||
bl_label = "Action Maps"
|
||||
|
||||
def draw(self, context):
|
||||
ac = action_map.vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
scene = context.scene
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("VIEW3D_UL_vr_actionmaps", "", ac, "actionmaps",
|
||||
ac, "selected_actionmap", rows=3)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("view3d.vr_actionmap_add", icon='ADD', text="")
|
||||
col.operator("view3d.vr_actionmap_remove", icon='REMOVE', text="")
|
||||
|
||||
col.menu("VIEW3D_MT_vr_actionmap_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
am = action_map.vr_actionmap_selected_get(ac)
|
||||
|
||||
if am:
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
col.prop(am, "name", text="Action Map")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_actions_actions(VRActionsPanel, Panel):
|
||||
bl_label = "Actions"
|
||||
bl_parent_id = "VIEW3D_PT_vr_actions_actionmaps"
|
||||
|
||||
def draw(self, context):
|
||||
ac = action_map.vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
am = action_map.vr_actionmap_selected_get(ac)
|
||||
|
||||
if am:
|
||||
col = vr_indented_layout(layout, 1)
|
||||
row = col.row()
|
||||
row.template_list("VIEW3D_UL_vr_actions", "", am, "actionmap_items",
|
||||
am, "selected_item", rows=3)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("view3d.vr_action_add", icon='ADD', text="")
|
||||
col.operator("view3d.vr_action_remove", icon='REMOVE', text="")
|
||||
|
||||
col.menu("VIEW3D_MT_vr_action_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
ami = action_map.vr_actionmap_item_selected_get(am)
|
||||
|
||||
if ami:
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
col.prop(ami, "name", text="Action")
|
||||
col.prop(ami, "type", text="Type")
|
||||
col.prop(ami, "user_path0", text="User Path 0")
|
||||
col.prop(ami, "user_path1", text="User Path 1")
|
||||
|
||||
if ami.type == 'FLOAT' or ami.type == 'VECTOR2D':
|
||||
col.prop(ami, "op", text="Operator")
|
||||
col.prop(ami, "op_mode", text="Operator Mode")
|
||||
col.prop(ami, "bimanual", text="Bimanual")
|
||||
# Properties.
|
||||
vr_draw_ami(ami, col, 1)
|
||||
elif ami.type == 'POSE':
|
||||
col.prop(ami, "pose_is_controller_grip", text="Use for Controller Grips")
|
||||
col.prop(ami, "pose_is_controller_aim", text="Use for Controller Aims")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_actions_haptics(VRActionsPanel, Panel):
|
||||
bl_label = "Haptics"
|
||||
bl_parent_id = "VIEW3D_PT_vr_actions_actions"
|
||||
|
||||
def draw(self, context):
|
||||
ac = action_map.vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
am = action_map.vr_actionmap_selected_get(ac)
|
||||
|
||||
if am:
|
||||
ami = action_map.vr_actionmap_item_selected_get(am)
|
||||
|
||||
if ami:
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
if ami.type == 'FLOAT' or ami.type == 'VECTOR2D':
|
||||
col.prop(ami, "haptic_name", text="Haptic Action")
|
||||
col.prop(ami, "haptic_match_user_paths", text="Match User Paths")
|
||||
col.prop(ami, "haptic_duration", text="Duration")
|
||||
col.prop(ami, "haptic_frequency", text="Frequency")
|
||||
col.prop(ami, "haptic_amplitude", text="Amplitude")
|
||||
col.prop(ami, "haptic_mode", text="Haptic Mode")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_actions_bindings(VRActionsPanel, Panel):
|
||||
bl_label = "Bindings"
|
||||
bl_parent_id = "VIEW3D_PT_vr_actions_actions"
|
||||
|
||||
def draw(self, context):
|
||||
ac = action_map.vr_actionconfig_active_get(context)
|
||||
if not ac:
|
||||
return
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
am = action_map.vr_actionmap_selected_get(ac)
|
||||
|
||||
if am:
|
||||
ami = action_map.vr_actionmap_item_selected_get(am)
|
||||
|
||||
if ami:
|
||||
col = vr_indented_layout(layout, 2)
|
||||
row = col.row()
|
||||
row.template_list("VIEW3D_UL_vr_actionbindings", "", ami, "bindings",
|
||||
ami, "selected_binding", rows=3)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("view3d.vr_actionbinding_add", icon='ADD', text="")
|
||||
col.operator("view3d.vr_actionbinding_remove", icon='REMOVE', text="")
|
||||
|
||||
col.menu("VIEW3D_MT_vr_actionbinding_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
amb = action_map.vr_actionmap_binding_selected_get(ami)
|
||||
|
||||
if amb:
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
col.prop(amb, "name", text="Binding")
|
||||
col.prop(amb, "profile", text="Profile")
|
||||
col.prop(amb, "component_path0", text="Component Path 0")
|
||||
col.prop(amb, "component_path1", text="Component Path 1")
|
||||
if ami.type == 'FLOAT' or ami.type == 'VECTOR2D':
|
||||
col.prop(amb, "threshold", text="Threshold")
|
||||
if ami.type == 'FLOAT':
|
||||
col.prop(amb, "axis0_region", text="Axis Region")
|
||||
else: # ami.type == 'VECTOR2D'
|
||||
col.prop(amb, "axis0_region", text="Axis 0 Region")
|
||||
col.prop(amb, "axis1_region", text="Axis 1 Region")
|
||||
elif ami.type == 'POSE':
|
||||
col.prop(amb, "pose_location", text="Location Offset")
|
||||
col.prop(amb, "pose_rotation", text="Rotation Offset")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_actions_extensions(VRActionsPanel, Panel):
|
||||
bl_label = "Extensions"
|
||||
bl_parent_id = "VIEW3D_PT_vr_actions_actionmaps"
|
||||
|
||||
def draw(self, context):
|
||||
scene = context.scene
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(scene, "vr_actions_enable_reverb_g2", text="HP Reverb G2")
|
||||
col.prop(scene, "vr_actions_enable_cosmos", text="HTC Vive Cosmos")
|
||||
col.prop(scene, "vr_actions_enable_huawei", text="Huawei")
|
||||
|
||||
|
||||
### Motion capture.
|
||||
class VIEW3D_UL_vr_mocap_objects(UIList):
|
||||
def draw_item(self, context, layout, _data, item, icon, _active_data,
|
||||
_active_propname, index):
|
||||
scene_mocap_ob = item
|
||||
|
||||
layout.emboss = 'NONE'
|
||||
|
||||
if scene_mocap_ob.object:
|
||||
layout.prop(scene_mocap_ob.object, "name", text="")
|
||||
else:
|
||||
layout.label(icon='X')
|
||||
|
||||
|
||||
class VIEW3D_MT_vr_mocap_object_menu(Menu):
|
||||
bl_label = "Motion Capture Object Controls"
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator("view3d.vr_mocap_object_help")
|
||||
|
||||
|
||||
class VIEW3D_PT_vr_motion_capture(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "Motion Capture"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
scene = context.scene
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(icon='ERROR', text="Note:")
|
||||
col.label(text="Settings here may have a significant")
|
||||
col.label(text="performance impact!")
|
||||
|
||||
layout.separator()
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("VIEW3D_UL_vr_mocap_objects", "", scene, "vr_mocap_objects",
|
||||
session_settings, "selected_mocap_object", rows=3)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("view3d.vr_mocap_object_add", icon='ADD', text="")
|
||||
col.operator("view3d.vr_mocap_object_remove", icon='REMOVE', text="")
|
||||
|
||||
col.menu("VIEW3D_MT_vr_mocap_object_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
mocap_ob = properties.vr_mocap_object_selected_get(session_settings)
|
||||
scene_mocap_ob = properties.vr_scene_mocap_object_selected_get(scene, session_settings)
|
||||
|
||||
if mocap_ob and scene_mocap_ob:
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
|
||||
col.prop(scene_mocap_ob, "object", text="Object")
|
||||
col.prop(mocap_ob, "user_path", text="User Path")
|
||||
col.prop(mocap_ob, "enable", text="Enable")
|
||||
col.prop(mocap_ob, "autokey", text="Auto Key")
|
||||
col.prop(mocap_ob, "location_offset", text="Location Offset")
|
||||
col.prop(mocap_ob, "rotation_offset", text="Rotation Offset")
|
||||
|
||||
|
||||
### Viewport feedback.
|
||||
class VIEW3D_PT_vr_viewport_feedback(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "Viewport Feedback"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
view3d = context.space_data
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(icon='ERROR', text="Note:")
|
||||
col.label(text="Settings here may have a significant")
|
||||
col.label(text="performance impact!")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.prop(view3d.shading, "vr_show_virtual_camera")
|
||||
layout.prop(view3d.shading, "vr_show_controllers")
|
||||
layout.prop(view3d.shading, "vr_show_landmarks")
|
||||
layout.prop(view3d, "mirror_xr_session")
|
||||
|
||||
|
||||
### Info.
|
||||
class VIEW3D_PT_vr_info(bpy.types.Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "VR"
|
||||
bl_label = "VR Info"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not bpy.app.build_options.xr_openxr
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(icon='ERROR', text="Built without VR/OpenXR features.")
|
||||
|
||||
|
||||
classes = (
|
||||
VIEW3D_PT_vr_session,
|
||||
VIEW3D_PT_vr_session_view,
|
||||
VIEW3D_PT_vr_landmarks,
|
||||
VIEW3D_PT_vr_actions_actionmaps,
|
||||
VIEW3D_PT_vr_actions_actions,
|
||||
VIEW3D_PT_vr_actions_haptics,
|
||||
VIEW3D_PT_vr_actions_bindings,
|
||||
VIEW3D_PT_vr_actions_extensions,
|
||||
VIEW3D_PT_vr_motion_capture,
|
||||
VIEW3D_PT_vr_viewport_feedback,
|
||||
|
||||
VIEW3D_UL_vr_landmarks,
|
||||
VIEW3D_MT_vr_landmark_menu,
|
||||
|
||||
VIEW3D_UL_vr_actionmaps,
|
||||
VIEW3D_MT_vr_actionmap_menu,
|
||||
VIEW3D_UL_vr_actions,
|
||||
VIEW3D_MT_vr_action_menu,
|
||||
VIEW3D_UL_vr_actionbindings,
|
||||
VIEW3D_MT_vr_actionbinding_menu,
|
||||
|
||||
VIEW3D_UL_vr_mocap_objects,
|
||||
VIEW3D_MT_vr_mocap_object_menu,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
# View3DShading is the only per 3D-View struct with custom property
|
||||
# support, so "abusing" that to get a per 3D-View option.
|
||||
bpy.types.View3DShading.vr_show_virtual_camera = bpy.props.BoolProperty(
|
||||
name="Show VR Camera"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_controllers = bpy.props.BoolProperty(
|
||||
name="Show VR Controllers"
|
||||
)
|
||||
bpy.types.View3DShading.vr_show_landmarks = bpy.props.BoolProperty(
|
||||
name="Show Landmarks"
|
||||
)
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
del bpy.types.View3DShading.vr_show_virtual_camera
|
||||
del bpy.types.View3DShading.vr_show_controllers
|
||||
del bpy.types.View3DShading.vr_show_landmarks
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,295 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
import bpy
|
||||
from bpy.types import (
|
||||
PropertyGroup,
|
||||
)
|
||||
from bpy.app.handlers import persistent
|
||||
|
||||
|
||||
### Landmarks.
|
||||
@persistent
|
||||
def vr_ensure_default_landmark(context: bpy.context):
|
||||
# Ensure there's a default landmark (scene camera by default).
|
||||
landmarks = bpy.context.scene.vr_landmarks
|
||||
if not landmarks:
|
||||
landmarks.add()
|
||||
landmarks[0].type = 'SCENE_CAMERA'
|
||||
|
||||
|
||||
def vr_landmark_active_type_update(self, context):
|
||||
wm = context.window_manager
|
||||
session_settings = wm.xr_session_settings
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Update session's base pose type to the matching type.
|
||||
if landmark_active.type == 'SCENE_CAMERA':
|
||||
session_settings.base_pose_type = 'SCENE_CAMERA'
|
||||
elif landmark_active.type == 'OBJECT':
|
||||
session_settings.base_pose_type = 'OBJECT'
|
||||
elif landmark_active.type == 'CUSTOM':
|
||||
session_settings.base_pose_type = 'CUSTOM'
|
||||
|
||||
|
||||
def vr_landmark_active_base_pose_object_update(self, context):
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Update the anchor object to the (new) camera of this landmark.
|
||||
session_settings.base_pose_object = landmark_active.base_pose_object
|
||||
|
||||
|
||||
def vr_landmark_active_base_pose_location_update(self, context):
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
session_settings.base_pose_location = landmark_active.base_pose_location
|
||||
|
||||
|
||||
def vr_landmark_active_base_pose_angle_update(self, context):
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
session_settings.base_pose_angle = landmark_active.base_pose_angle
|
||||
|
||||
|
||||
def vr_landmark_active_base_scale_update(self, context):
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
session_settings.base_scale = landmark_active.base_scale
|
||||
|
||||
|
||||
def vr_landmark_type_update(self, context):
|
||||
landmark_selected = VRLandmark.get_selected_landmark(context)
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Only update session settings data if the changed landmark is actually
|
||||
# the active one.
|
||||
if landmark_active == landmark_selected:
|
||||
vr_landmark_active_type_update(self, context)
|
||||
|
||||
|
||||
def vr_landmark_base_pose_object_update(self, context):
|
||||
landmark_selected = VRLandmark.get_selected_landmark(context)
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Only update session settings data if the changed landmark is actually
|
||||
# the active one.
|
||||
if landmark_active == landmark_selected:
|
||||
vr_landmark_active_base_pose_object_update(self, context)
|
||||
|
||||
|
||||
def vr_landmark_base_pose_location_update(self, context):
|
||||
landmark_selected = VRLandmark.get_selected_landmark(context)
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Only update session settings data if the changed landmark is actually
|
||||
# the active one.
|
||||
if landmark_active == landmark_selected:
|
||||
vr_landmark_active_base_pose_location_update(self, context)
|
||||
|
||||
|
||||
def vr_landmark_base_pose_angle_update(self, context):
|
||||
landmark_selected = VRLandmark.get_selected_landmark(context)
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Only update session settings data if the changed landmark is actually
|
||||
# the active one.
|
||||
if landmark_active == landmark_selected:
|
||||
vr_landmark_active_base_pose_angle_update(self, context)
|
||||
|
||||
|
||||
def vr_landmark_base_scale_update(self, context):
|
||||
landmark_selected = VRLandmark.get_selected_landmark(context)
|
||||
landmark_active = VRLandmark.get_active_landmark(context)
|
||||
|
||||
# Only update session settings data if the changed landmark is actually
|
||||
# the active one.
|
||||
if landmark_active == landmark_selected:
|
||||
vr_landmark_active_base_scale_update(self, context)
|
||||
|
||||
|
||||
def vr_landmark_active_update(self, context):
|
||||
wm = context.window_manager
|
||||
|
||||
vr_landmark_active_type_update(self, context)
|
||||
vr_landmark_active_base_pose_object_update(self, context)
|
||||
vr_landmark_active_base_pose_location_update(self, context)
|
||||
vr_landmark_active_base_pose_angle_update(self, context)
|
||||
vr_landmark_active_base_scale_update(self, context)
|
||||
|
||||
if wm.xr_session_state:
|
||||
wm.xr_session_state.reset_to_base_pose(context)
|
||||
|
||||
|
||||
class VRLandmark(PropertyGroup):
|
||||
name: bpy.props.StringProperty(
|
||||
name="VR Landmark",
|
||||
default="Landmark"
|
||||
)
|
||||
type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
items=[
|
||||
('SCENE_CAMERA', "Scene Camera",
|
||||
"Use scene's currently active camera to define the VR view base "
|
||||
"location and rotation"),
|
||||
('OBJECT', "Custom Object",
|
||||
"Use an existing object to define the VR view base location and "
|
||||
"rotation"),
|
||||
('CUSTOM', "Custom Pose",
|
||||
"Allow a manually defined position and rotation to be used as "
|
||||
"the VR view base pose"),
|
||||
],
|
||||
default='SCENE_CAMERA',
|
||||
update=vr_landmark_type_update,
|
||||
)
|
||||
base_pose_object: bpy.props.PointerProperty(
|
||||
name="Object",
|
||||
type=bpy.types.Object,
|
||||
update=vr_landmark_base_pose_object_update,
|
||||
)
|
||||
base_pose_location: bpy.props.FloatVectorProperty(
|
||||
name="Base Pose Location",
|
||||
subtype='TRANSLATION',
|
||||
update=vr_landmark_base_pose_location_update,
|
||||
)
|
||||
base_pose_angle: bpy.props.FloatProperty(
|
||||
name="Base Pose Angle",
|
||||
subtype='ANGLE',
|
||||
update=vr_landmark_base_pose_angle_update,
|
||||
)
|
||||
base_scale: bpy.props.FloatProperty(
|
||||
name="Base Scale",
|
||||
default=1.0,
|
||||
min=0.001,
|
||||
max=1000.0,
|
||||
soft_min=0.001,
|
||||
soft_max=1000.0,
|
||||
update=vr_landmark_base_scale_update,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_selected_landmark(context):
|
||||
scene = context.scene
|
||||
landmarks = scene.vr_landmarks
|
||||
|
||||
return (
|
||||
None if (len(landmarks) <
|
||||
1) else landmarks[scene.vr_landmarks_selected]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_active_landmark(context):
|
||||
scene = context.scene
|
||||
landmarks = scene.vr_landmarks
|
||||
|
||||
return (
|
||||
None if (len(landmarks) <
|
||||
1) else landmarks[scene.vr_landmarks_active]
|
||||
)
|
||||
|
||||
|
||||
### Motion capture.
|
||||
def vr_mocap_object_selected_get(session_settings):
|
||||
mocap_objects = session_settings.mocap_objects
|
||||
return (
|
||||
None if (len(mocap_objects) <
|
||||
1) else mocap_objects[session_settings.selected_mocap_object]
|
||||
)
|
||||
|
||||
|
||||
def vr_scene_mocap_object_selected_get(scene, session_settings):
|
||||
mocap_objects = scene.vr_mocap_objects
|
||||
return (
|
||||
None if (len(mocap_objects) <
|
||||
1) else mocap_objects[session_settings.selected_mocap_object]
|
||||
)
|
||||
|
||||
|
||||
def vr_scene_mocap_object_update(self, context):
|
||||
session_settings = context.window_manager.xr_session_settings
|
||||
mocap_ob = vr_mocap_object_selected_get(session_settings)
|
||||
if not mocap_ob:
|
||||
return
|
||||
|
||||
scene = context.scene
|
||||
scene_mocap_ob = vr_scene_mocap_object_selected_get(scene, session_settings)
|
||||
if not scene_mocap_ob:
|
||||
return
|
||||
|
||||
# Check for duplicate object.
|
||||
if scene_mocap_ob.object and session_settings.mocap_objects.find(scene_mocap_ob.object):
|
||||
scene_mocap_ob.object = None
|
||||
return
|
||||
|
||||
mocap_ob.object = scene_mocap_ob.object
|
||||
|
||||
|
||||
class VRMotionCaptureObject(PropertyGroup):
|
||||
object: bpy.props.PointerProperty(
|
||||
name="Object",
|
||||
type=bpy.types.Object,
|
||||
update=vr_scene_mocap_object_update,
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
VRLandmark,
|
||||
VRMotionCaptureObject,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
bpy.types.Scene.vr_landmarks = bpy.props.CollectionProperty(
|
||||
name="Landmark",
|
||||
type=VRLandmark,
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_selected = bpy.props.IntProperty(
|
||||
name="Selected Landmark"
|
||||
)
|
||||
bpy.types.Scene.vr_landmarks_active = bpy.props.IntProperty(
|
||||
update=vr_landmark_active_update,
|
||||
)
|
||||
# This scene collection property is needed instead of directly accessing
|
||||
# XrSessionSettings.mocap_objects in the UI to avoid invalid pointers when
|
||||
# deleting objects.
|
||||
bpy.types.Scene.vr_mocap_objects = bpy.props.CollectionProperty(
|
||||
name="Motion Capture Object",
|
||||
type=VRMotionCaptureObject,
|
||||
)
|
||||
|
||||
bpy.app.handlers.load_post.append(vr_ensure_default_landmark)
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
bpy.utils.unregister_class(cls)
|
||||
|
||||
del bpy.types.Scene.vr_landmarks
|
||||
del bpy.types.Scene.vr_landmarks_selected
|
||||
del bpy.types.Scene.vr_landmarks_active
|
||||
del bpy.types.Scene.vr_mocap_objects
|
||||
|
||||
bpy.app.handlers.load_post.remove(vr_ensure_default_landmark)
|
Loading…
Reference in New Issue