diff options
author | Peter Kim <pk15950@gmail.com> | 2022-02-20 09:54:14 +0300 |
---|---|---|
committer | Peter Kim <pk15950@gmail.com> | 2022-02-20 09:54:14 +0300 |
commit | f358eb205b0657831de1cd79cec6801b051b5924 (patch) | |
tree | 81b0d4b9fcae3a231be544c44b7e2451225c7b39 | |
parent | b172b0292c6d046d2211e87d0558e5cc23ac9664 (diff) |
VR: Motion Capture
https://developer.blender.org/D13102
-rw-r--r-- | viewport_vr_preview/gui.py | 77 | ||||
-rw-r--r-- | viewport_vr_preview/operators.py | 126 | ||||
-rw-r--r-- | viewport_vr_preview/properties.py | 53 |
3 files changed, 255 insertions, 1 deletions
diff --git a/viewport_vr_preview/gui.py b/viewport_vr_preview/gui.py index cfbbc4c1..8b92f13d 100644 --- a/viewport_vr_preview/gui.py +++ b/viewport_vr_preview/gui.py @@ -548,6 +548,79 @@ class VIEW3D_PT_vr_actions_extensions(VRActionsPanel, Panel): 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_objects_enable") + layout.operator("view3d.vr_mocap_objects_disable") + layout.operator("view3d.vr_mocap_objects_clear") + 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' @@ -602,6 +675,7 @@ classes = ( VIEW3D_PT_vr_actions_bindings, VIEW3D_PT_vr_actions_component_paths, VIEW3D_PT_vr_actions_extensions, + VIEW3D_PT_vr_motion_capture, VIEW3D_PT_vr_viewport_feedback, VIEW3D_UL_vr_landmarks, @@ -617,6 +691,9 @@ classes = ( VIEW3D_MT_vr_actionbinding_menu, VIEW3D_UL_vr_actionbinding_component_paths, VIEW3D_MT_vr_actionbinding_component_path_menu, + + VIEW3D_UL_vr_mocap_objects, + VIEW3D_MT_vr_mocap_object_menu, ) diff --git a/viewport_vr_preview/operators.py b/viewport_vr_preview/operators.py index d540658d..6d45c500 100644 --- a/viewport_vr_preview/operators.py +++ b/viewport_vr_preview/operators.py @@ -245,7 +245,7 @@ class VIEW3D_OT_vr_landmark_activate(Operator): return {'FINISHED'} - ### Actions. +### Actions. class VIEW3D_OT_vr_actionmap_add(Operator): bl_idname = "view3d.vr_actionmap_add" bl_label = "Add VR Action Map" @@ -781,6 +781,123 @@ class VIEW3D_OT_vr_actionbinding_component_paths_clear(Operator): return {'FINISHED'} +### Motion capture. +class VIEW3D_OT_vr_mocap_object_add(Operator): + bl_idname = "view3d.vr_mocap_object_add" + bl_label = "Add VR Motion Capture Object" + bl_description = "Add a new VR motion capture object" + bl_options = {'UNDO', 'REGISTER'} + + def execute(self, context): + session_settings = context.window_manager.xr_session_settings + + mocap_ob = session_settings.mocap_objects.new(None) + if not mocap_ob: + return {'CANCELLED'} + + # Enable object binding by default. + mocap_ob.enable = True + + context.scene.vr_mocap_objects.add() + + # Select newly created object. + session_settings.selected_mocap_object = len(session_settings.mocap_objects) - 1 + + return {'FINISHED'} + + +class VIEW3D_OT_vr_mocap_object_remove(Operator): + bl_idname = "view3d.vr_mocap_object_remove" + bl_label = "Remove VR Motion Capture Object" + bl_description = "Delete the selected VR motion capture object" + bl_options = {'UNDO', 'REGISTER'} + + def execute(self, context): + session_settings = context.window_manager.xr_session_settings + + mocap_ob = properties.vr_mocap_object_selected_get(session_settings) + if not mocap_ob: + return {'CANCELLED'} + + context.scene.vr_mocap_objects.remove(session_settings.selected_mocap_object) + + session_settings.mocap_objects.remove(mocap_ob) + + return {'FINISHED'} + + +class VIEW3D_OT_vr_mocap_objects_enable(Operator): + bl_idname = "view3d.vr_mocap_objects_enable" + bl_label = "Enable VR Motion Capture Objects" + bl_description = "Enable all VR motion capture objects" + bl_options = {'UNDO', 'REGISTER'} + + def execute(self, context): + session_settings = context.window_manager.xr_session_settings + + for mocap_ob in session_settings.mocap_objects: + mocap_ob.enable = True + + return {'FINISHED'} + + +class VIEW3D_OT_vr_mocap_objects_disable(Operator): + bl_idname = "view3d.vr_mocap_objects_disable" + bl_label = "Disable VR Motion Capture Objects" + bl_description = "Disable all VR motion capture objects" + bl_options = {'UNDO', 'REGISTER'} + + def execute(self, context): + session_settings = context.window_manager.xr_session_settings + + for mocap_ob in session_settings.mocap_objects: + mocap_ob.enable = False + + return {'FINISHED'} + + +class VIEW3D_OT_vr_mocap_objects_clear(Operator): + bl_idname = "view3d.vr_mocap_objects_clear" + bl_label = "Clear VR Motion Capture Objects" + bl_description = "Delete all VR motion capture objects from the scene" + bl_options = {'UNDO', 'REGISTER'} + + def execute(self, context): + session_settings = context.window_manager.xr_session_settings + + context.scene.vr_mocap_objects.clear() + + while session_settings.mocap_objects: + session_settings.mocap_objects.remove(session_settings.mocap_objects[0]) + + return {'FINISHED'} + + +class VIEW3D_OT_vr_mocap_object_help(Operator): + bl_idname = "view3d.vr_mocap_object_help" + bl_label = "Help" + bl_description = "Display information about VR motion capture objects" + bl_options = {'REGISTER'} + + def execute(self, context): + info_header = "Common User Paths:" + info_headset = "Headset - /user/head" + info_left_controller = "Left Controller* - /user/hand/left" + info_right_controller = "Right Controller* - /user/hand/right" + info_note = "*Requires VR actions for controller poses" + + def draw(self, context): + self.layout.label(text=info_header) + self.layout.label(text=info_headset) + self.layout.label(text=info_left_controller) + self.layout.label(text=info_right_controller) + self.layout.label(text=info_note) + + context.window_manager.popup_menu(draw, title="Motion Capture Objects", icon='INFO') + + return {'FINISHED'} + + ### Gizmos. class VIEW3D_GT_vr_camera_cone(Gizmo): bl_idname = "VIEW_3D_GT_vr_camera_cone" @@ -1049,6 +1166,13 @@ classes = ( VIEW3D_OT_vr_actionbinding_component_path_remove, VIEW3D_OT_vr_actionbinding_component_paths_clear, + VIEW3D_OT_vr_mocap_object_add, + VIEW3D_OT_vr_mocap_object_remove, + VIEW3D_OT_vr_mocap_objects_enable, + VIEW3D_OT_vr_mocap_objects_disable, + VIEW3D_OT_vr_mocap_objects_clear, + VIEW3D_OT_vr_mocap_object_help, + VIEW3D_GT_vr_camera_cone, VIEW3D_GT_vr_controller_grip, VIEW3D_GT_vr_controller_aim, diff --git a/viewport_vr_preview/properties.py b/viewport_vr_preview/properties.py index 55a4d4eb..20aa9d49 100644 --- a/viewport_vr_preview/properties.py +++ b/viewport_vr_preview/properties.py @@ -194,8 +194,53 @@ class VRLandmark(PropertyGroup): ) +### 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, ) @@ -213,6 +258,13 @@ def register(): 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) @@ -224,5 +276,6 @@ def unregister(): 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) |