From ded3ababbaad4280bd4b924e6ce8521722a3a10b Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sat, 30 Dec 2023 03:00:09 -0500 Subject: [PATCH 1/4] ENH: Update build-system adding OpenXRRemoting external projects Adds SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT CMake option enabling the build of OpenXRRemoting and vtkRenderingOpenXRRemoting external projects. --- CMakeLists.txt | 40 ++++++ SuperBuild/External_OpenXRRemoting.cmake | 74 +++++++++++ .../External_vtkRenderingOpenXRRemoting.cmake | 118 ++++++++++++++++++ SuperBuildPrerequisites.cmake | 15 +++ 4 files changed, 247 insertions(+) create mode 100644 SuperBuild/External_OpenXRRemoting.cmake create mode 100644 SuperBuild/External_vtkRenderingOpenXRRemoting.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index cfdefbf..e6ad6fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,29 @@ message(STATUS "") message(STATUS "Setting SlicerVirtualReality_HAS_OPENXR_SUPPORT to ${SlicerVirtualReality_HAS_OPENXR_SUPPORT}${_reason}") message(STATUS "") +# OpenXRRemoting +set(_default OFF) +set(_reason) +if(NOT DEFINED SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + if(WIN32) + if(NOT SlicerVirtualReality_HAS_OPENXR_SUPPORT) + set(_default OFF) + set(_reason " (OpenXR support was disabled)") + else() + set(_default ON) + set(_reason " (OpenXRRemoting is supported on Windows)") + endif() + else() + set(_default OFF) + set(_reason " (OpenXRRemoting is not supported on this platform)") + endif() +endif() +option(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT "Build OpenXR Remoting support" ${_default}) +mark_as_superbuild(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) +message(STATUS "") +message(STATUS "Setting SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT to ${SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT}${_reason}") +message(STATUS "") + #----------------------------------------------------------------------------- # SuperBuild setup option(${EXTENSION_NAME}_SUPERBUILD "Build ${EXTENSION_NAME} and the projects it depends on." ON) @@ -101,6 +124,12 @@ if(SlicerVirtualReality_HAS_OPENXR_SUPPORT) set(vtkRenderingOpenXR_DIR \"${vtkRenderingOpenXR_DIR}\") find_package(vtkRenderingOpenXR REQUIRED) endif() + +set(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT ${SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT}) +if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + set(vtkRenderingOpenXRRemoting_DIR \"${vtkRenderingOpenXRRemoting_DIR}\") + find_package(vtkRenderingOpenXRRemoting REQUIRED) +endif() ################################################## ") include(${Slicer_EXTENSION_GENERATE_CONFIG}) @@ -165,11 +194,13 @@ endif() #----------------------------------------------------------------------------- set(EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS) +# vtkRenderingVR list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingVR_DIR};vtkRenderingVR;runtime;/") if(Slicer_USE_PYTHONQT) list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingVR_DIR};vtkRenderingVR;python;/") endif() +# vtkRenderingOpenVR if(SlicerVirtualReality_HAS_OPENVR_SUPPORT) list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingOpenVR_DIR};vtkRenderingOpenVR;runtime;/") if(Slicer_USE_PYTHONQT) @@ -177,6 +208,7 @@ if(SlicerVirtualReality_HAS_OPENVR_SUPPORT) endif() endif() +# vtkRenderingOpenXR if(SlicerVirtualReality_HAS_OPENXR_SUPPORT) list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingOpenXR_DIR};vtkRenderingOpenXR;runtime;/") if(Slicer_USE_PYTHONQT) @@ -184,6 +216,14 @@ if(SlicerVirtualReality_HAS_OPENXR_SUPPORT) endif() endif() +# vtkRenderingOpenXRRemoting +if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingOpenXRRemoting_DIR};vtkRenderingOpenXRRemoting;runtime;/") + if(Slicer_USE_PYTHONQT) + list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingOpenXRRemoting_DIR};vtkRenderingOpenXRRemoting;python;/") + endif() +endif() + set(${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS "${EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS}" CACHE STRING "List of external projects to install" FORCE) #----------------------------------------------------------------------------- diff --git a/SuperBuild/External_OpenXRRemoting.cmake b/SuperBuild/External_OpenXRRemoting.cmake new file mode 100644 index 0000000..2c064b2 --- /dev/null +++ b/SuperBuild/External_OpenXRRemoting.cmake @@ -0,0 +1,74 @@ + +set(proj OpenXRRemoting) + +set(${proj}_DEPENDENCIES "") + +# Include dependent projects if any +ExternalProject_Include_Dependencies(${proj} PROJECT_VAR proj DEPENDS_VAR ${proj}_DEPENDENCIES) + +if(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}) + message(FATAL_ERROR "Enabling ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj} is not supported !") +endif() + +# Sanity checks +if(DEFINED OpenXRRemoting_BIN_DIR AND NOT EXISTS ${OpenXRRemoting_BIN_DIR}) + message(FATAL_ERROR "OpenXRRemoting_BIN_DIR variable is defined but corresponds to nonexistent directory") +endif() +if(DEFINED OpenXRRemoting_INCLUDE_DIR AND NOT EXISTS ${OpenXRRemoting_INCLUDE_DIR}) + message(FATAL_ERROR "OpenXRRemoting_INCLUDE_DIR variable is defined but corresponds to nonexistent path") +endif() + +if((NOT OpenXRRemoting_BIN_DIR OR NOT OpenXRRemoting_INCLUDE_DIR) + AND NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}) + + set(EP_INSTALL_DIR ${CMAKE_BINARY_DIR}/${proj}-install) + + set(_ver "2.9.1") + set(_sha256 "e8174adaf64089a0cd7cc7e21445dbe8151b57b364312eab773e5c64d9dc28b1") + + ExternalProject_Add(${proj} + ${${proj}_EP_ARGS} + URL "https://www.nuget.org/api/v2/package/Microsoft.Holographic.Remoting.OpenXr/${_ver}" + URL_HASH "SHA256=${_sha256}" + SOURCE_DIR ${EP_INSTALL_DIR} + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + DEPENDS + ${${proj}_DEPENDENCIES} + ) + + set(OpenXRRemoting_BIN_DIR "${EP_INSTALL_DIR}/build/native/bin/x64/Desktop/") + set(OpenXRRemoting_INCLUDE_DIR "${EP_INSTALL_DIR}/build/native/include/openxr/") + + #----------------------------------------------------------------------------- + # Launcher setting specific to build tree + + # library paths + set(${proj}_LIBRARY_PATHS_LAUNCHER_BUILD + ${OpenXRRemoting_BIN_DIR} + ) + mark_as_superbuild( + VARS ${proj}_LIBRARY_PATHS_LAUNCHER_BUILD + LABELS "LIBRARY_PATHS_LAUNCHER_BUILD" + ) + + #----------------------------------------------------------------------------- + # Launcher setting specific to install tree + + # NA + +else() + ExternalProject_Add_Empty(${proj} DEPENDS ${${proj}_DEPENDS}) +endif() + +ExternalProject_Message(${proj} "OpenXRRemoting_BIN_DIR:${OpenXRRemoting_BIN_DIR}") +ExternalProject_Message(${proj} "OpenXRRemoting_INCLUDE_DIR:${OpenXRRemoting_INCLUDE_DIR}") + +mark_as_superbuild( + VARS + OpenXRRemoting_BIN_DIR:PATH + OpenXRRemoting_INCLUDE_DIR:PATH + ) + diff --git a/SuperBuild/External_vtkRenderingOpenXRRemoting.cmake b/SuperBuild/External_vtkRenderingOpenXRRemoting.cmake new file mode 100644 index 0000000..5d47085 --- /dev/null +++ b/SuperBuild/External_vtkRenderingOpenXRRemoting.cmake @@ -0,0 +1,118 @@ +#----------------------------------------------------------------------------- +# Build VTK Rendering OpenXRRemoting module, pointing it to Slicer's VTK and the vtkRenderingOpenXR +# module also built by this extension. + +set(proj vtkRenderingOpenXRRemoting) + +# Set dependency list +set(${proj}_DEPENDS + vtkRenderingOpenXR + OpenXRRemoting + ) + +# Include dependent projects if any +ExternalProject_Include_Dependencies(${proj} PROJECT_VAR proj) + +if(${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}) + message(FATAL_ERROR "Enabling ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj} is not supported !") +endif() + +# Sanity checks +if(DEFINED ${proj}_DIR AND NOT EXISTS ${${proj}_DIR}) + message(FATAL_ERROR "${proj}_DIR [${${proj}_DIR}] variable is defined but corresponds to nonexistent directory") +endif() + +if(NOT DEFINED ${proj}_DIR AND NOT ${SUPERBUILD_TOPLEVEL_PROJECT}_USE_SYSTEM_${proj}) + + set(EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS) + if(VTK_WRAP_PYTHON) + list(APPEND EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS + -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} + -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} + -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} + # Required by FindPython3 CMake module used by VTK + -DPython3_ROOT_DIR:PATH=${Python3_ROOT_DIR} + -DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} + -DPython3_LIBRARY:FILEPATH=${Python3_LIBRARY} + -DPython3_LIBRARY_DEBUG:FILEPATH=${Python3_LIBRARY_DEBUG} + -DPython3_LIBRARY_RELEASE:FILEPATH=${Python3_LIBRARY_RELEASE} + -DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} + ) + endif() + + if(NOT EXISTS ${VTKExternalModule_SOURCE_DIR}) + message(FATAL_ERROR "VTKExternalModule_SOURCE_DIR [${VTKExternalModule_SOURCE_DIR}] variable is set to a nonexistent directory") + endif() + + set(VTK_SOURCE_DIR ${VTK_DIR}/../VTK) + ExternalProject_Message(${proj} "VTK_SOURCE_DIR:${VTK_SOURCE_DIR}") + + set(_module_subdir Rendering/OpenXRRemoting) + set(_module_name RenderingOpenXRRemoting) + + set(EP_SOURCE_DIR ${VTK_SOURCE_DIR}/${_module_subdir}) + set(EP_BINARY_DIR ${CMAKE_BINARY_DIR}/${proj}-build) + + ExternalProject_Add(${proj} + ${${proj}_EP_ARGS} + DOWNLOAD_COMMAND "" + SOURCE_DIR ${VTKExternalModule_SOURCE_DIR} + BINARY_DIR ${EP_BINARY_DIR} + INSTALL_COMMAND "" + CMAKE_CACHE_ARGS + # VTKExternalModule + -DVTK_MODULE_NAME:STRING=${_module_name} + -DVTK_MODULE_SOURCE_DIR:PATH=${EP_SOURCE_DIR} + -DVTK_MODULE_CMAKE_MODULE_PATH:PATH=${VTK_SOURCE_DIR}/CMake + # vtkRenderingOpenXRRemoting + -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_FLAGS:STRING=${ep_common_cxx_flags} + -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} + -DCMAKE_C_FLAGS:STRING=${ep_common_c_flags} + -DBUILD_TESTING:BOOL=OFF + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${CMAKE_BINARY_DIR}/${Slicer_THIRDPARTY_BIN_DIR} + -DCMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${CMAKE_BINARY_DIR}/${Slicer_THIRDPARTY_LIB_DIR} + -DCMAKE_INSTALL_BINDIR:STRING=${Slicer_INSTALL_THIRDPARTY_BIN_DIR} + -DCMAKE_INSTALL_LIBDIR:STRING=${Slicer_INSTALL_THIRDPARTY_LIB_DIR} + -DCMAKE_MACOSX_RPATH:BOOL=0 + # Required to find VTK + -DVTK_DIR:PATH=${VTK_DIR} + # Required to find vtkRenderingOpenXRRemoting + -DvtkRenderingVR_DIR:PATH=${vtkRenderingVR_DIR} + -DvtkRenderingOpenXR_DIR:PATH=${vtkRenderingOpenXR_DIR} + # Required to find OpenXRRemoting + -DOpenXRRemoting_BIN_DIR:PATH=${OpenXRRemoting_BIN_DIR} + -DOpenXRRemoting_INCLUDE_DIR:PATH=${OpenXRRemoting_INCLUDE_DIR} + ${EXTERNAL_PROJECT_OPTIONAL_CMAKE_CACHE_ARGS} + DEPENDS + ${${proj}_DEPENDS} + ) + + ExternalProject_AlwaysConfigure(${proj}) + + set(${proj}_DIR ${EP_BINARY_DIR}) + + #----------------------------------------------------------------------------- + # Launcher setting specific to build tree + + # pythonpath + set(${proj}_PYTHONPATH_LAUNCHER_BUILD + ${${proj}_DIR}/${Slicer_INSTALL_THIRDPARTY_LIB_DIR}/${PYTHON_SITE_PACKAGES_SUBDIR}/vtkmodules + ) + mark_as_superbuild( + VARS ${proj}_PYTHONPATH_LAUNCHER_BUILD + LABELS "PYTHONPATH_LAUNCHER_BUILD" + ) + + #----------------------------------------------------------------------------- + # Launcher setting specific to install tree + + # NA + +else() + ExternalProject_Add_Empty(${proj} DEPENDS ${${proj}_DEPENDS}) +endif() + +mark_as_superbuild(VARS ${proj}_DIR:PATH) +ExternalProject_Message(${proj} "${proj}_DIR:${${proj}_DIR}") + diff --git a/SuperBuildPrerequisites.cmake b/SuperBuildPrerequisites.cmake index c3ed558..6ea8e5e 100644 --- a/SuperBuildPrerequisites.cmake +++ b/SuperBuildPrerequisites.cmake @@ -15,6 +15,9 @@ endif() if(NOT DEFINED SlicerVirtualReality_HAS_OPENXR_SUPPORT) message(FATAL_ERROR "SlicerVirtualReality_HAS_OPENXR_SUPPORT is not set") endif() +if(NOT DEFINED SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + message(FATAL_ERROR "SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT is not set") +endif() # Set list of dependencies to ensure the custom application bundling this # extension does NOT automatically collect the project list and attempt to @@ -48,6 +51,11 @@ else() vtkRenderingOpenXR ) endif() + if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + list(APPEND SlicerVirtualReality_EXTERNAL_PROJECT_DEPENDENCIES + vtkRenderingOpenXRRemoting + ) + endif() endif() message(STATUS "SlicerVirtualReality_EXTERNAL_PROJECT_DEPENDENCIES:${SlicerVirtualReality_EXTERNAL_PROJECT_DEPENDENCIES}") @@ -58,6 +66,7 @@ if(NOT DEFINED Slicer_SOURCE_DIR) # - vtkRenderingVR # - vtkRenderingOpenVR # - vtkRenderingOpenXR + # - vtkRenderingOpenXRRemoting include(${SlicerVirtualReality_SOURCE_DIR}/FetchVTKExternalModule.cmake) else() @@ -89,12 +98,18 @@ else() else() set(VTK_MODULE_ENABLE_VTK_RenderingOpenXR NO) endif() + if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + set(VTK_MODULE_ENABLE_VTK_RenderingOpenXRRemoting YES) + else() + set(VTK_MODULE_ENABLE_VTK_RenderingOpenXRRemoting NO) + endif() mark_as_superbuild( VARS VTK_MODULE_ENABLE_VTK_RenderingVR:STRING VTK_MODULE_ENABLE_VTK_RenderingOpenVR:STRING VTK_MODULE_ENABLE_VTK_RenderingOpenXR:STRING + VTK_MODULE_ENABLE_VTK_RenderingOpenXRRemoting:STRING PROJECTS VTK ) From 93344a848d510e926f3a1dfb1c4a61054396c8cf Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sat, 30 Dec 2023 06:06:31 -0500 Subject: [PATCH 2/4] ENH: Copy and install OpenXRRemoting libraries along side VTK libraries This requires VTK MR-10449 (see [1]) backported to Slicer/VTK through the Slicer PR-7190 (see [2]). [1] https://gitlab.kitware.com/vtk/vtk/-/merge_requests/10449 [2] Slicer/Slicer#7190 (cherry picked from commit KitwareMedical/SlicerMixedReality@5d5db0b67d9479c0f74909437b359ce0d55f9a1e) --- CMakeLists.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6ad6fb..935b4a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,34 @@ if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) if(Slicer_USE_PYTHONQT) list(APPEND EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS "${vtkRenderingOpenXRRemoting_DIR};vtkRenderingOpenXRRemoting;python;/") endif() + + # OpenXRRemoting: RemotingXR.json and companion files are copied or installed along side the + # vtkRenderingRemotingOpenXR library so that "vtkOpenXRManagerRemoteConnection::Initialize()" + # can locate the files and set the XR_RUNTIME_JSON env. variable + set(OpenXRRemoting_FILES ) + if(WIN32) + set(OpenXRRemoting_FILES + Microsoft.Holographic.AppRemoting.OpenXr.dll + Microsoft.Holographic.AppRemoting.OpenXr.SU.dll + PerceptionDevice.dll + RemotingXR.json + ) + endif() + set(_dest ${CMAKE_BINARY_DIR}/${Slicer_THIRDPARTY_BIN_DIR}) + foreach(file IN LISTS OpenXRRemoting_FILES) + # Copy + message(STATUS "Copying ${file} to ${_dest}") + file(COPY ${OpenXRRemoting_BIN_DIR}/${file} + DESTINATION ${_dest} + USE_SOURCE_PERMISSIONS + ) + # Install + install(FILES ${OpenXRRemoting_BIN_DIR}/${file} + DESTINATION ${Slicer_INSTALL_THIRDPARTY_LIB_DIR} + COMPONENT RuntimeLibraries + ) + endforeach() + endif() set(${EXTENSION_NAME}_CPACK_INSTALL_CMAKE_PROJECTS "${EXTENSION_CPACK_INSTALL_CMAKE_PROJECTS}" CACHE STRING "List of external projects to install" FORCE) From 9f02ed263ff64a09624e1ca8fa6c115c40d26fa0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Sun, 7 Jan 2024 18:29:59 -0500 Subject: [PATCH 3/4] ENH: Add OpenXR Remoting support This commit updates the view node by adding "Remoting" and "PlayerIPAddress" properties. The corresponding UI updates include a checkbox for toggling remoting and a `QLineEdit` for entering the IP address. The macro `SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT` is added to `vtkMRMLVirtualRealityConfigure.h.in` to conditionally include code specific to OpenXR remoting. The "Remoting" checkbox and "PlayerIPAddress" line edit are disabled if an active connection has been established. To fix OpenXRRemoting "wglDXRegisterObjectNV failed in RegisterSharedTexture()", the OpenXRRemoting HelperWindow MultiSamples property is explicitly set to 0. To ensure no background is displayed, the background alpha/color/gradient is explicitly set when remoting is used. The last "Remoting" and "PlayerIPAddress" properties associated with a successful hardware connection are saved to and restored from the settings. Co-authored-by: Lucas Gandel --- VirtualReality/CMakeLists.txt | 3 + VirtualReality/MRML/CMakeLists.txt | 5 ++ .../MRML/vtkMRMLVirtualRealityConfigure.h.in | 1 + .../MRML/vtkMRMLVirtualRealityViewNode.cxx | 12 ++++ .../MRML/vtkMRMLVirtualRealityViewNode.h | 17 +++++ .../UI/qSlicerVirtualRealityModuleWidget.ui | 34 +++++++++- .../Widgets/qMRMLVirtualRealityView.cxx | 68 +++++++++++++++++-- .../Widgets/qMRMLVirtualRealityView_p.h | 2 + .../qSlicerVirtualRealityModule.cxx | 10 +++ .../qSlicerVirtualRealityModuleWidget.cxx | 44 ++++++++++++ .../qSlicerVirtualRealityModuleWidget.h | 3 + 11 files changed, 190 insertions(+), 9 deletions(-) diff --git a/VirtualReality/CMakeLists.txt b/VirtualReality/CMakeLists.txt index f081228..9d5c261 100644 --- a/VirtualReality/CMakeLists.txt +++ b/VirtualReality/CMakeLists.txt @@ -13,6 +13,9 @@ endif() if(SlicerVirtualReality_HAS_OPENXR_SUPPORT) find_package(vtkRenderingOpenXR REQUIRED) endif() +if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + find_package(vtkRenderingOpenXRRemoting REQUIRED) +endif() #----------------------------------------------------------------------------- add_subdirectory(MRML) diff --git a/VirtualReality/MRML/CMakeLists.txt b/VirtualReality/MRML/CMakeLists.txt index 9f367f4..6fc9245 100644 --- a/VirtualReality/MRML/CMakeLists.txt +++ b/VirtualReality/MRML/CMakeLists.txt @@ -37,6 +37,11 @@ if(SlicerVirtualReality_HAS_OPENXR_SUPPORT) VTK::RenderingOpenXR ) endif() +if(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + list(APPEND ${KIT}_TARGET_LIBRARIES + VTK::RenderingOpenXRRemoting + ) +endif() #----------------------------------------------------------------------------- SlicerMacroBuildModuleMRML( diff --git a/VirtualReality/MRML/vtkMRMLVirtualRealityConfigure.h.in b/VirtualReality/MRML/vtkMRMLVirtualRealityConfigure.h.in index 3e41f7d..d3aa2ae 100644 --- a/VirtualReality/MRML/vtkMRMLVirtualRealityConfigure.h.in +++ b/VirtualReality/MRML/vtkMRMLVirtualRealityConfigure.h.in @@ -3,5 +3,6 @@ #cmakedefine SlicerVirtualReality_HAS_OPENVR_SUPPORT #cmakedefine SlicerVirtualReality_HAS_OPENXR_SUPPORT +#cmakedefine SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT #endif diff --git a/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.cxx b/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.cxx index 49dfcc3..510b667 100644 --- a/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.cxx +++ b/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.cxx @@ -83,6 +83,9 @@ void vtkMRMLVirtualRealityViewNode::WriteXML(ostream& of, int nIndent) vtkMRMLWriteXMLBooleanMacro(hmdTransformUpdate, HMDTransformUpdate); vtkMRMLWriteXMLBooleanMacro(controllerModelsVisible, ControllerModelsVisible); vtkMRMLWriteXMLBooleanMacro(lighthouseModelsVisible, LighthouseModelsVisible); + // OpenXRRemoting + vtkMRMLWriteXMLBooleanMacro(remoting, Remoting); + vtkMRMLWriteXMLStdStringMacro(playerIPAddress, PlayerIPAddress); vtkMRMLWriteXMLEndMacro(); } @@ -105,6 +108,9 @@ void vtkMRMLVirtualRealityViewNode::ReadXMLAttributes(const char** atts) vtkMRMLReadXMLBooleanMacro(hmdTransformUpdate, HMDTransformUpdate); vtkMRMLReadXMLBooleanMacro(controllerModelsVisible, ControllerModelsVisible); vtkMRMLReadXMLBooleanMacro(lighthouseModelsVisible, LighthouseModelsVisible); + // OpenXRRemoting + vtkMRMLReadXMLBooleanMacro(remoting, Remoting); + vtkMRMLReadXMLStdStringMacro(playerIPAddress, PlayerIPAddress); vtkMRMLReadXMLEndMacro(); this->EndModify(disabledModify); @@ -131,6 +137,9 @@ void vtkMRMLVirtualRealityViewNode::Copy(vtkMRMLNode* anode) vtkMRMLCopyBooleanMacro(HMDTransformUpdate); vtkMRMLCopyBooleanMacro(ControllerModelsVisible); vtkMRMLCopyBooleanMacro(LighthouseModelsVisible); + // OpenXRRemoting + vtkMRMLCopyBooleanMacro(Remoting); + vtkMRMLCopyStringMacro(PlayerIPAddress); vtkMRMLCopyEndMacro(); this->EndModify(disabledModify); @@ -153,6 +162,9 @@ void vtkMRMLVirtualRealityViewNode::PrintSelf(ostream& os, vtkIndent indent) vtkMRMLPrintBooleanMacro(HMDTransformUpdate); vtkMRMLPrintBooleanMacro(ControllerModelsVisible); vtkMRMLPrintBooleanMacro(LighthouseModelsVisible); + // OpenXRRemoting + vtkMRMLPrintBooleanMacro(Remoting); + vtkMRMLPrintStdStringMacro(PlayerIPAddress); vtkMRMLPrintEndMacro(); } diff --git a/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.h b/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.h index 261c9df..a313448 100644 --- a/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.h +++ b/VirtualReality/MRML/vtkMRMLVirtualRealityViewNode.h @@ -242,6 +242,19 @@ class VTK_SLICER_VIRTUALREALITY_MODULE_MRML_EXPORT vtkMRMLVirtualRealityViewNode static int GetXRRuntimeFromString(const char* name); ///@} + ///@{ + /// Get/Set if remoting is enabled. + vtkGetMacro(Remoting, bool); + vtkSetMacro(Remoting, bool); + vtkBooleanMacro(Remoting, bool); + ///@} + + ///@{ + /// OpenXR remoting IP address to connect to. + vtkSetMacro(PlayerIPAddress, const std::string); + vtkGetMacro(PlayerIPAddress, std::string); + ///@} + /// Return true if an error has occurred. /// "Connected" member requests connection but this method can tell if the /// hardware connection has been actually successfully established. @@ -273,6 +286,10 @@ class VTK_SLICER_VIRTUALREALITY_MODULE_MRML_EXPORT vtkMRMLVirtualRealityViewNode std::string LastErrorMessage; + // OpenXRRemoting + bool Remoting{false}; + std::string PlayerIPAddress; + vtkMRMLVirtualRealityViewNode(); ~vtkMRMLVirtualRealityViewNode() override; vtkMRMLVirtualRealityViewNode(const vtkMRMLVirtualRealityViewNode&); diff --git a/VirtualReality/Resources/UI/qSlicerVirtualRealityModuleWidget.ui b/VirtualReality/Resources/UI/qSlicerVirtualRealityModuleWidget.ui index e439275..ed9312d 100644 --- a/VirtualReality/Resources/UI/qSlicerVirtualRealityModuleWidget.ui +++ b/VirtualReality/Resources/UI/qSlicerVirtualRealityModuleWidget.ui @@ -37,13 +37,41 @@ + + + Enable Remoting: + + + + + + + + + + + + false + + + + + + + 000.000.000.000 + + + + + + Connect to hardware: - + @@ -100,14 +128,14 @@ - + Enable rendering: - + diff --git a/VirtualReality/Widgets/qMRMLVirtualRealityView.cxx b/VirtualReality/Widgets/qMRMLVirtualRealityView.cxx index d757114..6509916 100644 --- a/VirtualReality/Widgets/qMRMLVirtualRealityView.cxx +++ b/VirtualReality/Widgets/qMRMLVirtualRealityView.cxx @@ -21,6 +21,7 @@ // For: // - SlicerVirtualReality_HAS_OPENVR_SUPPORT // - SlicerVirtualReality_HAS_OPENXR_SUPPORT +// - SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT #include "vtkMRMLVirtualRealityConfigure.h" // VR Logic includes @@ -93,6 +94,11 @@ #include #endif +#if defined(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) +// VTK Rendering/OpenXRRemoting includes +#include +#endif + // VTK Rendering/VR includes #include #include @@ -242,7 +248,20 @@ void qMRMLVirtualRealityViewPrivate::createRenderWindow(vtkMRMLVirtualRealityVie vtkNew interactorStyle; interactorStyle->SetInteractorStyleDelegate(this->InteractorStyleDelegate); - this->RenderWindow = vtkSmartPointer::New(); +#if defined(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + if (this->MRMLVirtualRealityViewNode->GetRemoting()) + { + vtkSmartPointer xrRemotingRenderWindow = vtkSmartPointer::New(); + xrRemotingRenderWindow->SetRemotingIPAddress(this->MRMLVirtualRealityViewNode->GetPlayerIPAddress().c_str()); + // Address "wglDXRegisterObjectNV failed in RegisterSharedTexture()" reported when using "OpenXRRemoting" + xrRemotingRenderWindow->GetHelperWindow()->SetMultiSamples(0); + this->RenderWindow = xrRemotingRenderWindow; + } + else +#endif + { + this->RenderWindow = vtkSmartPointer::New(); + } this->Renderer = vtkSmartPointer::New(); this->InteractorStyle = interactorStyle; this->Interactor = vtkSmartPointer::New(); @@ -386,6 +405,10 @@ void qMRMLVirtualRealityViewPrivate::createRenderWindow(vtkMRMLVirtualRealityVie // Keep track of last valid parameters in the settings QSettings().setValue("VirtualReality/DefaultXRRuntime", xrRuntimeAsStr); +#if defined(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + QSettings().setValue("VirtualReality/DefaultRemotingEnabled", this->MRMLVirtualRealityViewNode->GetRemoting()); + QSettings().setValue("VirtualReality/DefaultPlayerIPAddress", QString::fromStdString(this->MRMLVirtualRealityViewNode->GetPlayerIPAddress())); +#endif qDebug() << ""; qDebug() << "XR runtime \"" << xrRuntimeAsStr << "\" initialized"; @@ -434,7 +457,11 @@ vtkMRMLVirtualRealityViewNode::XRRuntimeType qMRMLVirtualRealityViewPrivate::cur } #endif #if defined(SlicerVirtualReality_HAS_OPENXR_SUPPORT) - if (vtkOpenXRRenderWindow::SafeDownCast(this->RenderWindow) != nullptr) + if (vtkOpenXRRenderWindow::SafeDownCast(this->RenderWindow) != nullptr +#if defined(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + || vtkOpenXRRemotingRenderWindow::SafeDownCast(this->RenderWindow) != nullptr +#endif + ) { return vtkMRMLVirtualRealityViewNode::OpenXR; } @@ -444,6 +471,22 @@ vtkMRMLVirtualRealityViewNode::XRRuntimeType qMRMLVirtualRealityViewPrivate::cur return vtkMRMLVirtualRealityViewNode::UndefinedXRRuntime; } +// -------------------------------------------------------------------------- +bool qMRMLVirtualRealityViewPrivate::currentXRRuntimeRemotingEnabled() const +{ +#if defined(SlicerVirtualReality_HAS_OPENXRREMOTING_SUPPORT) + return vtkOpenXRRemotingRenderWindow::SafeDownCast(this->RenderWindow) != nullptr; +#else + return false; +#endif +} + +// -------------------------------------------------------------------------- +std::string qMRMLVirtualRealityViewPrivate::currentXRRuntimeRemotingIPAddress() const +{ + return vtkOpenXRManager::GetInstance().GetConnectionStrategy()->GetIPAddress(); +} + // -------------------------------------------------------------------------- void qMRMLVirtualRealityViewPrivate::updateWidgetFromMRML() { @@ -473,7 +516,9 @@ void qMRMLVirtualRealityViewPrivate::updateWidgetFromMRMLNoModify() } // Reset initialization attempts and clear errors if the XR runtime has changed - if (this->currentXRRuntime() != this->MRMLVirtualRealityViewNode->GetXRRuntime()) + if (this->currentXRRuntime() != this->MRMLVirtualRealityViewNode->GetXRRuntime() + || this->currentXRRuntimeRemotingEnabled() != this->MRMLVirtualRealityViewNode->GetRemoting() + || this->currentXRRuntimeRemotingIPAddress() != this->MRMLVirtualRealityViewNode->GetPlayerIPAddress()) { this->InitializationAttempts = 0; this->MRMLVirtualRealityViewNode->ClearError(); @@ -482,6 +527,8 @@ void qMRMLVirtualRealityViewPrivate::updateWidgetFromMRMLNoModify() // Attempt to initialize XR runtime if the current runtime differs or is undefined, and // the view is visible (i.e., connected to the hardware) if ((this->currentXRRuntime() != this->MRMLVirtualRealityViewNode->GetXRRuntime() + || this->currentXRRuntimeRemotingEnabled() != this->MRMLVirtualRealityViewNode->GetRemoting() + || this->currentXRRuntimeRemotingIPAddress() != this->MRMLVirtualRealityViewNode->GetPlayerIPAddress() || this->currentXRRuntime() == vtkMRMLVirtualRealityViewNode::UndefinedXRRuntime) && this->MRMLVirtualRealityViewNode->GetVisibility()) { @@ -520,9 +567,18 @@ void qMRMLVirtualRealityViewPrivate::updateWidgetFromMRMLNoModify() } // Renderer properties - this->Renderer->SetGradientBackground(1); - this->Renderer->SetBackground(this->MRMLVirtualRealityViewNode->GetBackgroundColor()); - this->Renderer->SetBackground2(this->MRMLVirtualRealityViewNode->GetBackgroundColor2()); + if (this->MRMLVirtualRealityViewNode->GetRemoting()) + { + this->Renderer->SetGradientBackground(0); + this->Renderer->SetBackground(0.0, 0.0, 0.0); + this->Renderer->SetBackgroundAlpha(0.0); + } + else + { + this->Renderer->SetGradientBackground(1); + this->Renderer->SetBackground(this->MRMLVirtualRealityViewNode->GetBackgroundColor()); + this->Renderer->SetBackground2(this->MRMLVirtualRealityViewNode->GetBackgroundColor2()); + } this->Renderer->SetTwoSidedLighting(this->MRMLVirtualRealityViewNode->GetTwoSidedLighting()); diff --git a/VirtualReality/Widgets/qMRMLVirtualRealityView_p.h b/VirtualReality/Widgets/qMRMLVirtualRealityView_p.h index a2f52b5..906422a 100644 --- a/VirtualReality/Widgets/qMRMLVirtualRealityView_p.h +++ b/VirtualReality/Widgets/qMRMLVirtualRealityView_p.h @@ -90,6 +90,8 @@ class qMRMLVirtualRealityViewPrivate: public QObject double stillUpdateRate(); vtkMRMLVirtualRealityViewNode::XRRuntimeType currentXRRuntime() const; + bool currentXRRuntimeRemotingEnabled() const; + std::string currentXRRuntimeRemotingIPAddress() const; public slots: void updateWidgetFromMRML(); diff --git a/VirtualReality/qSlicerVirtualRealityModule.cxx b/VirtualReality/qSlicerVirtualRealityModule.cxx index 1c3774c..4ee9ded 100644 --- a/VirtualReality/qSlicerVirtualRealityModule.cxx +++ b/VirtualReality/qSlicerVirtualRealityModule.cxx @@ -469,6 +469,16 @@ void qSlicerVirtualRealityModule::updateDefaultViewNodeFromSettings(vtkMRMLVirtu settings.value("DefaultXRRuntime").toString().toUtf8().constData()); } defaultViewNode->SetXRRuntime(defaultXRRuntime); + // Remoting + if (settings.contains("DefaultRemotingEnabled")) + { + defaultViewNode->SetRemoting(settings.value("DefaultRemotingEnabled").toBool()); + } + // PlayerIPAddress + if (settings.contains("DefaultPlayerIPAddress")) + { + defaultViewNode->SetPlayerIPAddress(settings.value("DefaultPlayerIPAddress").toString().toStdString()); + } settings.endGroup(); // VirtualReality } diff --git a/VirtualReality/qSlicerVirtualRealityModuleWidget.cxx b/VirtualReality/qSlicerVirtualRealityModuleWidget.cxx index 4d410b3..95bb90d 100644 --- a/VirtualReality/qSlicerVirtualRealityModuleWidget.cxx +++ b/VirtualReality/qSlicerVirtualRealityModuleWidget.cxx @@ -93,6 +93,8 @@ void qSlicerVirtualRealityModuleWidget::setup() #endif connect(d->XRRuntimeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setVirtualRealityXRRuntime(int))); + connect(d->RemotingEnabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(setRemotingEnabled(bool))); + connect(d->PlayerIPAddressLineEdit, SIGNAL(editingFinished()), this, SLOT(onPlayerIPAddressLineEditEditingFinished())); connect(d->ConnectCheckBox, SIGNAL(toggled(bool)), this, SLOT(setVirtualRealityConnected(bool))); connect(d->RenderingEnabledCheckBox, SIGNAL(toggled(bool)), this, SLOT(setVirtualRealityActive(bool))); @@ -220,6 +222,25 @@ void qSlicerVirtualRealityModuleWidget::updateWidgetFromMRML() d->UpdateViewFromReferenceViewCameraButton->setEnabled(vrViewNode != nullptr && vrViewNode->GetReferenceViewNode() != nullptr); + + // OpenXRRemoting + wasBlocked = d->RemotingEnabledCheckBox->blockSignals(true); + d->RemotingEnabledCheckBox->setChecked(vrViewNode != nullptr ? vrViewNode->GetRemoting() : false); + d->RemotingEnabledCheckBox->setEnabled( + (vrViewNode != nullptr) + && vrViewNode->GetXRRuntime() == vtkMRMLVirtualRealityViewNode::OpenXR + && !vrLogic->GetVirtualRealityConnected()); + d->RemotingEnabledCheckBox->blockSignals(wasBlocked); + + wasBlocked = d->PlayerIPAddressLineEdit->blockSignals(true); + d->PlayerIPAddressLineEdit->setText( + vrViewNode != nullptr ? QString::fromStdString(vrViewNode->GetPlayerIPAddress()) : QString()); + d->PlayerIPAddressLineEdit->setEnabled( + (vrViewNode != nullptr) + && vrViewNode->GetXRRuntime() == vtkMRMLVirtualRealityViewNode::OpenXR + && vrViewNode->GetRemoting()); + d->PlayerIPAddressLineEdit->setReadOnly(vrLogic->GetVirtualRealityConnected()); + d->PlayerIPAddressLineEdit->blockSignals(wasBlocked); } @@ -445,3 +466,26 @@ void qSlicerVirtualRealityModuleWidget::setTrackerTransformsUpdate(bool active) vrViewNode->SetTrackerTransformUpdate(active); } } + +//---------------------------------------------------------------------------- +void qSlicerVirtualRealityModuleWidget::setRemotingEnabled(bool enabled) +{ + vtkSlicerVirtualRealityLogic* vrLogic = vtkSlicerVirtualRealityLogic::SafeDownCast(this->logic()); + vtkMRMLVirtualRealityViewNode* vrViewNode = vrLogic->GetVirtualRealityViewNode(); + if (vrViewNode) + { + vrViewNode->SetRemoting(enabled); + } +} + +//---------------------------------------------------------------------------- +void qSlicerVirtualRealityModuleWidget::onPlayerIPAddressLineEditEditingFinished() +{ + Q_D(qSlicerVirtualRealityModuleWidget); + vtkSlicerVirtualRealityLogic* vrLogic = vtkSlicerVirtualRealityLogic::SafeDownCast(this->logic()); + vtkMRMLVirtualRealityViewNode* vrViewNode = vrLogic->GetVirtualRealityViewNode(); + if (vrViewNode) + { + vrViewNode->SetPlayerIPAddress(d->PlayerIPAddressLineEdit->text().toStdString()); + } +} diff --git a/VirtualReality/qSlicerVirtualRealityModuleWidget.h b/VirtualReality/qSlicerVirtualRealityModuleWidget.h index 5add30f..7b66b71 100644 --- a/VirtualReality/qSlicerVirtualRealityModuleWidget.h +++ b/VirtualReality/qSlicerVirtualRealityModuleWidget.h @@ -54,6 +54,9 @@ public slots: void setControllerTransformsUpdate(bool); void setHMDTransformUpdate(bool); void setTrackerTransformsUpdate(bool); + // OpenXRRemoting + void setRemotingEnabled(bool); + void onPlayerIPAddressLineEditEditingFinished(); protected slots: void updateWidgetFromMRML(); From f2001bace8f8a4d4e1cd14b61d1fd07278bfee59 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Mon, 8 Jan 2024 22:12:33 -0500 Subject: [PATCH 4/4] ENH: Update OpenXRRemoting from 2.9.1 to 2.9.3 This enhancement enables building the SlicerVirtualReality extension against the latest version (2.9.3) of Microsoft.Holographic.Remoting.OpenXr. This aligns SlicerVirtualReality with the corresponding version of the "Holographic Remoting Player" available on the Microsoft Store. The update relies on VTK changes integrated into the upstream VTK project via vtk/vtk!10814. Additionally, Slicer/VTK fork branches, namely Slicer/VTK#53 for SlicerPreview and Slicer/VTK#54 for SlicerStable, have been synchronized with these changes. For SlicerPreview, changes have been integrated in Slicer through Slicer/Slicer#7534. In the case of SlicerStable, the updated VTK fork has been manually checked out on the relevant build machines to incorporate the necessary adjustments. --- SuperBuild/External_OpenXRRemoting.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SuperBuild/External_OpenXRRemoting.cmake b/SuperBuild/External_OpenXRRemoting.cmake index 2c064b2..b135064 100644 --- a/SuperBuild/External_OpenXRRemoting.cmake +++ b/SuperBuild/External_OpenXRRemoting.cmake @@ -23,8 +23,8 @@ if((NOT OpenXRRemoting_BIN_DIR OR NOT OpenXRRemoting_INCLUDE_DIR) set(EP_INSTALL_DIR ${CMAKE_BINARY_DIR}/${proj}-install) - set(_ver "2.9.1") - set(_sha256 "e8174adaf64089a0cd7cc7e21445dbe8151b57b364312eab773e5c64d9dc28b1") + set(_ver "2.9.3") + set(_sha256 "9ef533aeff9ddef40104ad0d03e1e631c314729b18690385a4a624fab2408797") ExternalProject_Add(${proj} ${${proj}_EP_ARGS}