Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--viewport_vr_preview.py840
-rw-r--r--viewport_vr_preview/__init__.py71
-rw-r--r--viewport_vr_preview/action_map.py206
-rw-r--r--viewport_vr_preview/action_map_io.py351
-rw-r--r--viewport_vr_preview/configs/default.py534
-rw-r--r--viewport_vr_preview/defaults.py1979
-rw-r--r--viewport_vr_preview/gui.py642
-rw-r--r--viewport_vr_preview/operators.py1014
-rw-r--r--viewport_vr_preview/properties.py295
-rw-r--r--viewport_vr_preview/versioning.py54
10 files changed, 5146 insertions, 840 deletions
diff --git a/viewport_vr_preview.py b/viewport_vr_preview.py
deleted file mode 100644
index 07f34756..00000000
--- a/viewport_vr_preview.py
+++ /dev/null
@@ -1,840 +0,0 @@
-# ##### 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 (
- Gizmo,
- GizmoGroup,
- PropertyGroup,
- UIList,
- Menu,
- Panel,
- Operator,
-)
-from bpy.props import (
- CollectionProperty,
- IntProperty,
- BoolProperty,
-)
-from bpy.app.handlers import persistent
-
-bl_info = {
- "name": "VR Scene Inspection",
- "author": "Julian Eisel (Severin), Sebastian Koenig",
- "version": (0, 9, 0),
- "blender": (2, 90, 0),
- "location": "3D View > Sidebar > VR",
- "description": ("View the viewport with virtual reality glasses "
- "(head-mounted displays)"),
- "support": "OFFICIAL",
- "warning": "This is an early, limited preview of in development "
- "VR support for Blender.",
- "doc_url": "{BLENDER_MANUAL_URL}/addons/3d_view/vr_scene_inspection.html",
- "category": "3D View",
-}
-
-
-@persistent
-def ensure_default_vr_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 xr_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 == 'USER_CAMERA':
- session_settings.base_pose_type = 'OBJECT'
- elif landmark_active.type == 'CUSTOM':
- session_settings.base_pose_type = 'CUSTOM'
-
-
-def xr_landmark_active_camera_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_camera
-
-
-def xr_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 xr_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 xr_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:
- xr_landmark_active_type_update(self, context)
-
-
-def xr_landmark_camera_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:
- xr_landmark_active_camera_update(self, context)
-
-
-def xr_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:
- xr_landmark_active_base_pose_location_update(self, context)
-
-
-def xr_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:
- xr_landmark_active_base_pose_angle_update(self, context)
-
-
-def xr_landmark_camera_object_poll(self, object):
- return object.type == 'CAMERA'
-
-
-def xr_landmark_active_update(self, context):
- wm = context.window_manager
-
- xr_landmark_active_type_update(self, context)
- xr_landmark_active_camera_update(self, context)
- xr_landmark_active_base_pose_location_update(self, context)
- xr_landmark_active_base_pose_angle_update(self, context)
-
- if wm.xr_session_state:
- wm.xr_session_state.reset_to_base_pose(context)
-
-
-class VIEW3D_MT_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 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"),
- ('USER_CAMERA', "Custom Camera",
- "Use an existing camera 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=xr_landmark_type_update,
- )
- base_pose_camera: bpy.props.PointerProperty(
- name="Camera",
- type=bpy.types.Object,
- poll=xr_landmark_camera_object_poll,
- update=xr_landmark_camera_update,
- )
- base_pose_location: bpy.props.FloatVectorProperty(
- name="Base Pose Location",
- subtype='TRANSLATION',
- update=xr_landmark_base_pose_location_update,
- )
-
- base_pose_angle: bpy.props.FloatProperty(
- name="Base Pose Angle",
- subtype='ANGLE',
- update=xr_landmark_base_pose_angle_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]
- )
-
-
-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 = 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_landmark_menu", icon='DOWNARROW_HLT', text="")
-
- if landmark_selected:
- layout.prop(landmark_selected, "type")
-
- if landmark_selected.type == 'USER_CAMERA':
- layout.prop(landmark_selected, "base_pose_camera")
- elif landmark_selected.type == 'CUSTOM':
- layout.prop(landmark_selected,
- "base_pose_location", text="Location")
- layout.prop(landmark_selected,
- "base_pose_angle", text="Angle")
-
-
-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 = layout.column(align=True)
- col.prop(session_settings, "clip_start", text="Clip Start")
- col.prop(session_settings, "clip_end", text="End")
-
-
-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")
-
-
-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")
-
-
-class VIEW3D_OT_vr_landmark_add(Operator):
- bl_idname = "view3d.vr_landmark_add"
- bl_label = "Add VR Landmark"
- bl_description = "Add a new VR landmark to the list and select it"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- scene = context.scene
- landmarks = scene.vr_landmarks
-
- landmarks.add()
-
- # select newly created set
- scene.vr_landmarks_selected = len(landmarks) - 1
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_vr_landmark_from_camera(Operator):
- bl_idname = "view3d.vr_landmark_from_camera"
- bl_label = "Add VR Landmark from camera"
- bl_description = "Add a new VR landmark from the active camera object to the list and select it"
- bl_options = {'UNDO', 'REGISTER'}
-
- @classmethod
- def poll(cls, context):
- cam_selected = False
-
- vl_objects = bpy.context.view_layer.objects
- if vl_objects.active and vl_objects.active.type == 'CAMERA':
- cam_selected = True
- return cam_selected
-
- def execute(self, context):
- scene = context.scene
- landmarks = scene.vr_landmarks
- cam = context.view_layer.objects.active
- lm = landmarks.add()
- lm.type = 'USER_CAMERA'
- lm.base_pose_camera = cam
- lm.name = "LM_" + cam.name
-
- # select newly created set
- scene.vr_landmarks_selected = len(landmarks) - 1
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_vr_landmark_from_session(Operator):
- bl_idname = "view3d.vr_landmark_from_session"
- bl_label = "Add VR Landmark from session"
- bl_description = "Add VR landmark from the viewer pose of the running VR session to the list and select it"
- bl_options = {'UNDO', 'REGISTER'}
-
- @classmethod
- def poll(cls, context):
- return bpy.types.XrSessionState.is_running(context)
-
- @staticmethod
- def _calc_landmark_angle_from_viewer_rotation(rot):
- from mathutils import Vector
-
- # We want an angle around Z based on the current viewer rotation. Idea
- # is to create a vector from the viewer rotation, project that onto a
- # Z-Up plane and use the resulting vector to get an angle around Z.
-
- view_rot_vec = Vector((0, 0, 1))
- view_rot_vec.rotate(rot)
- angle_vec = view_rot_vec - view_rot_vec.project(Vector((0, 0, 1)))
-
- # We could probably use a 3D version of Vector.angle_signed() here, but
- # that's not available. So manually calculate it via a quaternion delta.
- forward_vec = Vector((0, -1, 0))
- diff = angle_vec.rotation_difference(forward_vec)
-
- return diff.angle * -diff.axis[2]
-
- def execute(self, context):
- scene = context.scene
- landmarks = scene.vr_landmarks
- wm = context.window_manager
-
- lm = landmarks.add()
- lm.type = 'CUSTOM'
- scene.vr_landmarks_selected = len(landmarks) - 1
-
- loc = wm.xr_session_state.viewer_pose_location
- rot = wm.xr_session_state.viewer_pose_rotation
- angle = self._calc_landmark_angle_from_viewer_rotation(rot)
-
- lm.base_pose_location = loc
- lm.base_pose_angle = angle
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_update_vr_landmark(Operator):
- bl_idname = "view3d.update_vr_landmark"
- bl_label = "Update Custom VR Landmark"
- bl_description = "Update the selected landmark from the current viewer pose in the VR session"
- bl_options = {'UNDO', 'REGISTER'}
-
- @classmethod
- def poll(cls, context):
- selected_landmark = VRLandmark.get_selected_landmark(context)
- return bpy.types.XrSessionState.is_running(context) and selected_landmark.type == 'CUSTOM'
-
- def execute(self, context):
- wm = context.window_manager
-
- lm = VRLandmark.get_selected_landmark(context)
-
- loc = wm.xr_session_state.viewer_pose_location
- rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
-
- lm.base_pose_location = loc
- lm.base_pose_angle = rot
-
- # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
- xr_landmark_active_update(None, context)
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_vr_landmark_remove(Operator):
- bl_idname = "view3d.vr_landmark_remove"
- bl_label = "Remove VR Landmark"
- bl_description = "Delete the selected VR landmark from the list"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- scene = context.scene
- landmarks = scene.vr_landmarks
-
- if len(landmarks) > 1:
- landmark_selected_idx = scene.vr_landmarks_selected
- landmarks.remove(landmark_selected_idx)
-
- scene.vr_landmarks_selected -= 1
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_cursor_to_vr_landmark(Operator):
- bl_idname = "view3d.cursor_to_vr_landmark"
- bl_label = "Cursor to VR Landmark"
- bl_description = "Move the 3D Cursor to the selected VR Landmark"
- bl_options = {'UNDO', 'REGISTER'}
-
- @classmethod
- def poll(cls, context):
- lm = VRLandmark.get_selected_landmark(context)
- if lm.type == 'SCENE_CAMERA':
- return context.scene.camera is not None
- elif lm.type == 'USER_CAMERA':
- return lm.base_pose_camera is not None
-
- return True
-
- def execute(self, context):
- scene = context.scene
- lm = VRLandmark.get_selected_landmark(context)
- if lm.type == 'SCENE_CAMERA':
- lm_pos = scene.camera.location
- elif lm.type == 'USER_CAMERA':
- lm_pos = lm.base_pose_camera.location
- else:
- lm_pos = lm.base_pose_location
- scene.cursor.location = lm_pos
-
- return{'FINISHED'}
-
-
-class VIEW3d_OT_add_camera_from_vr_landmark(Operator):
- bl_idname = "view3d.add_camera_from_vr_landmark"
- bl_label = "New Camera from VR Landmark"
- bl_description = "Create a new Camera from the selected VR Landmark"
- bl_options = {'UNDO', 'REGISTER'}
-
- def execute(self, context):
- import math
-
- scene = context.scene
- lm = VRLandmark.get_selected_landmark(context)
-
- cam = bpy.data.cameras.new("Camera_" + lm.name)
- new_cam = bpy.data.objects.new("Camera_" + lm.name, cam)
- scene.collection.objects.link(new_cam)
- angle = lm.base_pose_angle
- new_cam.location = lm.base_pose_location
- new_cam.rotation_euler = (math.pi, 0, angle)
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_camera_to_vr_landmark(Operator):
- bl_idname = "view3d.camera_to_vr_landmark"
- bl_label = "Scene Camera to VR Landmark"
- bl_description = "Position the scene camera at the selected landmark"
- bl_options = {'UNDO', 'REGISTER'}
-
- @classmethod
- def poll(cls, context):
- return context.scene.camera is not None
-
- def execute(self, context):
- import math
-
- scene = context.scene
- lm = VRLandmark.get_selected_landmark(context)
-
- cam = scene.camera
- angle = lm.base_pose_angle
- cam.location = lm.base_pose_location
- cam.rotation_euler = (math.pi / 2, 0, angle)
-
- return {'FINISHED'}
-
-
-class VIEW3D_OT_vr_landmark_activate(Operator):
- bl_idname = "view3d.vr_landmark_activate"
- bl_label = "Activate VR Landmark"
- bl_description = "Change to the selected VR landmark from the list"
- bl_options = {'UNDO', 'REGISTER'}
-
- index: IntProperty(
- name="Index",
- options={'HIDDEN'},
- )
-
- def execute(self, context):
- scene = context.scene
-
- if self.index >= len(scene.vr_landmarks):
- return {'CANCELLED'}
-
- scene.vr_landmarks_active = (
- self.index if self.properties.is_property_set(
- "index") else scene.vr_landmarks_selected
- )
-
- return {'FINISHED'}
-
-
-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
- view3d = context.space_data
-
- 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_landmarks")
- layout.prop(view3d, "mirror_xr_session")
-
-
-class VIEW3D_GT_vr_camera_cone(Gizmo):
- bl_idname = "VIEW_3D_GT_vr_camera_cone"
-
- aspect = 1.0, 1.0
-
- def draw(self, context):
- import bgl
-
- if not hasattr(self, "frame_shape"):
- aspect = self.aspect
-
- frame_shape_verts = (
- (-aspect[0], -aspect[1], -1.0),
- (aspect[0], -aspect[1], -1.0),
- (aspect[0], aspect[1], -1.0),
- (-aspect[0], aspect[1], -1.0),
- )
- lines_shape_verts = (
- (0.0, 0.0, 0.0),
- frame_shape_verts[0],
- (0.0, 0.0, 0.0),
- frame_shape_verts[1],
- (0.0, 0.0, 0.0),
- frame_shape_verts[2],
- (0.0, 0.0, 0.0),
- frame_shape_verts[3],
- )
-
- self.frame_shape = self.new_custom_shape(
- 'LINE_LOOP', frame_shape_verts)
- self.lines_shape = self.new_custom_shape(
- 'LINES', lines_shape_verts)
-
- # Ensure correct GL state (otherwise other gizmos might mess that up)
- bgl.glLineWidth(1)
- bgl.glEnable(bgl.GL_BLEND)
-
- self.draw_custom_shape(self.frame_shape)
- self.draw_custom_shape(self.lines_shape)
-
-
-class VIEW3D_GGT_vr_viewer_pose(GizmoGroup):
- bl_idname = "VIEW3D_GGT_vr_viewer_pose"
- bl_label = "VR Viewer Pose Indicator"
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'WINDOW'
- bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
-
- @classmethod
- def poll(cls, context):
- view3d = context.space_data
- return (
- view3d.shading.vr_show_virtual_camera and
- bpy.types.XrSessionState.is_running(context) and
- not view3d.mirror_xr_session
- )
-
- @staticmethod
- def _get_viewer_pose_matrix(context):
- from mathutils import Matrix, Quaternion
-
- wm = context.window_manager
-
- loc = wm.xr_session_state.viewer_pose_location
- rot = wm.xr_session_state.viewer_pose_rotation
-
- rotmat = Matrix.Identity(3)
- rotmat.rotate(rot)
- rotmat.resize_4x4()
- transmat = Matrix.Translation(loc)
-
- return transmat @ rotmat
-
- def setup(self, context):
- gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
- gizmo.aspect = 1 / 3, 1 / 4
-
- gizmo.color = gizmo.color_highlight = 0.2, 0.6, 1.0
- gizmo.alpha = 1.0
-
- self.gizmo = gizmo
-
- def draw_prepare(self, context):
- self.gizmo.matrix_basis = self._get_viewer_pose_matrix(context)
-
-
-class VIEW3D_GGT_vr_landmarks(GizmoGroup):
- bl_idname = "VIEW3D_GGT_vr_landmarks"
- bl_label = "VR Landmark Indicators"
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'WINDOW'
- bl_options = {'3D', 'PERSISTENT', 'SCALE'}
-
- @classmethod
- def poll(cls, context):
- view3d = context.space_data
- return (
- view3d.shading.vr_show_landmarks
- )
-
- def setup(self, context):
- pass
-
- def draw_prepare(self, context):
- # first delete the old gizmos
- for g in self.gizmos:
- self.gizmos.remove(g)
-
- from math import radians
- from mathutils import Matrix, Euler
- scene = context.scene
- landmarks = scene.vr_landmarks
-
- for lm in landmarks:
- if ((lm.type == 'SCENE_CAMERA' and not scene.camera) or
- (lm.type == 'USER_CAMERA' and not lm.base_pose_camera)):
- continue
-
- gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
- gizmo.aspect = 1 / 3, 1 / 4
-
- gizmo.color = gizmo.color_highlight = 0.2, 1.0, 0.6
- gizmo.alpha = 1.0
-
- self.gizmo = gizmo
-
- if lm.type == 'SCENE_CAMERA':
- cam = scene.camera
- lm_mat = cam.matrix_world if cam else Matrix.Identity(4)
- elif lm.type == 'USER_CAMERA':
- lm_mat = lm.base_pose_camera.matrix_world
- else:
- angle = lm.base_pose_angle
- raw_rot = Euler((radians(90.0), 0, angle))
-
- rotmat = Matrix.Identity(3)
- rotmat.rotate(raw_rot)
- rotmat.resize_4x4()
-
- transmat = Matrix.Translation(lm.base_pose_location)
-
- lm_mat = transmat @ rotmat
-
- self.gizmo.matrix_basis = lm_mat
-
-
-classes = (
- VIEW3D_PT_vr_session,
- VIEW3D_PT_vr_session_view,
- VIEW3D_PT_vr_landmarks,
- VIEW3D_PT_vr_viewport_feedback,
-
- VRLandmark,
- VIEW3D_UL_vr_landmarks,
- VIEW3D_MT_landmark_menu,
-
- VIEW3D_OT_vr_landmark_add,
- VIEW3D_OT_vr_landmark_remove,
- VIEW3D_OT_vr_landmark_activate,
- VIEW3D_OT_vr_landmark_from_session,
- VIEW3d_OT_add_camera_from_vr_landmark,
- VIEW3D_OT_camera_to_vr_landmark,
- VIEW3D_OT_vr_landmark_from_camera,
- VIEW3D_OT_cursor_to_vr_landmark,
- VIEW3D_OT_update_vr_landmark,
-
- VIEW3D_GT_vr_camera_cone,
- VIEW3D_GGT_vr_viewer_pose,
- VIEW3D_GGT_vr_landmarks,
-)
-
-
-def register():
- if not bpy.app.build_options.xr_openxr:
- bpy.utils.register_class(VIEW3D_PT_vr_info)
- return
-
- for cls in classes:
- bpy.utils.register_class(cls)
-
- bpy.types.Scene.vr_landmarks = CollectionProperty(
- name="Landmark",
- type=VRLandmark,
- )
- bpy.types.Scene.vr_landmarks_selected = IntProperty(
- name="Selected Landmark"
- )
- bpy.types.Scene.vr_landmarks_active = IntProperty(
- update=xr_landmark_active_update,
- )
- # 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 = BoolProperty(
- name="Show VR Camera"
- )
- bpy.types.View3DShading.vr_show_landmarks = BoolProperty(
- name="Show Landmarks"
- )
-
- bpy.app.handlers.load_post.append(ensure_default_vr_landmark)
-
-
-def unregister():
- if not bpy.app.build_options.xr_openxr:
- bpy.utils.unregister_class(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.View3DShading.vr_show_virtual_camera
- del bpy.types.View3DShading.vr_show_landmarks
-
- bpy.app.handlers.load_post.remove(ensure_default_vr_landmark)
-
-
-if __name__ == "__main__":
- register()
diff --git a/viewport_vr_preview/__init__.py b/viewport_vr_preview/__init__.py
new file mode 100644
index 00000000..216fec5e
--- /dev/null
+++ b/viewport_vr_preview/__init__.py
@@ -0,0 +1,71 @@
+# ##### 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>
+
+bl_info = {
+ "name": "VR Scene Inspection",
+ "author": "Julian Eisel (Severin), Sebastian Koenig, Peter Kim (muxed-reality)",
+ "version": (0, 10, 0),
+ "blender": (3, 0, 0),
+ "location": "3D View > Sidebar > VR",
+ "description": ("View the viewport with virtual reality glasses "
+ "(head-mounted displays)"),
+ "support": "OFFICIAL",
+ "warning": "This is an early, limited preview of in development "
+ "VR support for Blender.",
+ "doc_url": "{BLENDER_MANUAL_URL}/addons/3d_view/vr_scene_inspection.html",
+ "category": "3D View",
+}
+
+
+if "bpy" in locals():
+ import importlib
+ importlib.reload(action_map)
+ importlib.reload(defaults)
+ importlib.reload(gui)
+ importlib.reload(operators)
+ importlib.reload(properties)
+else:
+ from . import action_map, defaults, gui, operators, properties
+
+import bpy
+
+
+def register():
+ if not bpy.app.build_options.xr_openxr:
+ bpy.utils.register_class(gui.VIEW3D_PT_vr_info)
+ return
+
+ 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(gui.VIEW3D_PT_vr_info)
+ return
+
+ defaults.unregister()
+ action_map.unregister()
+ gui.unregister()
+ operators.unregister()
+ properties.unregister()
diff --git a/viewport_vr_preview/action_map.py b/viewport_vr_preview/action_map.py
new file mode 100644
index 00000000..1bc35569
--- /dev/null
+++ b/viewport_vr_preview/action_map.py
@@ -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)
diff --git a/viewport_vr_preview/action_map_io.py b/viewport_vr_preview/action_map_io.py
new file mode 100644
index 00000000..cd03b83f
--- /dev/null
+++ b/viewport_vr_preview/action_map_io.py
@@ -0,0 +1,351 @@
+# ##### 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>
+
+# -----------------------------------------------------------------------------
+# Export Functions
+
+__all__ = (
+ "actionconfig_export_as_data",
+ "actionconfig_import_from_data",
+ "actionconfig_init_from_data",
+ "actionmap_init_from_data",
+ "actionmap_item_init_from_data",
+)
+
+
+def indent(levels):
+ return levels * " "
+
+
+def round_float_32(f):
+ from struct import pack, unpack
+ return unpack("f", pack("f", f))[0]
+
+
+def repr_f32(f):
+ f_round = round_float_32(f)
+ f_str = repr(f)
+ f_str_frac = f_str.partition(".")[2]
+ if not f_str_frac:
+ return f_str
+ for i in range(1, len(f_str_frac)):
+ f_test = round(f, i)
+ f_test_round = round_float_32(f_test)
+ if f_test_round == f_round:
+ return "%.*f" % (i, f_test)
+ return f_str
+
+def ami_args_as_data(ami):
+ s = [
+ f"\"type\": '{ami.type}'",
+ f"\"user_path0\": '{ami.user_path0}'",
+ f"\"user_path1\": '{ami.user_path1}'",
+ ]
+
+ if ami.type == 'FLOAT' or ami.type == 'VECTOR2D':
+ s.append(f"\"op\": '{ami.op}'")
+ s.append(f"\"op_mode\": '{ami.op_mode}'")
+ s.append(f"\"bimanual\": '{ami.bimanual}'")
+ s.append(f"\"haptic_name\": '{ami.haptic_name}'")
+ s.append(f"\"haptic_match_user_paths\": '{ami.haptic_match_user_paths}'")
+ s.append(f"\"haptic_duration\": '{ami.haptic_duration}'")
+ s.append(f"\"haptic_frequency\": '{ami.haptic_frequency}'")
+ s.append(f"\"haptic_amplitude\": '{ami.haptic_amplitude}'")
+ s.append(f"\"haptic_mode\": '{ami.haptic_mode}'")
+ elif ami.type == 'POSE':
+ s.append(f"\"pose_is_controller_grip\": '{ami.pose_is_controller_grip}'")
+ s.append(f"\"pose_is_controller_aim\": '{ami.pose_is_controller_aim}'")
+
+
+ return "{" + ", ".join(s) + "}"
+
+
+def ami_data_from_args(ami, args):
+ ami.type = args["type"]
+ ami.user_path0 = args["user_path0"]
+ ami.user_path1 = args["user_path1"]
+
+ if ami.type == 'FLOAT' or ami.type == 'VECTOR2D':
+ ami.op = args["op"]
+ ami.op_mode = args["op_mode"]
+ ami.bimanual = True if (args["bimanual"] == 'True') else False
+ ami.haptic_name = args["haptic_name"]
+ ami.haptic_match_user_paths = True if (args["haptic_match_user_paths"] == 'True') else False
+ ami.haptic_duration = float(args["haptic_duration"])
+ ami.haptic_frequency = float(args["haptic_frequency"])
+ ami.haptic_amplitude = float(args["haptic_amplitude"])
+ ami.haptic_mode = args["haptic_mode"]
+ elif ami.type == 'POSE':
+ ami.pose_is_controller_grip = True if (args["pose_is_controller_grip"] == 'True') else False
+ ami.pose_is_controller_aim = True if (args["pose_is_controller_aim"] == 'True') else False
+
+
+def _ami_properties_to_lines_recursive(level, properties, lines):
+ from bpy.types import OperatorProperties
+
+ def string_value(value):
+ if isinstance(value, (str, bool, int, set)):
+ return repr(value)
+ elif isinstance(value, float):
+ return repr_f32(value)
+ elif getattr(value, '__len__', False):
+ return repr(tuple(value))
+ raise Exception(f"Export action configuration: can't write {value!r}")
+
+ for pname in properties.bl_rna.properties.keys():
+ if pname != "rna_type":
+ value = getattr(properties, pname)
+ if isinstance(value, OperatorProperties):
+ lines_test = []
+ _ami_properties_to_lines_recursive(level + 2, value, lines_test)
+ if lines_test:
+ lines.append(f"(")
+ lines.append(f"\"{pname}\",\n")
+ lines.append(f"{indent(level + 3)}" "[")
+ lines.extend(lines_test)
+ lines.append("],\n")
+ lines.append(f"{indent(level + 3)}" "),\n" f"{indent(level + 2)}")
+ del lines_test
+ elif properties.is_property_set(pname):
+ value = string_value(value)
+ lines.append((f"(\"{pname}\", {value:s}),\n" f"{indent(level + 2)}"))
+
+
+def _ami_properties_to_lines(level, ami_props, lines):
+ if ami_props is None:
+ return
+
+ lines_test = [f"\"op_properties\":\n" f"{indent(level + 1)}" "["]
+ _ami_properties_to_lines_recursive(level, ami_props, lines_test)
+ if len(lines_test) > 1:
+ lines_test.append("],\n")
+ lines.extend(lines_test)
+
+
+def _ami_attrs_or_none(level, ami):
+ lines = []
+ _ami_properties_to_lines(level + 1, ami.op_properties, lines)
+ if not lines:
+ return None
+ return "".join(lines)
+
+
+def amb_args_as_data(amb, type):
+ s = [
+ f"\"profile\": '{amb.profile}'",
+ f"\"component_path0\": '{amb.component_path0}'",
+ f"\"component_path1\": '{amb.component_path1}'",
+ ]
+
+ if type == 'FLOAT' or type == 'VECTOR2D':
+ s.append(f"\"threshold\": '{amb.threshold}'")
+ if type == 'FLOAT':
+ s.append(f"\"axis_region\": '{amb.axis0_region}'")
+ else: # type == 'VECTOR2D':
+ s.append(f"\"axis0_region\": '{amb.axis0_region}'")
+ s.append(f"\"axis1_region\": '{amb.axis1_region}'")
+ elif type == 'POSE':
+ s.append(f"\"pose_location\": '{amb.pose_location.x, amb.pose_location.y, amb.pose_location.z}'")
+ s.append(f"\"pose_rotation\": '{amb.pose_rotation.x, amb.pose_rotation.y, amb.pose_rotation.z}'")
+
+ return "{" + ", ".join(s) + "}"
+
+
+def amb_data_from_args(amb, args, type):
+ amb.profile = args["profile"]
+ amb.component_path0 = args["component_path0"]
+ amb.component_path1 = args["component_path1"]
+
+ if type == 'FLOAT' or type == 'VECTOR2D':
+ amb.threshold = float(args["threshold"])
+ if type == 'FLOAT':
+ amb.axis0_region = args["axis_region"]
+ else: # type == 'VECTOR2D':
+ amb.axis0_region = args["axis0_region"]
+ amb.axis1_region = args["axis1_region"]
+ elif type == 'POSE':
+ l = args["pose_location"].strip(')(').split(', ')
+ amb.pose_location.x = float(l[0])
+ amb.pose_location.y = float(l[1])
+ amb.pose_location.z = float(l[2])
+ l = args["pose_rotation"].strip(')(').split(', ')
+ amb.pose_rotation.x = float(l[0])
+ amb.pose_rotation.y = float(l[1])
+ amb.pose_rotation.z = float(l[2])
+
+
+def actionconfig_export_as_data(ac, filepath, *, all_actionmaps=True, sort=False):
+ export_actionmaps = []
+
+ for am in ac.actionmaps:
+ if all_actionmaps or am.is_user_modified:
+ export_actionmaps.append(am)
+
+ if sort:
+ export_actionmaps.sort(key=lambda k: k.name)
+
+ with open(filepath, "w", encoding="utf-8") as fh:
+ fw = fh.write
+
+ # Use the file version since it includes the sub-version
+ # which we can bump multiple times between releases.
+ from bpy.app import version_file
+ fw(f"actionconfig_version = {version_file!r}\n")
+ del version_file
+
+ fw("actionconfig_data = \\\n[")
+
+ for am in export_actionmaps:
+ fw("(")
+ fw(f"\"{am.name:s}\",\n")
+
+ fw(f"{indent(2)}" "{")
+ fw(f"\"items\":\n")
+ fw(f"{indent(3)}[")
+ for ami in am.actionmap_items:
+ fw(f"(")
+ fw(f"\"{ami.name:s}\"")
+ ami_args = ami_args_as_data(ami)
+ ami_data = _ami_attrs_or_none(4, ami)
+ if ami_data is None:
+ fw(f", ")
+ else:
+ fw(",\n" f"{indent(5)}")
+
+ fw(ami_args)
+ if ami_data is None:
+ fw(", None,\n")
+ else:
+ fw(",\n")
+ fw(f"{indent(5)}" "{")
+ fw(ami_data)
+ fw(f"{indent(6)}")
+ fw("}," f"{indent(5)}")
+ fw("\n")
+
+ fw(f"{indent(5)}" "{")
+ fw(f"\"bindings\":\n")
+ fw(f"{indent(6)}[")
+ for amb in ami.bindings:
+ fw(f"(")
+ fw(f"\"{amb.name:s}\"")
+ fw(f", ")
+ amb_args = amb_args_as_data(amb, ami.type)
+ fw(amb_args)
+ fw("),\n" f"{indent(7)}")
+ fw("],\n" f"{indent(6)}")
+ fw("},\n" f"{indent(5)}")
+ fw("),\n" f"{indent(4)}")
+
+ fw("],\n" f"{indent(3)}")
+ fw("},\n" f"{indent(2)}")
+ fw("),\n" f"{indent(1)}")
+
+ fw("]\n")
+ fw("\n\n")
+ fw("if __name__ == \"__main__\":\n")
+
+ # We could remove this in the future, as loading new action-maps in older Blender versions
+ # makes less and less sense as Blender changes.
+ fw(" # Only add keywords that are supported.\n")
+ fw(" from bpy.app import version as blender_version\n")
+ fw(" keywords = {}\n")
+ fw(" if blender_version >= (3, 0, 0):\n")
+ fw(" keywords[\"actionconfig_version\"] = actionconfig_version\n")
+
+ fw(" import os\n")
+ fw(" from viewport_vr_preview.io import actionconfig_import_from_data\n")
+ fw(" actionconfig_import_from_data(\n")
+ fw(" os.path.splitext(os.path.basename(__file__))[0],\n")
+ fw(" actionconfig_data,\n")
+ fw(" **keywords,\n")
+ fw(" )\n")
+
+
+# -----------------------------------------------------------------------------
+# Import Functions
+
+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:
+ _ami_props_setattr(ami_subprop, subattr, subvalue)
+ return
+
+ try:
+ setattr(ami_props, attr, value)
+ except AttributeError:
+ print(f"Warning: property '{attr}' not found in actionmap item '{ami_name}'")
+ except Exception as ex:
+ print(f"Warning: {ex!r}")
+
+
+def actionmap_item_init_from_data(ami, ami_bindings):
+ new_fn = getattr(ami.bindings, "new")
+ for (amb_name, amb_args) in ami_bindings:
+ amb = new_fn(amb_name, True)
+ amb_data_from_args(amb, amb_args, ami.type)
+
+
+def actionmap_init_from_data(am, am_items):
+ new_fn = getattr(am.actionmap_items, "new")
+ for (ami_name, ami_args, ami_data, ami_content) in am_items:
+ ami = new_fn(ami_name, True)
+ ami_data_from_args(ami, ami_args)
+ if ami_data is not None:
+ ami_props_data = ami_data.get("op_properties", None)
+ if ami_props_data is not None:
+ ami_props = ami.op_properties
+ assert type(ami_props_data) is list
+ for attr, value in ami_props_data:
+ _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)
+
+
+def actionconfig_init_from_data(ac, actionconfig_data, actionconfig_version):
+ # Load data in the format defined above.
+ #
+ # Runs at load time, keep this fast!
+ if actionconfig_version is not None:
+ from .versioning import actionconfig_update
+ actionconfig_data = actionconfig_update(actionconfig_data, actionconfig_version)
+
+ for (am_name, am_content) in actionconfig_data:
+ am = ac.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.
+ #
+ # For full actionmaps, ensure these are always lists to allow for extending them
+ # in a generic way that doesn't have to check for the type each time.
+ assert type(am_items) is list
+ actionmap_init_from_data(am, am_items)
+
+
+def actionconfig_import_from_data(name, actionconfig_data, *, actionconfig_version=(0, 0, 0)):
+ # Load data in the format defined above.
+ #
+ # Runs at load time, keep this fast!
+ import bpy
+ ac = bpy.context.window_manager.xr_session_settings.actionconfigs.new(name)
+ actionconfig_init_from_data(ac, actionconfig_data, actionconfig_version)
+ return ac
diff --git a/viewport_vr_preview/configs/default.py b/viewport_vr_preview/configs/default.py
new file mode 100644
index 00000000..581966b5
--- /dev/null
+++ b/viewport_vr_preview/configs/default.py
@@ -0,0 +1,534 @@
+actionconfig_version = (3, 0, 20)
+actionconfig_data = \
+[("blender_default",
+ {"items":
+ [("controller_grip", {"type": 'POSE', "user_path0": '/user/hand/left', "user_path1": '/user/hand/right', "pose_is_controller_grip": 'True', "pose_is_controller_aim": 'False'}, None,
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/grip/pose', "component_path1": '/input/grip/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ],
+ },
+ ),
+ ("controller_aim", {"type": 'POSE', "user_path0": '/user/hand/left', "user_path1": '/user/hand/right', "pose_is_controller_grip": 'False', "pose_is_controller_aim": 'True'}, None,
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/aim/pose', "component_path1": '/input/aim/pose', "pose_location": '(0.0, 0.0, 0.0)', "pose_rotation": '(0.0, 0.0, 0.0)'}),
+ ],
+ },
+ ),
+ ("teleport",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_teleport', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("interpolation", 0.9),
+ ("color", (0.0, 1.0, 1.0, 1.0)),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/input/select/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("nav_grab",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '/user/hand/right', "op": 'wm.xr_navigation_grab', "op_mode": 'MODAL', "bimanual": 'True', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("lock_rotation", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/squeeze/click', "component_path1": '/input/squeeze/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/back/click', "component_path1": '/input/back/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/squeeze/value', "component_path1": '/input/squeeze/value', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/squeeze/value', "component_path1": '/input/squeeze/value', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/squeeze/value', "component_path1": '/input/squeeze/value', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/squeeze/click', "component_path1": '/input/squeeze/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/squeeze/click', "component_path1": '/input/squeeze/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("fly_forward",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_FORWARD'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_back",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_BACK'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_left",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_LEFT'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_right",
+ {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_RIGHT'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_up",
+ {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'UP'),
+ ("speed_min", 0.014),
+ ("speed_max", 0.042),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_down",
+ {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'DOWN'),
+ ("speed_min", 0.014),
+ ("speed_max", 0.042),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_turnleft",
+ {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'TURNLEFT'),
+ ("speed_min", 0.01),
+ ("speed_max", 0.03),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_turnright",
+ {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'TURNRIGHT'),
+ ("speed_min", 0.01),
+ ("speed_max", 0.03),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trackpad/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("nav_reset",
+ {"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),
+ ("scale", True),
+ ],
+ },
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/thumbstick/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'}),
+ ("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/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'}),
+ ("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'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/thumbstick/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("raycast_select", {"type": 'FLOAT', "user_path0": '/user/hand/right', "user_path1": '', "op": 'wm.xr_select_raycast', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'}, None,
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/input/select/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/trigger/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("grab", {"type": 'FLOAT', "user_path0": '/user/hand/left', "user_path1": '/user/hand/right', "op": 'wm.xr_transform_grab', "op_mode": 'MODAL', "bimanual": 'True', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'}, None,
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/input/x/click', "component_path1": '/input/a/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/input/home/click', "component_path1": '/input/home/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/input/a/click', "component_path1": '/input/a/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/input/x/click', "component_path1": '/input/a/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/input/x/click', "component_path1": '/input/a/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/input/menu/click', "component_path1": '/input/menu/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/input/menu/click', "component_path1": '/input/menu/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/input/menu/click', "component_path1": '/input/menu/click', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("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'}),
+ ],
+ },
+ ),
+ ("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'}),
+ ],
+ },
+ ),
+ ("haptic", {"type": 'VIBRATION', "user_path0": '/user/hand/left', "user_path1": '/user/hand/right'}, None,
+ {"bindings":
+ [("cosmos", {"profile": '/interaction_profiles/htc/vive_cosmos_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("huawei", {"profile": '/interaction_profiles/huawei/controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("index", {"profile": '/interaction_profiles/valve/index_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("oculus", {"profile": '/interaction_profiles/oculus/touch_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("reverb_g2", {"profile": '/interaction_profiles/hp/mixed_reality_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("simple", {"profile": '/interaction_profiles/khr/simple_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("vive", {"profile": '/interaction_profiles/htc/vive_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ("wmr", {"profile": '/interaction_profiles/microsoft/motion_controller', "component_path0": '/output/haptic', "component_path1": '/output/haptic'}),
+ ],
+ },
+ ),
+ ],
+ },
+ ),
+ ("blender_default_gamepad",
+ {"items":
+ [("teleport",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_teleport', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("interpolation", 0.9),
+ ("from_viewer", True),
+ ("color", (0.0, 1.0, 1.0, 1.0)),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/trigger_left/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("fly", {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/a/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("fly_forward",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_FORWARD'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_left/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_back",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_BACK'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_left/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_left",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_LEFT'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_left/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_right",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'VIEWER_RIGHT'),
+ ("lock_location_z", True),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_left/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_up",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'UP'),
+ ("speed_min", 0.014),
+ ("speed_max", 0.042),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_right/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("fly_down",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'DOWN'),
+ ("speed_min", 0.014),
+ ("speed_max", 0.042),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_right/y', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_turnleft",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'TURNLEFT'),
+ ("speed_min", 0.01),
+ ("speed_max", 0.03),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_right/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'NEGATIVE'}),
+ ],
+ },
+ ),
+ ("fly_turnright",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_fly', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("mode", 'TURNRIGHT'),
+ ("speed_min", 0.01),
+ ("speed_max", 0.03),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/thumbstick_right/x', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'POSITIVE'}),
+ ],
+ },
+ ),
+ ("nav_reset",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_navigation_reset', "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":
+ [("location", False),
+ ("rotation", False),
+ ("scale", True),
+ ],
+ },
+ {"bindings":
+ [("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_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_right/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("raycast_select",
+ {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'wm.xr_select_raycast', "op_mode": 'MODAL', "bimanual": 'False', "haptic_name": '', "haptic_match_user_paths": 'False', "haptic_duration": '0.0', "haptic_frequency": '0.0', "haptic_amplitude": '0.0', "haptic_mode": 'PRESS'},
+ {"op_properties":
+ [("from_viewer", True),
+ ],
+ },
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/trigger_right/value', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("undo", {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'ed.undo', "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'}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/x/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("redo", {"type": 'FLOAT', "user_path0": '/user/gamepad', "user_path1": '', "op": 'ed.redo', "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'}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/input/b/click', "component_path1": '', "threshold": '0.30000001192092896', "axis_region": 'ANY'}),
+ ],
+ },
+ ),
+ ("haptic_left", {"type": 'VIBRATION', "user_path0": '/user/gamepad', "user_path1": ''}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/output/haptic_left', "component_path1": ''}),
+ ],
+ },
+ ),
+ ("haptic_right", {"type": 'VIBRATION', "user_path0": '/user/gamepad', "user_path1": ''}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/output/haptic_right', "component_path1": ''}),
+ ],
+ },
+ ),
+ ("haptic_lefttrigger", {"type": 'VIBRATION', "user_path0": '/user/gamepad', "user_path1": ''}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/output/haptic_left_trigger', "component_path1": ''}),
+ ],
+ },
+ ),
+ ("haptic_righttrigger", {"type": 'VIBRATION', "user_path0": '/user/gamepad', "user_path1": ''}, None,
+ {"bindings":
+ [("gamepad", {"profile": '/interaction_profiles/microsoft/xbox_controller', "component_path0": '/output/haptic_right_trigger', "component_path1": ''}),
+ ],
+ },
+ ),
+ ],
+ },
+ ),
+ ]
+
+
+if __name__ == "__main__":
+ # Only add keywords that are supported.
+ from bpy.app import version as blender_version
+ keywords = {}
+ if blender_version >= (3, 0, 0):
+ keywords["actionconfig_version"] = actionconfig_version
+ import os
+ from viewport_vr_preview.io import actionconfig_import_from_data
+ actionconfig_import_from_data(
+ os.path.splitext(os.path.basename(__file__))[0],
+ actionconfig_data,
+ **keywords,
+ )
diff --git a/viewport_vr_preview/defaults.py b/viewport_vr_preview/defaults.py
new file mode 100644
index 00000000..0c3d5bfb
--- /dev/null
+++ b/viewport_vr_preview/defaults.py
@@ -0,0 +1,1979 @@
+# ##### 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)
+else:
+ from . import action_map
+
+import bpy
+from bpy.app.handlers import persistent
+from enum import Enum
+import math
+import os.path
+
+
+# Default action maps.
+class VRDefaultActionmaps(Enum):
+ DEFAULT = "blender_default"
+ GAMEPAD = "blender_default_gamepad"
+
+
+# Default actions.
+class VRDefaultActions(Enum):
+ CONTROLLER_GRIP = "controller_grip"
+ CONTROLLER_AIM = "controller_aim"
+ TELEPORT = "teleport"
+ NAV_GRAB = "nav_grab"
+ FLY = "fly"
+ FLY_FORWARD = "fly_forward"
+ FLY_BACK = "fly_back"
+ FLY_LEFT = "fly_left"
+ FLY_RIGHT = "fly_right"
+ FLY_UP = "fly_up"
+ FLY_DOWN = "fly_down"
+ 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"
+ UNDO = "undo"
+ REDO = "redo"
+ HAPTIC = "haptic"
+ HAPTIC_LEFT = "haptic_left"
+ HAPTIC_RIGHT = "haptic_right"
+ HAPTIC_LEFTTRIGGER = "haptic_lefttrigger"
+ HAPTIC_RIGHTTRIGGER = "haptic_righttrigger"
+
+
+# Default action bindings.
+class VRDefaultActionbindings(Enum):
+ COSMOS = "cosmos"
+ GAMEPAD = "gamepad"
+ HUAWEI = "huawei"
+ INDEX = "index"
+ OCULUS = "oculus"
+ REVERB_G2 = "reverb_g2"
+ SIMPLE = "simple"
+ VIVE = "vive"
+ WMR = "wmr"
+
+
+class VRDefaultActionprofiles(Enum):
+ COSMOS = "/interaction_profiles/htc/vive_cosmos_controller"
+ GAMEPAD = "/interaction_profiles/microsoft/xbox_controller"
+ HUAWEI = "/interaction_profiles/huawei/controller"
+ INDEX = "/interaction_profiles/valve/index_controller"
+ OCULUS = "/interaction_profiles/oculus/touch_controller"
+ REVERB_G2 = "/interaction_profiles/hp/mixed_reality_controller"
+ SIMPLE = "/interaction_profiles/khr/simple_controller"
+ VIVE = "/interaction_profiles/htc/vive_controller"
+ WMR = "/interaction_profiles/microsoft/motion_controller"
+
+
+def vr_defaults_actionmap_add(ac, name):
+ am = ac.actionmaps.new(name, True)
+
+ return am
+
+
+def vr_defaults_action_add(am,
+ name,
+ user_path0,
+ user_path1,
+ op,
+ op_mode,
+ bimanual,
+ haptic_name,
+ haptic_match_user_paths,
+ haptic_duration,
+ haptic_frequency,
+ haptic_amplitude,
+ haptic_mode):
+
+
+ ami = am.actionmap_items.new(name, True)
+ if ami:
+ ami.type = 'FLOAT'
+ ami.user_path0 = user_path0
+ ami.user_path1 = user_path1
+ ami.op = op
+ ami.op_mode = op_mode
+ ami.bimanual = bimanual
+ ami.haptic_name = haptic_name
+ ami.haptic_match_user_paths = haptic_match_user_paths
+ ami.haptic_duration = haptic_duration
+ ami.haptic_frequency = haptic_frequency
+ ami.haptic_amplitude = haptic_amplitude
+ ami.haptic_mode = haptic_mode
+
+ return ami
+
+
+def vr_defaults_pose_action_add(am,
+ name,
+ user_path0,
+ user_path1,
+ is_controller_grip,
+ is_controller_aim):
+ ami = am.actionmap_items.new(name, True)
+ if ami:
+ ami.type = 'POSE'
+ ami.user_path0 = user_path0
+ ami.user_path1 = user_path1
+ ami.pose_is_controller_grip = is_controller_grip
+ ami.pose_is_controller_aim = is_controller_aim
+
+ return ami
+
+
+def vr_defaults_haptic_action_add(am,
+ name,
+ user_path0,
+ user_path1):
+ ami = am.actionmap_items.new(name, True)
+ if ami:
+ ami.type = 'VIBRATION'
+ ami.user_path0 = user_path0
+ ami.user_path1 = user_path1
+
+ return ami
+
+
+def vr_defaults_actionbinding_add(ami,
+ name,
+ profile,
+ component_path0,
+ component_path1,
+ threshold,
+ axis0_region,
+ axis1_region):
+ amb = ami.bindings.new(name, True)
+ if amb:
+ amb.profile = profile
+ amb.component_path0 = component_path0
+ amb.component_path1 = component_path1
+ amb.threshold = threshold
+ amb.axis0_region = axis0_region
+ amb.axis1_region = axis1_region
+
+ return amb
+
+
+def vr_defaults_pose_actionbinding_add(ami,
+ name,
+ profile,
+ component_path0,
+ component_path1,
+ location,
+ rotation):
+ amb = ami.bindings.new(name, True)
+ if amb:
+ amb.profile = profile
+ amb.component_path0 = component_path0
+ amb.component_path1 = component_path1
+ amb.pose_location = location
+ amb.pose_rotation = rotation
+
+ return amb
+
+
+def vr_defaults_haptic_actionbinding_add(ami,
+ name,
+ profile,
+ component_path0,
+ component_path1):
+ amb = ami.bindings.new(name, True)
+ if amb:
+ amb.profile = profile
+ amb.component_path0 = component_path0
+ amb.component_path1 = component_path1
+
+
+ return amb
+
+
+def vr_defaults_create_default(ac):
+ am = vr_defaults_actionmap_add(ac,
+ VRDefaultActionmaps.DEFAULT.value)
+ if not am:
+ return
+
+ ami = vr_defaults_pose_action_add(am,
+ VRDefaultActions.CONTROLLER_GRIP.value,
+ "/user/hand/left",
+ "/user/hand/right",
+ True,
+ False)
+ if ami:
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/grip/pose",
+ "/input/grip/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+
+ ami = vr_defaults_pose_action_add(am,
+ VRDefaultActions.CONTROLLER_AIM.value,
+ "/user/hand/left",
+ "/user/hand/right",
+ False,
+ True)
+ if ami:
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+ vr_defaults_pose_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/aim/pose",
+ "/input/aim/pose",
+ (0, 0, 0),
+ (0, 0, 0))
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.TELEPORT.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_teleport",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/input/select/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.NAV_GRAB.value,
+ "/user/hand/left",
+ "/user/hand/right",
+ "wm.xr_navigation_grab",
+ 'MODAL',
+ True,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/squeeze/click",
+ "/input/squeeze/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/back/click",
+ "/input/back/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/squeeze/value",
+ "/input/squeeze/value",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/squeeze/value",
+ "/input/squeeze/value",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/squeeze/value",
+ "/input/squeeze/value",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/squeeze/click",
+ "/input/squeeze/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/squeeze/click",
+ "/input/squeeze/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_FORWARD.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_BACK.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_LEFT.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_RIGHT.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_UP.value,
+ "/user/hand/right",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_DOWN.value,
+ "/user/hand/right",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_TURNLEFT.value,
+ "/user/hand/right",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_TURNRIGHT.value,
+ "/user/hand/right",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trackpad/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.NAV_RESET.value,
+ "/user/hand/left",
+ "",
+ "wm.xr_navigation_reset",
+ 'PRESS',
+ False,
+ "haptic",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.TOGGLE_MATVIEW.value,
+ "/user/hand/right",
+ "",
+ "view3d.toggle_shading",
+ 'PRESS',
+ False,
+ "haptic",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/thumbstick/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.RAYCAST_SELECT.value,
+ "/user/hand/right",
+ "",
+ "wm.xr_select_raycast",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/input/select/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/trigger/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.GRAB.value,
+ "/user/hand/left",
+ "/user/hand/right",
+ "wm.xr_transform_grab",
+ 'MODAL',
+ True,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/x/click",
+ "/input/a/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/input/home/click",
+ "/input/home/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/input/a/click",
+ "/input/a/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/x/click",
+ "/input/a/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/x/click",
+ "/input/a/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/input/menu/click",
+ "/input/menu/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/input/menu/click",
+ "/input/menu/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/input/menu/click",
+ "/input/menu/click",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.UNDO.value,
+ "/user/hand/left",
+ "",
+ "ed.undo",
+ 'PRESS',
+ False,
+ "haptic",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/y/click",
+ "",
+ 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,
+ "/input/b/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/y/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/y/click",
+ "",
+ 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,
+ "/input/trackpad/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.REDO.value,
+ "/user/hand/right",
+ "",
+ "ed.redo",
+ 'PRESS',
+ False,
+ "haptic",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/input/b/click",
+ "",
+ 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,
+ "/input/b/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/input/b/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/input/b/click",
+ "",
+ 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,
+ "/input/trackpad/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_haptic_action_add(am,
+ VRDefaultActions.HAPTIC.value,
+ "/user/hand/left",
+ "/user/hand/right")
+ if ami:
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.COSMOS.value,
+ VRDefaultActionprofiles.COSMOS.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.HUAWEI.value,
+ VRDefaultActionprofiles.HUAWEI.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.INDEX.value,
+ VRDefaultActionprofiles.INDEX.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.OCULUS.value,
+ VRDefaultActionprofiles.OCULUS.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.REVERB_G2.value,
+ VRDefaultActionprofiles.REVERB_G2.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.SIMPLE.value,
+ VRDefaultActionprofiles.SIMPLE.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.VIVE.value,
+ VRDefaultActionprofiles.VIVE.value,
+ "/output/haptic",
+ "/output/haptic")
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.WMR.value,
+ VRDefaultActionprofiles.WMR.value,
+ "/output/haptic",
+ "/output/haptic")
+
+
+def vr_defaults_create_default_gamepad(ac):
+ am = vr_defaults_actionmap_add(ac,
+ VRDefaultActionmaps.GAMEPAD.value)
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.TELEPORT.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_teleport",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/trigger_left/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/a/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_FORWARD.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_left/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_BACK.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_left/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_LEFT.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_left/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_RIGHT.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_left/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_UP.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_right/y",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_DOWN.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_right/y",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_TURNLEFT.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_right/x",
+ "",
+ 0.3,
+ 'NEGATIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.FLY_TURNRIGHT.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_fly",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/thumbstick_right/x",
+ "",
+ 0.3,
+ 'POSITIVE',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.NAV_RESET.value,
+ "/user/gamepad",
+ "",
+ "wm.xr_navigation_reset",
+ '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/y/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.TOGGLE_SOLIDVIEW.value,
+ "/user/gamepad",
+ "",
+ "view3d.toggle_shading",
+ 'PRESS',
+ False,
+ "haptic_left",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/shoulder_left/click",
+ "",
+ 0.3,
+ '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",
+ "",
+ "wm.xr_select_raycast",
+ 'MODAL',
+ False,
+ "",
+ False,
+ 0.0,
+ 0.0,
+ 0.0,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/trigger_right/value",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.UNDO.value,
+ "/user/gamepad",
+ "",
+ "ed.undo",
+ 'PRESS',
+ False,
+ "haptic_left",
+ True,
+ 0.3,
+ 3000.0,
+ 0.5,
+ 'PRESS')
+ if ami:
+ vr_defaults_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/input/x/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami = vr_defaults_action_add(am,
+ VRDefaultActions.REDO.value,
+ "/user/gamepad",
+ "",
+ "ed.redo",
+ '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/b/click",
+ "",
+ 0.3,
+ 'ANY',
+ 'ANY')
+
+ ami =vr_defaults_haptic_action_add(am,
+ VRDefaultActions.HAPTIC_LEFT.value,
+ "/user/gamepad",
+ "")
+ if ami:
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/output/haptic_left",
+ "")
+
+ ami =vr_defaults_haptic_action_add(am,
+ VRDefaultActions.HAPTIC_RIGHT.value,
+ "/user/gamepad",
+ "")
+ if ami:
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/output/haptic_right",
+ "")
+
+ ami = vr_defaults_haptic_action_add(am,
+ VRDefaultActions.HAPTIC_LEFTTRIGGER.value,
+ "/user/gamepad",
+ "")
+ if ami:
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/output/haptic_left_trigger",
+ "")
+
+ ami = vr_defaults_haptic_action_add(am,
+ VRDefaultActions.HAPTIC_RIGHTTRIGGER.value,
+ "/user/gamepad",
+ "")
+ if ami:
+ vr_defaults_haptic_actionbinding_add(ami,
+ VRDefaultActionbindings.GAMEPAD.value,
+ VRDefaultActionprofiles.GAMEPAD.value,
+ "/output/haptic_right_trigger",
+ "")
+
+
+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
+
+ actionconfigs = context.window_manager.xr_session_settings.actionconfigs
+ if not actionconfigs:
+ return
+ ac = actionconfigs.default
+ if not ac:
+ return
+
+ # Set default config as active.
+ actionconfigs.active = ac
+
+ # Load default actionmaps.
+ filepath = vr_get_default_config_path()
+
+ 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)
+
+ 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)
diff --git a/viewport_vr_preview/gui.py b/viewport_vr_preview/gui.py
new file mode 100644
index 00000000..7cbeddc1
--- /dev/null
+++ b/viewport_vr_preview/gui.py
@@ -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
diff --git a/viewport_vr_preview/operators.py b/viewport_vr_preview/operators.py
new file mode 100644
index 00000000..d0145958
--- /dev/null
+++ b/viewport_vr_preview/operators.py
@@ -0,0 +1,1014 @@
+# ##### 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(defaults)
+ importlib.reload(properties)
+else:
+ from . import action_map, defaults, properties
+
+import bpy
+from bpy.types import (
+ Gizmo,
+ 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.
+class VIEW3D_OT_vr_landmark_add(Operator):
+ bl_idname = "view3d.vr_landmark_add"
+ bl_label = "Add VR Landmark"
+ bl_description = "Add a new VR landmark to the list and select it"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ scene = context.scene
+ landmarks = scene.vr_landmarks
+
+ landmarks.add()
+
+ # select newly created set
+ scene.vr_landmarks_selected = len(landmarks) - 1
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_vr_landmark_from_camera(Operator):
+ bl_idname = "view3d.vr_landmark_from_camera"
+ bl_label = "Add VR Landmark from Camera"
+ bl_description = "Add a new VR landmark from the active camera object to the list and select it"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ cam_selected = False
+
+ vl_objects = bpy.context.view_layer.objects
+ if vl_objects.active and vl_objects.active.type == 'CAMERA':
+ cam_selected = True
+ return cam_selected
+
+ def execute(self, context):
+ scene = context.scene
+ landmarks = scene.vr_landmarks
+ cam = context.view_layer.objects.active
+ lm = landmarks.add()
+ lm.type = 'OBJECT'
+ lm.base_pose_object = cam
+ lm.name = "LM_" + cam.name
+
+ # select newly created set
+ scene.vr_landmarks_selected = len(landmarks) - 1
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_vr_landmark_from_session(Operator):
+ bl_idname = "view3d.vr_landmark_from_session"
+ bl_label = "Add VR Landmark from Session"
+ bl_description = "Add VR landmark from the viewer pose of the running VR session to the list and select it"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ return bpy.types.XrSessionState.is_running(context)
+
+ def execute(self, context):
+ scene = context.scene
+ landmarks = scene.vr_landmarks
+ wm = context.window_manager
+
+ lm = landmarks.add()
+ lm.type = "CUSTOM"
+ scene.vr_landmarks_selected = len(landmarks) - 1
+
+ loc = wm.xr_session_state.viewer_pose_location
+ rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
+
+ lm.base_pose_location = loc
+ lm.base_pose_angle = rot[2]
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_update_vr_landmark(Operator):
+ bl_idname = "view3d.update_vr_landmark"
+ bl_label = "Update Custom VR Landmark"
+ bl_description = "Update the selected landmark from the current viewer pose in the VR session"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ selected_landmark = properties.VRLandmark.get_selected_landmark(context)
+ return bpy.types.XrSessionState.is_running(context) and selected_landmark.type == 'CUSTOM'
+
+ def execute(self, context):
+ wm = context.window_manager
+
+ lm = properties.VRLandmark.get_selected_landmark(context)
+
+ loc = wm.xr_session_state.viewer_pose_location
+ rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
+
+ lm.base_pose_location = loc
+ lm.base_pose_angle = rot
+
+ # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
+ vr_landmark_active_update(None, context)
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_vr_landmark_remove(Operator):
+ bl_idname = "view3d.vr_landmark_remove"
+ bl_label = "Remove VR Landmark"
+ bl_description = "Delete the selected VR landmark from the list"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ scene = context.scene
+ landmarks = scene.vr_landmarks
+
+ if len(landmarks) > 1:
+ landmark_selected_idx = scene.vr_landmarks_selected
+ landmarks.remove(landmark_selected_idx)
+
+ scene.vr_landmarks_selected -= 1
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_cursor_to_vr_landmark(Operator):
+ bl_idname = "view3d.cursor_to_vr_landmark"
+ bl_label = "Cursor to VR Landmark"
+ bl_description = "Move the 3D Cursor to the selected VR Landmark"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ lm = properties.VRLandmark.get_selected_landmark(context)
+ if lm.type == 'SCENE_CAMERA':
+ return context.scene.camera is not None
+ elif lm.type == 'OBJECT':
+ return lm.base_pose_object is not None
+
+ return True
+
+ def execute(self, context):
+ scene = context.scene
+ lm = properties.VRLandmark.get_selected_landmark(context)
+ if lm.type == 'SCENE_CAMERA':
+ lm_pos = scene.camera.location
+ elif lm.type == 'OBJECT':
+ lm_pos = lm.base_pose_object.location
+ else:
+ lm_pos = lm.base_pose_location
+ scene.cursor.location = lm_pos
+
+ return{'FINISHED'}
+
+
+class VIEW3D_OT_add_camera_from_vr_landmark(Operator):
+ bl_idname = "view3d.add_camera_from_vr_landmark"
+ bl_label = "New Camera from VR Landmark"
+ bl_description = "Create a new Camera from the selected VR Landmark"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ def execute(self, context):
+ scene = context.scene
+ lm = properties.VRLandmark.get_selected_landmark(context)
+
+ cam = bpy.data.cameras.new("Camera_" + lm.name)
+ new_cam = bpy.data.objects.new("Camera_" + lm.name, cam)
+ scene.collection.objects.link(new_cam)
+ angle = lm.base_pose_angle
+ new_cam.location = lm.base_pose_location
+ new_cam.rotation_euler = (math.pi, 0, angle)
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_camera_to_vr_landmark(Operator):
+ bl_idname = "view3d.camera_to_vr_landmark"
+ bl_label = "Scene Camera to VR Landmark"
+ bl_description = "Position the scene camera at the selected landmark"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ @classmethod
+ def poll(cls, context):
+ return context.scene.camera is not None
+
+ def execute(self, context):
+ scene = context.scene
+ lm = properties.VRLandmark.get_selected_landmark(context)
+
+ cam = scene.camera
+ angle = lm.base_pose_angle
+ cam.location = lm.base_pose_location
+ cam.rotation_euler = (math.pi / 2, 0, angle)
+
+ return {'FINISHED'}
+
+
+class VIEW3D_OT_vr_landmark_activate(Operator):
+ bl_idname = "view3d.vr_landmark_activate"
+ bl_label = "Activate VR Landmark"
+ bl_description = "Change to the selected VR landmark from the list"
+ bl_options = {'UNDO', 'REGISTER'}
+
+ index: bpy.props.IntProperty(
+ name="Index",
+ options={'HIDDEN'},
+ )
+
+ def execute(self, context):
+ scene = context.scene
+
+ if self.index >= len(scene.vr_landmarks):
+ return {'CANCELLED'}
+
+ scene.vr_landmarks_active = (
+ self.index if self.properties.is_property_set(
+ "index") else scene.vr_landmarks_selected
+ )
+
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = ac.actionmaps.new("actionmap", False)
+ if not am:
+ return {'CANCELLED'}
+
+ # Select newly created actionmap.
+ ac.selected_actionmap = len(ac.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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ if not am:
+ return {'CANCELLED'}
+
+ ac.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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac or (self.index >= len(ac.actionmaps)):
+ return {'CANCELLED'}
+
+ ac.active_actionmap = (
+ self.index if self.properties.is_property_set(
+ "index") else ac.selected_actionmap
+ )
+
+ session_state = context.window_manager.xr_session_state
+ if session_state:
+ am = action_map.vr_actionmap_active_get(ac)
+ if am:
+ session_state.active_action_set_set(context, am.name)
+
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ filepath = defaults.vr_get_default_config_path()
+
+ if not action_map.vr_load_actionmaps(context, 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):
+ filename, ext = os.path.splitext(self.filepath)
+ if (ext != ".py"):
+ return {'CANCELLED'}
+
+ if not action_map.vr_load_actionmaps(context, 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):
+ filename, ext = os.path.splitext(self.filepath)
+ if (ext != ".py"):
+ return {'CANCELLED'}
+
+ if not action_map.vr_save_actionmaps(context, 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ if not am:
+ return {'CANCELLED'}
+
+ # Copy actionmap.
+ am_new = ac.actionmaps.new_from_actionmap(am)
+ if not am_new:
+ return {'CANCELLED'}
+
+ # Select newly created actionmap.
+ ac.selected_actionmap = len(ac.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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ while ac.actionmaps:
+ ac.actionmaps.remove(ac.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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ if not am:
+ return {'CANCELLED'}
+
+ while am.actionmap_items:
+ am.actionmap_items.remove(am.actionmap_items[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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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):
+ ac = action_map.vr_actionconfig_active_get(context)
+ if not ac:
+ return {'CANCELLED'}
+
+ am = action_map.vr_actionmap_selected_get(ac)
+ 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'}
+
+
+### 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_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"
+
+ aspect = 1.0, 1.0
+
+ def draw(self, context):
+ if not hasattr(self, "frame_shape"):
+ aspect = self.aspect
+
+ frame_shape_verts = (
+ (-aspect[0], -aspect[1], -1.0),
+ (aspect[0], -aspect[1], -1.0),
+ (aspect[0], aspect[1], -1.0),
+ (-aspect[0], aspect[1], -1.0),
+ )
+ lines_shape_verts = (
+ (0.0, 0.0, 0.0),
+ frame_shape_verts[0],
+ (0.0, 0.0, 0.0),
+ frame_shape_verts[1],
+ (0.0, 0.0, 0.0),
+ frame_shape_verts[2],
+ (0.0, 0.0, 0.0),
+ frame_shape_verts[3],
+ )
+
+ self.frame_shape = self.new_custom_shape(
+ 'LINE_LOOP', frame_shape_verts)
+ self.lines_shape = self.new_custom_shape(
+ 'LINES', lines_shape_verts)
+
+ # Ensure correct GL state (otherwise other gizmos might mess that up)
+ bgl.glLineWidth(1)
+ bgl.glEnable(bgl.GL_BLEND)
+
+ self.draw_custom_shape(self.frame_shape)
+ self.draw_custom_shape(self.lines_shape)
+
+
+class VIEW3D_GT_vr_controller_grip(Gizmo):
+ bl_idname = "VIEW_3D_GT_vr_controller_grip"
+
+ def draw(self, context):
+ bgl.glLineWidth(1)
+ bgl.glEnable(bgl.GL_BLEND)
+
+ self.color = 0.422, 0.438, 0.446
+ self.draw_preset_circle(self.matrix_basis, axis='POS_X')
+ self.draw_preset_circle(self.matrix_basis, axis='POS_Y')
+ self.draw_preset_circle(self.matrix_basis, axis='POS_Z')
+
+
+class VIEW3D_GT_vr_controller_aim(Gizmo):
+ bl_idname = "VIEW_3D_GT_vr_controller_aim"
+
+ def draw(self, context):
+ bgl.glLineWidth(1)
+ bgl.glEnable(bgl.GL_BLEND)
+
+ self.color = 1.0, 0.2, 0.322
+ self.draw_preset_arrow(self.matrix_basis, axis='POS_X')
+ self.color = 0.545, 0.863, 0.0
+ self.draw_preset_arrow(self.matrix_basis, axis='POS_Y')
+ self.color = 0.157, 0.565, 1.0
+ self.draw_preset_arrow(self.matrix_basis, axis='POS_Z')
+
+
+class VIEW3D_GGT_vr_viewer_pose(GizmoGroup):
+ bl_idname = "VIEW3D_GGT_vr_viewer_pose"
+ bl_label = "VR Viewer Pose Indicator"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'WINDOW'
+ bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
+
+ @classmethod
+ def poll(cls, context):
+ view3d = context.space_data
+ return (
+ view3d.shading.vr_show_virtual_camera and
+ bpy.types.XrSessionState.is_running(context) and
+ not view3d.mirror_xr_session
+ )
+
+ @staticmethod
+ def _get_viewer_pose_matrix(context):
+ wm = context.window_manager
+
+ loc = wm.xr_session_state.viewer_pose_location
+ rot = wm.xr_session_state.viewer_pose_rotation
+
+ rotmat = Matrix.Identity(3)
+ rotmat.rotate(rot)
+ rotmat.resize_4x4()
+ transmat = Matrix.Translation(loc)
+
+ return transmat @ rotmat
+
+ def setup(self, context):
+ gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
+ gizmo.aspect = 1 / 3, 1 / 4
+
+ gizmo.color = gizmo.color_highlight = 0.2, 0.6, 1.0
+ gizmo.alpha = 1.0
+
+ self.gizmo = gizmo
+
+ def draw_prepare(self, context):
+ self.gizmo.matrix_basis = self._get_viewer_pose_matrix(context)
+
+
+class VIEW3D_GGT_vr_controller_poses(GizmoGroup):
+ bl_idname = "VIEW3D_GGT_vr_controller_poses"
+ bl_label = "VR Controller Poses Indicator"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'WINDOW'
+ bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
+
+ @classmethod
+ def poll(cls, context):
+ view3d = context.space_data
+ return (
+ view3d.shading.vr_show_controllers and
+ bpy.types.XrSessionState.is_running(context) and
+ not view3d.mirror_xr_session
+ )
+
+ @staticmethod
+ def _get_controller_pose_matrix(context, idx, is_grip, scale):
+ wm = context.window_manager
+
+ loc = None
+ rot = None
+ if is_grip:
+ loc = wm.xr_session_state.controller_grip_location_get(context, idx)
+ rot = wm.xr_session_state.controller_grip_rotation_get(context, idx)
+ else:
+ loc = wm.xr_session_state.controller_aim_location_get(context, idx)
+ rot = wm.xr_session_state.controller_aim_rotation_get(context, idx)
+
+ rotmat = Matrix.Identity(3)
+ rotmat.rotate(Quaternion(Vector(rot)))
+ rotmat.resize_4x4()
+ transmat = Matrix.Translation(loc)
+ scalemat = Matrix.Scale(scale, 4)
+
+ return transmat @ rotmat @ scalemat
+
+ def setup(self, context):
+ for idx in range(2):
+ self.gizmos.new(VIEW3D_GT_vr_controller_grip.bl_idname)
+ self.gizmos.new(VIEW3D_GT_vr_controller_aim.bl_idname)
+
+ for gizmo in self.gizmos:
+ gizmo.aspect = 1 / 3, 1 / 4
+ gizmo.color_highlight = 1.0, 1.0, 1.0
+ gizmo.alpha = 1.0
+
+ def draw_prepare(self, context):
+ grip_idx = 0
+ aim_idx = 0
+ idx = 0
+ scale = 1.0
+ for gizmo in self.gizmos:
+ is_grip = (gizmo.bl_idname == VIEW3D_GT_vr_controller_grip.bl_idname)
+ if (is_grip):
+ idx = grip_idx
+ grip_idx += 1
+ scale = 0.1
+ else:
+ idx = aim_idx
+ aim_idx += 1
+ scale = 0.5
+ gizmo.matrix_basis = self._get_controller_pose_matrix(context, idx, is_grip, scale)
+
+
+class VIEW3D_GGT_vr_landmarks(GizmoGroup):
+ bl_idname = "VIEW3D_GGT_vr_landmarks"
+ bl_label = "VR Landmark Indicators"
+ bl_space_type = 'VIEW_3D'
+ bl_region_type = 'WINDOW'
+ bl_options = {'3D', 'PERSISTENT', 'SCALE'}
+
+ @classmethod
+ def poll(cls, context):
+ view3d = context.space_data
+ return (
+ view3d.shading.vr_show_landmarks
+ )
+
+ def setup(self, context):
+ pass
+
+ def draw_prepare(self, context):
+ # first delete the old gizmos
+ for g in self.gizmos:
+ self.gizmos.remove(g)
+
+ scene = context.scene
+ landmarks = scene.vr_landmarks
+
+ for lm in landmarks:
+ if ((lm.type == 'SCENE_CAMERA' and not scene.camera) or
+ (lm.type == 'OBJECT' and not lm.base_pose_object)):
+ continue
+
+ gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
+ gizmo.aspect = 1 / 3, 1 / 4
+
+ gizmo.color = gizmo.color_highlight = 0.2, 1.0, 0.6
+ gizmo.alpha = 1.0
+
+ self.gizmo = gizmo
+
+ if lm.type == 'SCENE_CAMERA':
+ cam = scene.camera
+ lm_mat = cam.matrix_world if cam else Matrix.Identity(4)
+ elif lm.type == 'OBJECT':
+ lm_mat = lm.base_pose_object.matrix_world
+ else:
+ angle = lm.base_pose_angle
+ raw_rot = Euler((radians(90.0), 0, angle))
+
+ rotmat = Matrix.Identity(3)
+ rotmat.rotate(raw_rot)
+ rotmat.resize_4x4()
+
+ transmat = Matrix.Translation(lm.base_pose_location)
+
+ lm_mat = transmat @ rotmat
+
+ self.gizmo.matrix_basis = lm_mat
+
+
+classes = (
+ VIEW3D_OT_vr_landmark_add,
+ VIEW3D_OT_vr_landmark_remove,
+ VIEW3D_OT_vr_landmark_activate,
+ VIEW3D_OT_vr_landmark_from_session,
+ VIEW3D_OT_add_camera_from_vr_landmark,
+ VIEW3D_OT_camera_to_vr_landmark,
+ VIEW3D_OT_vr_landmark_from_camera,
+ 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_actionbinding_add,
+ VIEW3D_OT_vr_actionbinding_remove,
+ VIEW3D_OT_vr_actionbinding_copy,
+ VIEW3D_OT_vr_actionbindings_clear,
+
+ VIEW3D_OT_vr_mocap_object_add,
+ VIEW3D_OT_vr_mocap_object_remove,
+ VIEW3D_OT_vr_mocap_object_help,
+
+ VIEW3D_GT_vr_camera_cone,
+ VIEW3D_GT_vr_controller_grip,
+ VIEW3D_GT_vr_controller_aim,
+ VIEW3D_GGT_vr_viewer_pose,
+ VIEW3D_GGT_vr_controller_poses,
+ VIEW3D_GGT_vr_landmarks,
+)
+
+
+def register():
+ for cls in classes:
+ bpy.utils.register_class(cls)
+
+
+def unregister():
+ for cls in classes:
+ bpy.utils.unregister_class(cls)
diff --git a/viewport_vr_preview/properties.py b/viewport_vr_preview/properties.py
new file mode 100644
index 00000000..2f62fd51
--- /dev/null
+++ b/viewport_vr_preview/properties.py
@@ -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)
diff --git a/viewport_vr_preview/versioning.py b/viewport_vr_preview/versioning.py
new file mode 100644
index 00000000..8ee2755e
--- /dev/null
+++ b/viewport_vr_preview/versioning.py
@@ -0,0 +1,54 @@
+# ##### 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>
+
+# Update Blender version this action-map was written in:
+#
+# When the version is ``(0, 0, 0)``, the action-map being loaded didn't contain any versioning information.
+# This will older than ``(3, 0, 0)``.
+
+def actionconfig_update(actionconfig_data, actionconfig_version):
+ from bpy.app import version_file as blender_version
+ if actionconfig_version >= blender_version:
+ return actionconfig_data
+
+## # Version the action map.
+## import copy
+## has_copy = False
+##
+## if actionconfig_version <= (3, 0, 0):
+## # Only copy once.
+## if not has_copy:
+## actionconfig_data = copy.deepcopy(actionconfig_data)
+## has_copy = True
+##
+## for (am_name, am_content) in actionconfig_data:
+## # Apply action map updates.
+##
+## am_items = am_content["items"]
+##
+## for (ami_name, ami_args, ami_data, ami_content) in am_items
+## # Apply action map item updates.
+##
+## ami_bindings = ami_content["bindings"]
+##
+## for (amb_name, amb_args) in ami_bindings:
+## # Apply action map binding updates.
+
+ return actionconfig_data