VR: Customizable Actions

https://developer.blender.org/D13421
This commit is contained in:
Peter Kim 2022-02-20 15:24:51 +09:00
parent b0274e50da
commit b172b0292c
5 changed files with 1043 additions and 56 deletions

View File

@ -4,6 +4,7 @@
if "bpy" in locals():
import importlib
importlib.reload(action_map_io)
importlib.reload(defaults)
else:
from . import action_map_io, defaults
@ -15,22 +16,65 @@ import importlib.util
import os.path
def vr_actionmap_active_get(session_settings):
actionmaps = session_settings.actionmaps
return (
None if (len(actionmaps) <
1) else actionmaps[session_settings.active_actionmap]
)
def vr_actionmap_selected_get(session_settings):
actionmaps = session_settings.actionmaps
return (
None if (len(actionmaps) <
1) else actionmaps[session_settings.selected_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_user_path_selected_get(ami):
user_paths = ami.user_paths
return (
None if (len(user_paths) <
1) else user_paths[ami.selected_user_path]
)
def vr_actionmap_binding_selected_get(ami):
actionmap_bindings = ami.bindings
return (
None if (len(actionmap_bindings) <
1) else actionmap_bindings[ami.selected_binding]
)
def vr_actionmap_component_path_selected_get(amb):
component_paths = amb.component_paths
return (
None if (len(component_paths) <
1) else component_paths[amb.selected_component_path]
)
def vr_actionset_active_update(context):
session_state = context.window_manager.xr_session_state
if not session_state or len(session_state.actionmaps) < 1:
if not session_state:
return
scene = context.scene
session_settings = context.window_manager.xr_session_settings
am = vr_actionmap_active_get(session_settings)
if not am:
return
if scene.vr_actions_use_gamepad and session_state.actionmaps.find(session_state, defaults.VRDefaultActionmaps.GAMEPAD.value):
session_state.active_action_set_set(context, defaults.VRDefaultActionmaps.GAMEPAD.value)
else:
# Use first action map.
session_state.active_action_set_set(context, session_state.actionmaps[0].name)
def vr_actions_use_gamepad_update(self, context):
vr_actionset_active_update(context)
session_state.active_action_set_set(context, am.name)
@persistent
@ -45,11 +89,14 @@ def vr_create_actions(context: bpy.context):
if not scene.vr_actions_enable:
return
# Ensure default action maps.
if not defaults.vr_ensure_default_actionmaps(session_state):
return
session_settings = context.window_manager.xr_session_settings
for am in session_state.actionmaps:
if (len(session_settings.actionmaps) < 1):
# Ensure default action maps.
if not defaults.vr_ensure_default_actionmaps(session_settings):
return
for am in session_settings.actionmaps:
if len(am.actionmap_items) < 1:
continue
@ -101,7 +148,7 @@ def vr_create_actions(context: bpy.context):
vr_actionset_active_update(context)
def vr_load_actionmaps(session_state, filepath):
def vr_load_actionmaps(session_settings, filepath):
if not os.path.exists(filepath):
return False
@ -109,16 +156,16 @@ def vr_load_actionmaps(session_state, filepath):
file = importlib.util.module_from_spec(spec)
spec.loader.exec_module(file)
action_map_io.actionconfig_init_from_data(session_state, file.actionconfig_data, file.actionconfig_version)
action_map_io.actionconfig_init_from_data(session_settings, file.actionconfig_data, file.actionconfig_version)
return True
def vr_save_actionmaps(session_state, filepath, sort=False):
action_map_io.actionconfig_export_as_data(session_state, filepath, sort=sort)
def vr_save_actionmaps(session_settings, filepath, sort=False):
action_map_io.actionconfig_export_as_data(session_settings, filepath, sort=sort)
print("Saved XR actionmaps: " + filepath)
return True
@ -128,11 +175,6 @@ def register():
description="Enable default VR controller actions, including controller poses and haptics",
default=True,
)
bpy.types.Scene.vr_actions_use_gamepad = bpy.props.BoolProperty(
description="Use input from gamepad (Microsoft Xbox Controller) instead of motion controllers",
default=False,
update=vr_actions_use_gamepad_update,
)
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,
@ -155,7 +197,6 @@ def register():
def unregister():
del bpy.types.Scene.vr_actions_enable
del bpy.types.Scene.vr_actions_use_gamepad
del bpy.types.Scene.vr_actions_enable_huawei
del bpy.types.Scene.vr_actions_enable_reverb_g2
del bpy.types.Scene.vr_actions_enable_vive_cosmos

View File

@ -189,10 +189,10 @@ def amb_data_from_args(amb, args, type):
amb.pose_rotation.z = float(l[2])
def actionconfig_export_as_data(session_state, filepath, *, sort=False):
def actionconfig_export_as_data(session_settings, filepath, *, sort=False):
export_actionmaps = []
for am in session_state.actionmaps:
for am in session_settings.actionmaps:
export_actionmaps.append(am)
if sort:
@ -318,7 +318,7 @@ def actionmap_init_from_data(am, am_items):
actionmap_item_init_from_data(ami, ami_bindings)
def actionconfig_init_from_data(session_state, actionconfig_data, actionconfig_version):
def actionconfig_init_from_data(session_settings, actionconfig_data, actionconfig_version):
# Load data in the format defined above.
#
# Runs at load time, keep this fast!
@ -327,7 +327,7 @@ def actionconfig_init_from_data(session_state, actionconfig_data, actionconfig_v
actionconfig_data = actionconfig_update(actionconfig_data, actionconfig_version)
for (am_name, am_content) in actionconfig_data:
am = session_state.actionmaps.new(session_state, am_name, True)
am = session_settings.actionmaps.new(am_name, True)
am_items = am_content["items"]
# Check here instead of inside 'actionmap_init_from_data'
# because we want to allow both tuple & list types in that case.
@ -338,9 +338,9 @@ def actionconfig_init_from_data(session_state, actionconfig_data, actionconfig_v
actionmap_init_from_data(am, am_items)
def actionconfig_import_from_data(session_state, actionconfig_data, *, actionconfig_version=(0, 0, 0)):
def actionconfig_import_from_data(session_settings, actionconfig_data, *, actionconfig_version=(0, 0, 0)):
# Load data in the format defined above.
#
# Runs at load time, keep this fast!
import bpy
actionconfig_init_from_data(session_state, actionconfig_data, actionconfig_version)
actionconfig_init_from_data(session_settings, actionconfig_data, actionconfig_version)

View File

@ -9,7 +9,6 @@ else:
from . import action_map
import bpy
from bpy.app.handlers import persistent
from enum import Enum
import math
import os.path
@ -71,8 +70,8 @@ class VRDefaultActionprofiles(Enum):
WMR = "/interaction_profiles/microsoft/motion_controller"
def vr_defaults_actionmap_add(session_state, name):
am = session_state.actionmaps.new(session_state, name, True)
def vr_defaults_actionmap_add(session_settings, name):
am = session_settings.actionmaps.new(name, True)
return am
@ -186,8 +185,8 @@ def vr_defaults_haptic_actionbinding_add(ami,
return amb
def vr_defaults_create_default(session_state):
am = vr_defaults_actionmap_add(session_state,
def vr_defaults_create_default(session_settings):
am = vr_defaults_actionmap_add(session_settings,
VRDefaultActionmaps.DEFAULT.value)
if not am:
return
@ -1199,8 +1198,8 @@ def vr_defaults_create_default(session_state):
"/output/haptic"])
def vr_defaults_create_default_gamepad(session_state):
am = vr_defaults_actionmap_add(session_state,
def vr_defaults_create_default_gamepad(session_settings):
am = vr_defaults_actionmap_add(session_settings,
VRDefaultActionmaps.GAMEPAD.value)
ami = vr_defaults_action_add(am,
@ -1476,11 +1475,11 @@ def vr_get_default_config_path():
return os.path.join(filepath, "default.py")
def vr_ensure_default_actionmaps(session_state):
def vr_ensure_default_actionmaps(session_settings):
loaded = True
for name in VRDefaultActionmaps:
if not session_state.actionmaps.find(session_state, name.value):
if not session_settings.actionmaps.find(name.value):
loaded = False
break
@ -1492,11 +1491,11 @@ def vr_ensure_default_actionmaps(session_state):
if not os.path.exists(filepath):
# Create and save default action maps.
vr_defaults_create_default(session_state)
vr_defaults_create_default_gamepad(session_state)
vr_defaults_create_default(session_settings)
vr_defaults_create_default_gamepad(session_settings)
action_map.vr_save_actionmaps(session_state, filepath, sort=False)
action_map.vr_save_actionmaps(session_settings, filepath, sort=False)
loaded = action_map.vr_load_actionmaps(session_state, filepath)
loaded = action_map.vr_load_actionmaps(session_settings, filepath)
return loaded

View File

@ -4,9 +4,10 @@
if "bpy" in locals():
import importlib
importlib.reload(action_map)
importlib.reload(properties)
else:
from . import properties
from . import action_map, properties
import bpy
from bpy.types import (
@ -68,7 +69,6 @@ class VIEW3D_PT_vr_session_view(Panel):
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")
@ -156,25 +156,392 @@ class VIEW3D_PT_vr_landmarks(Panel):
"base_scale", text="Scale")
### View.
class VIEW3D_PT_vr_actionmaps(Panel):
### 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):
session_settings = context.window_manager.xr_session_settings
am_active_idx = session_settings.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_action_user_paths(UIList):
def draw_item(self, context, layout, _data, item, icon, _active_data,
_active_propname, index):
user_path = item
layout.emboss = 'NONE'
layout.prop(user_path, "path", text="")
class VIEW3D_MT_vr_action_user_path_menu(Menu):
bl_label = "User Path Controls"
def draw(self, _context):
layout = self.layout
layout.operator("view3d.vr_action_user_paths_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 VIEW3D_UL_vr_actionbinding_component_paths(UIList):
def draw_item(self, context, layout, _data, item, icon, _active_data,
_active_propname, index):
component_path = item
layout.emboss = 'NONE'
layout.prop(component_path, "path", text="")
class VIEW3D_MT_vr_actionbinding_component_path_menu(Menu):
bl_label = "Component Path Controls"
def draw(self, _context):
layout = self.layout
layout.operator("view3d.vr_actionbinding_component_paths_clear")
class VRActionsPanel:
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "VR"
bl_label = "Action Maps"
bl_options = {'DEFAULT_CLOSED'}
class VIEW3D_PT_vr_actions_actionmaps(VRActionsPanel, Panel):
bl_label = "Action Maps"
def draw(self, context):
layout = self.layout
session_settings = context.window_manager.xr_session_settings
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", "", session_settings, "actionmaps",
session_settings, "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(session_settings)
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):
session_settings = context.window_manager.xr_session_settings
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
am = action_map.vr_actionmap_selected_get(session_settings)
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")
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_user_paths(VRActionsPanel, Panel):
bl_label = "User Paths"
bl_parent_id = "VIEW3D_PT_vr_actions_actions"
def draw(self, context):
session_settings = context.window_manager.xr_session_settings
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
am = action_map.vr_actionmap_selected_get(session_settings)
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_action_user_paths", "", ami, "user_paths",
ami, "selected_user_path", rows=2)
col = row.column(align=True)
col.operator("view3d.vr_action_user_path_add", icon='ADD', text="")
col.operator("view3d.vr_action_user_path_remove", icon='REMOVE', text="")
col.menu("VIEW3D_MT_vr_action_user_path_menu", icon='DOWNARROW_HLT', text="")
class VIEW3D_PT_vr_actions_haptics(VRActionsPanel, Panel):
bl_label = "Haptics"
bl_parent_id = "VIEW3D_PT_vr_actions_actions"
def draw(self, context):
session_settings = context.window_manager.xr_session_settings
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
am = action_map.vr_actionmap_selected_get(session_settings)
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):
session_settings = context.window_manager.xr_session_settings
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
am = action_map.vr_actionmap_selected_get(session_settings)
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")
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_component_paths(VRActionsPanel, Panel):
bl_label = "Component Paths"
bl_parent_id = "VIEW3D_PT_vr_actions_bindings"
def draw(self, context):
session_settings = context.window_manager.xr_session_settings
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
am = action_map.vr_actionmap_selected_get(session_settings)
if am:
ami = action_map.vr_actionmap_item_selected_get(am)
if ami:
amb = action_map.vr_actionmap_binding_selected_get(ami)
if amb:
col = vr_indented_layout(layout, 3)
row = col.row()
row.template_list("VIEW3D_UL_vr_actionbinding_component_paths", "", amb, "component_paths",
amb, "selected_component_path", rows=2)
col = row.column(align=True)
col.operator("view3d.vr_actionbinding_component_path_add", icon='ADD', text="")
col.operator("view3d.vr_actionbinding_component_path_remove", icon='REMOVE', text="")
col.menu("VIEW3D_MT_vr_actionbinding_component_path_menu", icon='DOWNARROW_HLT', text="")
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_use_gamepad", text="Gamepad")
col = layout.column(align=True, heading="Extensions")
col.prop(scene, "vr_actions_enable_reverb_g2", text="HP Reverb G2")
col.prop(scene, "vr_actions_enable_vive_cosmos", text="HTC Vive Cosmos")
col.prop(scene, "vr_actions_enable_vive_focus", text="HTC Vive Focus")
@ -228,11 +595,28 @@ classes = (
VIEW3D_PT_vr_session,
VIEW3D_PT_vr_session_view,
VIEW3D_PT_vr_landmarks,
VIEW3D_PT_vr_actionmaps,
VIEW3D_PT_vr_actions_actionmaps,
VIEW3D_PT_vr_actions_actions,
VIEW3D_PT_vr_actions_user_paths,
VIEW3D_PT_vr_actions_haptics,
VIEW3D_PT_vr_actions_bindings,
VIEW3D_PT_vr_actions_component_paths,
VIEW3D_PT_vr_actions_extensions,
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_action_user_paths,
VIEW3D_MT_vr_action_user_path_menu,
VIEW3D_UL_vr_actionbindings,
VIEW3D_MT_vr_actionbinding_menu,
VIEW3D_UL_vr_actionbinding_component_paths,
VIEW3D_MT_vr_actionbinding_component_path_menu,
)

View File

@ -4,9 +4,11 @@
if "bpy" in locals():
import importlib
importlib.reload(action_map)
importlib.reload(defaults)
importlib.reload(properties)
else:
from . import properties
from . import action_map, defaults, properties
import bpy
from bpy.types import (
@ -14,10 +16,12 @@ from bpy.types import (
GizmoGroup,
Operator,
)
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bgl
import math
from math import radians
from mathutils import Euler, Matrix, Quaternion, Vector
import os.path
### Landmarks.
@ -241,6 +245,542 @@ class VIEW3D_OT_vr_landmark_activate(Operator):
return {'FINISHED'}
### Actions.
class VIEW3D_OT_vr_actionmap_add(Operator):
bl_idname = "view3d.vr_actionmap_add"
bl_label = "Add VR Action Map"
bl_description = "Add a new VR action map to the scene"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = session_settings.actionmaps.new("actionmap", False)
if not am:
return {'CANCELLED'}
# Select newly created actionmap.
session_settings.selected_actionmap = len(session_settings.actionmaps) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actionmap_remove(Operator):
bl_idname = "view3d.vr_actionmap_remove"
bl_label = "Remove VR Action Map"
bl_description = "Delete the selected VR action map from the scene"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
session_settings.actionmaps.remove(am)
return {'FINISHED'}
class VIEW3D_OT_vr_actionmap_activate(Operator):
bl_idname = "view3d.vr_actionmap_activate"
bl_label = "Activate VR Action Map"
bl_description = "Set the current VR action map for the session"
bl_options = {'UNDO', 'REGISTER'}
index: bpy.props.IntProperty(
name="Index",
options={'HIDDEN'},
)
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
if (self.index >= len(session_settings.actionmaps)):
return {'CANCELLED'}
session_settings.active_actionmap = (
self.index if self.properties.is_property_set(
"index") else session_settings.selected_actionmap
)
action_map.vr_actionset_active_update(context)
return {'FINISHED'}
class VIEW3D_OT_vr_actionmaps_defaults_load(Operator):
bl_idname = "view3d.vr_actionmaps_defaults_load"
bl_label = "Load Default VR Action Maps"
bl_description = "Load default VR action maps"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
filepath = defaults.vr_get_default_config_path()
if not action_map.vr_load_actionmaps(session_settings, filepath):
return {'CANCELLED'}
return {'FINISHED'}
class VIEW3D_OT_vr_actionmaps_import(Operator, ImportHelper):
bl_idname = "view3d.vr_actionmaps_import"
bl_label = "Import VR Action Maps"
bl_description = "Import VR action maps from configuration file"
bl_options = {'UNDO', 'REGISTER'}
filter_glob: bpy.props.StringProperty(
default='*.py',
options={'HIDDEN'},
)
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
filename, ext = os.path.splitext(self.filepath)
if (ext != ".py"):
return {'CANCELLED'}
if not action_map.vr_load_actionmaps(session_settings, self.filepath):
return {'CANCELLED'}
return {'FINISHED'}
class VIEW3D_OT_vr_actionmaps_export(Operator, ExportHelper):
bl_idname = "view3d.vr_actionmaps_export"
bl_label = "Export VR Action Maps"
bl_description = "Export VR action maps to configuration file"
bl_options = {'REGISTER'}
filter_glob: bpy.props.StringProperty(
default='*.py',
options={'HIDDEN'},
)
filename_ext: bpy.props.StringProperty(
default='.py',
options={'HIDDEN'},
)
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
filename, ext = os.path.splitext(self.filepath)
if (ext != ".py"):
return {'CANCELLED'}
if not action_map.vr_save_actionmaps(session_settings, self.filepath):
return {'CANCELLED'}
return {'FINISHED'}
class VIEW3D_OT_vr_actionmap_copy(Operator):
bl_idname = "view3d.vr_actionmap_copy"
bl_label = "Copy VR Action Map"
bl_description = "Copy selected VR action map"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
# Copy actionmap.
am_new = session_settings.actionmaps.new_from_actionmap(am)
if not am_new:
return {'CANCELLED'}
# Select newly created actionmap.
session_settings.selected_actionmap = len(session_settings.actionmaps) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actionmaps_clear(Operator):
bl_idname = "view3d.vr_actionmaps_clear"
bl_label = "Clear VR Action Maps"
bl_description = "Delete all VR action maps from the scene"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
while session_settings.actionmaps:
session_settings.actionmaps.remove(session_settings.actionmaps[0])
return {'FINISHED'}
class VIEW3D_OT_vr_action_add(Operator):
bl_idname = "view3d.vr_action_add"
bl_label = "Add VR Action"
bl_description = "Add a new VR action to the action map"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = am.actionmap_items.new("action", False)
if not ami:
return {'CANCELLED'}
# Select newly created item.
am.selected_item = len(am.actionmap_items) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_action_remove(Operator):
bl_idname = "view3d.vr_action_remove"
bl_label = "Remove VR Action"
bl_description = "Delete the selected VR action from the action map"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
am.actionmap_items.remove(ami)
return {'FINISHED'}
class VIEW3D_OT_vr_action_copy(Operator):
bl_idname = "view3d.vr_action_copy"
bl_label = "Copy VR Action"
bl_description = "Copy selected VR action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
# Copy item.
ami_new = am.actionmap_items.new_from_item(ami)
if not ami_new:
return {'CANCELLED'}
# Select newly created item.
am.selected_item = len(am.actionmap_items) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actions_clear(Operator):
bl_idname = "view3d.vr_actions_clear"
bl_label = "Clear VR Actions"
bl_description = "Delete all VR actions from the action map"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
while am.actionmap_items:
am.actionmap_items.remove(am.actionmap_items[0])
return {'FINISHED'}
class VIEW3D_OT_vr_action_user_path_add(Operator):
bl_idname = "view3d.vr_action_user_path_add"
bl_label = "Add User Path"
bl_description = "Add a new user path to the VR action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
user_path = ami.user_paths.new("/")
if not user_path:
return {'CANCELLED'}
# Select newly created user path.
ami.selected_user_path = len(ami.user_paths) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_action_user_path_remove(Operator):
bl_idname = "view3d.vr_action_user_path_remove"
bl_label = "Remove User Path"
bl_description = "Delete the selected user path from the VR action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
user_path = action_map.vr_actionmap_user_path_selected_get(ami)
if not user_path:
return {'CANCELLED'}
ami.user_paths.remove(user_path)
return {'FINISHED'}
class VIEW3D_OT_vr_action_user_paths_clear(Operator):
bl_idname = "view3d.vr_action_user_paths_clear"
bl_label = "Clear User Paths"
bl_description = "Delete all user paths from the VR action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
while ami.user_paths:
ami.user_paths.remove(ami.user_paths[0])
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_add(Operator):
bl_idname = "view3d.vr_actionbinding_add"
bl_label = "Add VR Action Binding"
bl_description = "Add a new VR action binding to the action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = ami.bindings.new("binding", False)
if not amb:
return {'CANCELLED'}
# Select newly created binding.
ami.selected_binding = len(ami.bindings) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_remove(Operator):
bl_idname = "view3d.vr_actionbinding_remove"
bl_label = "Remove VR Action Binding"
bl_description = "Delete the selected VR action binding from the action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = action_map.vr_actionmap_binding_selected_get(ami)
if not amb:
return {'CANCELLED'}
ami.bindings.remove(amb)
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_copy(Operator):
bl_idname = "view3d.vr_actionbinding_copy"
bl_label = "Copy VR Action Binding"
bl_description = "Copy selected VR action binding"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = action_map.vr_actionmap_binding_selected_get(ami)
if not amb:
return {'CANCELLED'}
# Copy binding.
amb_new = ami.bindings.new_from_binding(amb)
if not amb_new:
return {'CANCELLED'}
# Select newly created binding.
ami.selected_binding = len(ami.bindings) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actionbindings_clear(Operator):
bl_idname = "view3d.vr_actionbindings_clear"
bl_label = "Clear VR Action Bindings"
bl_description = "Delete all VR action bindings from the action"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
while ami.bindings:
ami.bindings.remove(ami.bindings[0])
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_component_path_add(Operator):
bl_idname = "view3d.vr_actionbinding_component_path_add"
bl_label = "Add Component Path"
bl_description = "Add a new component path to the VR action binding"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = action_map.vr_actionmap_binding_selected_get(ami)
if not amb:
return {'CANCELLED'}
component_path = amb.component_paths.new("/")
if not component_path:
return {'CANCELLED'}
# Select newly created component path.
amb.selected_component_path = len(amb.component_paths) - 1
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_component_path_remove(Operator):
bl_idname = "view3d.vr_actionbinding_component_path_remove"
bl_label = "Remove Component Path"
bl_description = "Delete the selected component path from the VR action binding"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = action_map.vr_actionmap_binding_selected_get(ami)
if not amb:
return {'CANCELLED'}
component_path = action_map.vr_actionmap_component_path_selected_get(amb)
if not component_path:
return {'CANCELLED'}
amb.component_paths.remove(component_path)
return {'FINISHED'}
class VIEW3D_OT_vr_actionbinding_component_paths_clear(Operator):
bl_idname = "view3d.vr_actionbinding_component_paths_clear"
bl_label = "Clear Component Paths"
bl_description = "Delete all component paths from the VR action binding"
bl_options = {'UNDO', 'REGISTER'}
def execute(self, context):
session_settings = context.window_manager.xr_session_settings
am = action_map.vr_actionmap_selected_get(session_settings)
if not am:
return {'CANCELLED'}
ami = action_map.vr_actionmap_item_selected_get(am)
if not ami:
return {'CANCELLED'}
amb = action_map.vr_actionmap_binding_selected_get(ami)
if not amb:
return {'CANCELLED'}
while amb.component_paths:
amb.component_paths.remove(amb.component_paths[0])
return {'FINISHED'}
### Gizmos.
class VIEW3D_GT_vr_camera_cone(Gizmo):
bl_idname = "VIEW_3D_GT_vr_camera_cone"
@ -486,6 +1026,29 @@ classes = (
VIEW3D_OT_cursor_to_vr_landmark,
VIEW3D_OT_update_vr_landmark,
VIEW3D_OT_vr_actionmap_add,
VIEW3D_OT_vr_actionmap_remove,
VIEW3D_OT_vr_actionmap_activate,
VIEW3D_OT_vr_actionmaps_defaults_load,
VIEW3D_OT_vr_actionmaps_import,
VIEW3D_OT_vr_actionmaps_export,
VIEW3D_OT_vr_actionmap_copy,
VIEW3D_OT_vr_actionmaps_clear,
VIEW3D_OT_vr_action_add,
VIEW3D_OT_vr_action_remove,
VIEW3D_OT_vr_action_copy,
VIEW3D_OT_vr_actions_clear,
VIEW3D_OT_vr_action_user_path_add,
VIEW3D_OT_vr_action_user_path_remove,
VIEW3D_OT_vr_action_user_paths_clear,
VIEW3D_OT_vr_actionbinding_add,
VIEW3D_OT_vr_actionbinding_remove,
VIEW3D_OT_vr_actionbinding_copy,
VIEW3D_OT_vr_actionbindings_clear,
VIEW3D_OT_vr_actionbinding_component_path_add,
VIEW3D_OT_vr_actionbinding_component_path_remove,
VIEW3D_OT_vr_actionbinding_component_paths_clear,
VIEW3D_GT_vr_camera_cone,
VIEW3D_GT_vr_controller_grip,
VIEW3D_GT_vr_controller_aim,