[Bf-blender-cvs] [9dda65455b5] master: XR Controller Support Step 4: Controller Drawing

Peter Kim noreply at git.blender.org
Tue Oct 12 09:18:56 CEST 2021


Commit: 9dda65455b54336fe3efef91eba9e41866dac1c1
Author: Peter Kim
Date:   Tue Oct 12 16:18:05 2021 +0900
Branches: master
https://developer.blender.org/rB9dda65455b54336fe3efef91eba9e41866dac1c1

XR Controller Support Step 4: Controller Drawing

Addresses T77127 (Controller Drawing).

Adds VR controller visualization and custom drawing via draw
handlers. Add-ons can draw to the XR surface (headset display) and
mirror window by adding a View3D draw handler of region type 'XR' and
draw type 'POST_VIEW'.  Controller drawing and custom overlays can be
toggled individually as XR session options, which will be added in a
future update to the VR Scene Inspection add-on.

For the actual drawing, the OpenXR XR_MSFT_controller_model extension
is used to load a glTF model provided by the XR runtime. The model's
vertex data is then used to create a GPUBatch in the XR session
state. Finally, this batch is drawn via the XR surface draw handler
mentioned above.

For runtimes that do not support the controller model extension, a
a simple fallback shape (sphere) is drawn instead.

Reviewed By: Severin, fclem

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

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

M	intern/ghost/CMakeLists.txt
M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_Types.h
M	intern/ghost/intern/GHOST_C-api.cpp
M	intern/ghost/intern/GHOST_XrContext.cpp
A	intern/ghost/intern/GHOST_XrControllerModel.cpp
A	intern/ghost/intern/GHOST_XrControllerModel.h
M	intern/ghost/intern/GHOST_XrSession.cpp
M	intern/ghost/intern/GHOST_XrSession.h
M	source/blender/draw/intern/draw_manager.c
M	source/blender/editors/include/ED_space_api.h
M	source/blender/editors/include/ED_view3d_offscreen.h
M	source/blender/editors/space_api/spacetypes.c
M	source/blender/editors/space_view3d/space_view3d.c
M	source/blender/editors/space_view3d/view3d_draw.c
M	source/blender/makesdna/DNA_screen_types.h
M	source/blender/makesdna/DNA_view3d_enums.h
M	source/blender/makesdna/DNA_view3d_types.h
M	source/blender/makesdna/DNA_xr_types.h
M	source/blender/makesrna/intern/rna_screen.c
M	source/blender/makesrna/intern/rna_xr.c
M	source/blender/windowmanager/WM_api.h
M	source/blender/windowmanager/xr/intern/wm_xr_draw.c
M	source/blender/windowmanager/xr/intern/wm_xr_intern.h
M	source/blender/windowmanager/xr/intern/wm_xr_session.c

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

diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 76cac1049fb..05423209c71 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -473,6 +473,7 @@ if(WITH_XR_OPENXR)
     intern/GHOST_Xr.cpp
     intern/GHOST_XrAction.cpp
     intern/GHOST_XrContext.cpp
+    intern/GHOST_XrControllerModel.cpp
     intern/GHOST_XrEvent.cpp
     intern/GHOST_XrGraphicsBinding.cpp
     intern/GHOST_XrSession.cpp
@@ -482,13 +483,19 @@ if(WITH_XR_OPENXR)
     intern/GHOST_IXrGraphicsBinding.h
     intern/GHOST_XrAction.h
     intern/GHOST_XrContext.h
+    intern/GHOST_XrControllerModel.h
     intern/GHOST_XrException.h
     intern/GHOST_XrSession.h
     intern/GHOST_XrSwapchain.h
     intern/GHOST_Xr_intern.h
     intern/GHOST_Xr_openxr_includes.h
   )
+  list(APPEND INC
+    ../../extern/json/include
+    ../../extern/tinygltf
+  )
   list(APPEND INC_SYS
+    ${EIGEN3_INCLUDE_DIRS}
     ${XR_OPENXR_SDK_INCLUDE_DIR}
   )
   list(APPEND LIB
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index b78aac6f5eb..784febe8581 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -1140,6 +1140,30 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_context,
                                       const char *action_set_name,
                                       void **r_customdata_array);
 
+/* controller model */
+/**
+ * Load the OpenXR controller model.
+ */
+int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
+
+/**
+ * Unload the OpenXR controller model.
+ */
+void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_context, const char *subaction_path);
+
+/**
+ * Update component transforms for the OpenXR controller model.
+ */
+int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_context,
+                                            const char *subaction_path);
+
+/**
+ * Get vertex data for the OpenXR controller model.
+ */
+int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_context,
+                                   const char *subaction_path,
+                                   GHOST_XrControllerModelData *r_data);
+
 #endif /* WITH_XR_OPENXR */
 
 #ifdef __cplusplus
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 898ee451baf..2c8014a08cc 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -754,8 +754,31 @@ typedef struct GHOST_XrActionProfileInfo {
   const char *profile_path;
   uint32_t count_subaction_paths;
   const char **subaction_paths;
-  /* Bindings for each subaction path. */
+  /** Bindings for each subaction path. */
   const GHOST_XrActionBindingInfo *bindings;
 } GHOST_XrActionProfileInfo;
 
+typedef struct GHOST_XrControllerModelVertex {
+  float position[3];
+  float normal[3];
+} GHOST_XrControllerModelVertex;
+
+typedef struct GHOST_XrControllerModelComponent {
+  /** World space transform. */
+  float transform[4][4];
+  uint32_t vertex_offset;
+  uint32_t vertex_count;
+  uint32_t index_offset;
+  uint32_t index_count;
+} GHOST_XrControllerModelComponent;
+
+typedef struct GHOST_XrControllerModelData {
+  uint32_t count_vertices;
+  const GHOST_XrControllerModelVertex *vertices;
+  uint32_t count_indices;
+  const uint32_t *indices;
+  uint32_t count_components;
+  const GHOST_XrControllerModelComponent *components;
+} GHOST_XrControllerModelData;
+
 #endif /* WITH_XR_OPENXR */
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index a2871b46222..a21c3a90c06 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -1069,4 +1069,39 @@ void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_contexthandle,
                      xr_context);
 }
 
+int GHOST_XrLoadControllerModel(GHOST_XrContextHandle xr_contexthandle, const char *subaction_path)
+{
+  GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+  GHOST_XrSession *xr_session = xr_context->getSession();
+  GHOST_XR_CAPI_CALL_RET(xr_session->loadControllerModel(subaction_path), xr_context);
+  return 0;
+}
+
+void GHOST_XrUnloadControllerModel(GHOST_XrContextHandle xr_contexthandle,
+                                   const char *subaction_path)
+{
+  GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+  GHOST_XrSession *xr_session = xr_context->getSession();
+  GHOST_XR_CAPI_CALL(xr_session->unloadControllerModel(subaction_path), xr_context);
+}
+
+int GHOST_XrUpdateControllerModelComponents(GHOST_XrContextHandle xr_contexthandle,
+                                            const char *subaction_path)
+{
+  GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+  GHOST_XrSession *xr_session = xr_context->getSession();
+  GHOST_XR_CAPI_CALL_RET(xr_session->updateControllerModelComponents(subaction_path), xr_context);
+  return 0;
+}
+
+int GHOST_XrGetControllerModelData(GHOST_XrContextHandle xr_contexthandle,
+                                   const char *subaction_path,
+                                   GHOST_XrControllerModelData *r_data)
+{
+  GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+  GHOST_XrSession *xr_session = xr_context->getSession();
+  GHOST_XR_CAPI_CALL_RET(xr_session->getControllerModelData(subaction_path, *r_data), xr_context);
+  return 0;
+}
+
 #endif /* WITH_XR_OPENXR */
diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp
index fe8fec052fe..15b40690d83 100644
--- a/intern/ghost/intern/GHOST_XrContext.cpp
+++ b/intern/ghost/intern/GHOST_XrContext.cpp
@@ -412,11 +412,14 @@ void GHOST_XrContext::getExtensionsToEnable(
     try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
   }
 
-  /* Try enabling interaction profile extensions. */
+  /* Interaction profile extensions. */
   try_ext.push_back(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
   try_ext.push_back(XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
   try_ext.push_back(XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
 
+  /* Controller model extension. */
+  try_ext.push_back(XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME);
+
   /* Varjo quad view extension. */
   try_ext.push_back(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME);
 
diff --git a/intern/ghost/intern/GHOST_XrControllerModel.cpp b/intern/ghost/intern/GHOST_XrControllerModel.cpp
new file mode 100644
index 00000000000..ae15bf11aa0
--- /dev/null
+++ b/intern/ghost/intern/GHOST_XrControllerModel.cpp
@@ -0,0 +1,629 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include <cassert>
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include "GHOST_Types.h"
+#include "GHOST_XrException.h"
+#include "GHOST_Xr_intern.h"
+
+#include "GHOST_XrControllerModel.h"
+
+#define TINYGLTF_IMPLEMENTATION
+#define TINYGLTF_NO_STB_IMAGE
+#define TINYGLTF_NO_STB_IMAGE_WRITE
+#define STBIWDEF static inline
+#include "tiny_gltf.h"
+
+struct GHOST_XrControllerModelNode {
+  int32_t parent_idx = -1;
+  int32_t component_idx = -1;
+  float local_transform[4][4];
+};
+
+/* -------------------------------------------------------------------- */
+/** \name glTF Utilities
+ *
+ * Adapted from Microsoft OpenXR-Mixed Reality Samples (MIT License):
+ * https://github.com/microsoft/OpenXR-MixedReality
+ * \{ */
+
+struct GHOST_XrPrimitive {
+  std::vector<GHOST_XrControllerModelVertex> vertices;
+  std::vector<uint32_t> indices;
+};
+
+/**
+ * Validate that an accessor does not go out of bounds of the buffer view that it references and
+ * that the buffer view does not exceed the bounds of the buffer that it references
+ */
+static void validate_accessor(const tinygltf::Accessor &accessor,
+                              const tinygltf::BufferView &buffer_view,
+                              const tinygltf::Buffer &buffer,
+                              size_t byte_stride,
+                              size_t element_size)
+{
+  /* Make sure the accessor does not go out of range of the buffer view. */
+  if (accessor.byteOffset + (accessor.count - 1) * byte_stride + element_size >
+      buffer_view.byteLength) {
+    throw GHOST_XrException("glTF: Accessor goes out of range of bufferview.");
+  }
+
+  /* Make sure the buffer view does not go out of range of the buffer. */
+  if (buffer_view.byteOffset + buffer_view.byteLength > buffer.data.size()) {
+    throw GHOST_XrException("glTF: BufferView goes out of range of buffer.");
+  }
+}
+
+template<float (GHOST_XrControllerModelVertex::*field)[3]>
+static void read_vertices(const tinygltf::Accessor &accessor,
+                          const tinygltf::BufferView &buffer_view,
+                          const tinygltf::Buffer &buffer,
+                          GHOST_XrPrimitive &primitive)
+{
+  if (accessor.type != TINYGLTF_TYPE_VEC3) {
+    throw GHOST_XrException(
+        "glTF: Accessor for primitive attribute has incorrect type (VEC3 expected).");
+  }
+
+  if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
+    throw GHOST_XrException(
+        "glTF: Accessor for primitive attribute has incorrect component type (FLOAT expected).");
+  }
+
+  /* If stride is not specified, it is tightly packed. */
+  constexpr size_t packed_size = sizeof(float) * 3;
+  const size_t stride = buffer_view.byteStride == 0 ? packed_size : buffer_view.byteStride;
+  validate_accessor(accessor, buffer_view, buffer, stride, packed_size);
+
+  /* Resize the vertices vector, if necessary, to includ

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list