[Bf-extensions-cvs] [636b4ca2] master: VR: New "VR Scene Inspection" Add-on

Julian Eisel noreply at git.blender.org
Tue Mar 17 21:43:40 CET 2020


Commit: 636b4ca23dbe1290c8954018fc94cbba54c786e1
Author: Julian Eisel
Date:   Tue Mar 17 20:51:00 2020 +0100
Branches: master
https://developer.blender.org/rBA636b4ca23dbe1290c8954018fc94cbba54c786e1

VR: New "VR Scene Inspection" Add-on

This add-on adds a basic UI for managing the new VR features to the sidebar, in
a new "VR" tab.

Features:
* Buttons to control general VR session settings (e.g. toggle session,
  positional tracking)
* Options for viewport clipping and overlay toggles
* Landmarks - VR base pose management:
** Each landmark can either follow the scene camera or use a custom camera.
** Differentiates between active and selected landmarks. That way landmark
   settings can be changed without changing the current reference pose.
** Stored per scene
* Virtual camera gizmo (non-interactive) to show the current VR viewer position
  and rotation in regular 3D Views
* Per 3D View feedback options:
** Virtual camera gizmo
** VR mirror (3D View follows VR view position and rotation)

Differential Revision: https://developer.blender.org/D7100

===================================================================

A	viewport_vr_preview.py

===================================================================

diff --git a/viewport_vr_preview.py b/viewport_vr_preview.py
new file mode 100644
index 00000000..1fc444f0
--- /dev/null
+++ b/viewport_vr_preview.py
@@ -0,0 +1,533 @@
+# ##### 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,
+)
+from bpy.props import (
+    CollectionProperty,
+    IntProperty,
+    BoolProperty,
+)
+from bpy.app.handlers import persistent
+
+bl_info = {
+    "name": "VR Scene Inspection",
+    "author": "Julian Eisel (Severin)",
+    "version": (0, 0, 7),
+    "blender": (2, 83, 8),
+    "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.",
+    "category": "3D View",
+}
+
+
+ at 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):
+    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)
+
+
+class VRLandmark(bpy.types.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 base poses work, but it's uncertain if they are really
+            # needed. Disabled for now.
+            # ('CUSTOM', "Custom Pose",
+            #  "Allow a manually definied 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(bpy.types.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 = 'SOLO_ON' if (index == landmark_active_idx) else 'SOLO_OFF'
+        props = layout.operator(
+            "view3d.vr_landmark_activate", text="", icon=icon)
+        props.index = index
+
+
+class VIEW3D_PT_vr_landmarks(bpy.types.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="")
+
+        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(bpy.types.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.
+
+        layout.prop(session_settings, "show_floor", text="Floor")
+        layout.prop(session_settings, "show_annotation", text="Annotations")
+
+        layout.separator()
+
+        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(bpy.types.Panel):
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'UI'
+    bl_category = "VR"
+    bl_label = "VR Session"
+
+    def draw(self, context):
+        layout = self.l

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list