diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cb60d3926d30ee89edf8b98d5480d1383ff950d..7082c8a8da8c0f696c1ec532f4e083303846914a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,19 @@ if (LibArchive_FOUND) set(HAVE_LIBARCHIVE true) endif() +## OpenVR API path +find_library(OPENVR_LIBRARIES + NAMES + openvr_api +) +set(OPENVR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../headers) + +if (OPENVR_LIBRARIES) + message(STATUS "Found OpenVR: ${OPENVR_LIBRARIES}") + set(HAVE_OPENVR true) +endif() + + if (WITH_FIXSTARS) find_package( LibSGM ) if (LibSGM_FOUND) diff --git a/applications/gui/CMakeLists.txt b/applications/gui/CMakeLists.txt index baffb9bdd645c85cbfc593d81e14687965b9bf4c..b8970d7b91c47aa780c4ee9692b92779b1bc2fd6 100644 --- a/applications/gui/CMakeLists.txt +++ b/applications/gui/CMakeLists.txt @@ -27,6 +27,6 @@ target_include_directories(ftl-gui PUBLIC #endif() #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(ftl-gui ftlcommon ftlctrl ftlrgbd Threads::Threads ${OpenCV_LIBS} glog::glog ftlnet ftlrender nanogui GL) +target_link_libraries(ftl-gui ftlcommon ftlctrl ftlrgbd Threads::Threads ${OpenCV_LIBS} ${OPENVR_LIBRARIES} glog::glog ftlnet ftlrender nanogui GL) diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp index 4ee248dc306c47784b9284f3975d9caee8d267cc..8fdad63282a9a9f54020cb0268e366794104bf83 100644 --- a/applications/gui/src/camera.cpp +++ b/applications/gui/src/camera.cpp @@ -242,6 +242,17 @@ void ftl::gui::Camera::setChannel(ftl::rgbd::channel_t c) { } } +static Eigen::Matrix4d ConvertSteamVRMatrixToMatrix4( const vr::HmdMatrix34_t &matPose ) +{ + Eigen::Matrix4d matrixObj; + matrixObj << + matPose.m[0][0], matPose.m[1][0], matPose.m[2][0], 0.0, + matPose.m[0][1], matPose.m[1][1], matPose.m[2][1], 0.0, + matPose.m[0][2], matPose.m[1][2], matPose.m[2][2], 0.0, + matPose.m[0][3], matPose.m[1][3], matPose.m[2][3], 1.0f; + return matrixObj; +} + const GLTexture &ftl::gui::Camera::captureFrame() { float now = (float)glfwGetTime(); delta_ = now - ftime_; @@ -250,16 +261,32 @@ const GLTexture &ftl::gui::Camera::captureFrame() { if (src_ && src_->isReady()) { cv::Mat rgb, depth; - // Lerp the Eye - eye_[0] += (neye_[0] - eye_[0]) * lerpSpeed_ * delta_; - eye_[1] += (neye_[1] - eye_[1]) * lerpSpeed_ * delta_; - eye_[2] += (neye_[2] - eye_[2]) * lerpSpeed_ * delta_; - - Eigen::Translation3d trans(eye_); - Eigen::Affine3d t(trans); - Eigen::Matrix4d viewPose = t.matrix() * rotmat_; + if (screen_->hasVR()) { + #ifdef HAVE_OPENVR + vr::VRCompositor()->WaitGetPoses(rTrackedDevicePose_, vr::k_unMaxTrackedDeviceCount, NULL, 0 ); + + if ( rTrackedDevicePose_[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid ) + { + auto pose = ConvertSteamVRMatrixToMatrix4( rTrackedDevicePose_[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking ); + pose.inverse(); + if (src_->hasCapabilities(ftl::rgbd::kCapMovable)) src_->setPose(pose); + } else { + LOG(ERROR) << "No VR Pose"; + } + #endif + } else { + // Lerp the Eye + eye_[0] += (neye_[0] - eye_[0]) * lerpSpeed_ * delta_; + eye_[1] += (neye_[1] - eye_[1]) * lerpSpeed_ * delta_; + eye_[2] += (neye_[2] - eye_[2]) * lerpSpeed_ * delta_; + + Eigen::Translation3d trans(eye_); + Eigen::Affine3d t(trans); + Eigen::Matrix4d viewPose = t.matrix() * rotmat_; + + if (src_->hasCapabilities(ftl::rgbd::kCapMovable)) src_->setPose(viewPose); + } - if (src_->hasCapabilities(ftl::rgbd::kCapMovable)) src_->setPose(viewPose); src_->grab(); src_->getFrames(rgb, depth); diff --git a/applications/gui/src/camera.hpp b/applications/gui/src/camera.hpp index 8d48e2c0648caa37ad3064f195db47329e0bf82c..162bad2f0e73879e31efacaa1d20f66c35184b15 100644 --- a/applications/gui/src/camera.hpp +++ b/applications/gui/src/camera.hpp @@ -6,6 +6,10 @@ #include <string> +#ifdef HAVE_OPENVR +#include <openvr/openvr.h> +#endif + class StatisticsImage; namespace ftl { @@ -39,6 +43,7 @@ class Camera { const std::vector<ftl::rgbd::channel_t> &availableChannels(); const GLTexture &captureFrame(); + const GLTexture &getLeft() const { return texture_; } nlohmann::json getMetaData(); @@ -62,6 +67,10 @@ class Camera { bool pause_; ftl::rgbd::channel_t channel_; std::vector<ftl::rgbd::channel_t> channels_; + + #ifdef HAVE_OPENVR + vr::TrackedDevicePose_t rTrackedDevicePose_[ vr::k_unMaxTrackedDeviceCount ]; + #endif }; } diff --git a/applications/gui/src/screen.cpp b/applications/gui/src/screen.cpp index 56624ce61d9524c43e6dffe00948e807528ae595..e944c76b1c5f9eed7200b370097d883675e5085a 100644 --- a/applications/gui/src/screen.cpp +++ b/applications/gui/src/screen.cpp @@ -244,10 +244,31 @@ ftl::gui::Screen::Screen(ftl::Configurable *proot, ftl::net::Universe *pnet, ftl setVisible(true); performLayout(); + + + #ifdef HAVE_OPENVR + if (vr::VR_IsHmdPresent()) { + // Loading the SteamVR Runtime + vr::EVRInitError eError = vr::VRInitError_None; + HMD_ = vr::VR_Init( &eError, vr::VRApplication_Scene ); + + if ( eError != vr::VRInitError_None ) + { + HMD_ = nullptr; + LOG(ERROR) << "Unable to init VR runtime: " << vr::VR_GetVRInitErrorAsEnglishDescription( eError ); + } + } else { + HMD_ = nullptr; + } + #endif } ftl::gui::Screen::~Screen() { mShader.free(); + + #ifdef HAVE_OPENVR + vr::VR_Shutdown(); + #endif } void ftl::gui::Screen::setActiveCamera(ftl::gui::Camera *cam) { @@ -337,6 +358,17 @@ void ftl::gui::Screen::draw(NVGcontext *ctx) { imageSize = {camera_->width(), camera_->height()}; mImageID = camera_->captureFrame().texture(); + leftEye_ = mImageID; + rightEye_ = mImageID; + + #ifdef HAVE_OPENVR + if (hasVR() && (mImageID < std::numeric_limits<unsigned int>::max() && imageSize[0] > 0) && camera_->getLeft().isValid()) { + vr::Texture_t leftEyeTexture = {(void*)(uintptr_t)leftEye_, vr::TextureType_OpenGL, vr::ColorSpace_Gamma }; + vr::VRCompositor()->Submit(vr::Eye_Left, &leftEyeTexture ); + vr::Texture_t rightEyeTexture = {(void*)(uintptr_t)rightEye_, vr::TextureType_OpenGL, vr::ColorSpace_Gamma }; + vr::VRCompositor()->Submit(vr::Eye_Right, &rightEyeTexture ); + } + #endif if (mImageID < std::numeric_limits<unsigned int>::max() && imageSize[0] > 0) { auto mScale = (screenSize.cwiseQuotient(imageSize).minCoeff()); diff --git a/applications/gui/src/screen.hpp b/applications/gui/src/screen.hpp index 8bfce830a034e024ec42037dbc43539a62d50101..d51cec2bf2c34afc7c589b7e6114f503379afe30 100644 --- a/applications/gui/src/screen.hpp +++ b/applications/gui/src/screen.hpp @@ -11,6 +11,10 @@ #include "src_window.hpp" #include "gltexture.hpp" +#ifdef HAVE_OPENVR +#include <openvr/openvr.h> +#endif + class StatisticsImageNSamples; namespace ftl { @@ -39,6 +43,12 @@ class Screen : public nanogui::Screen { void setActiveCamera(ftl::gui::Camera*); ftl::gui::Camera *activeCamera() { return camera_; } + #ifdef HAVE_OPENVR + bool hasVR() const { return HMD_ != nullptr; } + #else + bool hasVR() const { return false; } + #endif + nanogui::Theme *windowtheme; nanogui::Theme *specialtheme; nanogui::Theme *mediatheme; @@ -68,6 +78,13 @@ class Screen : public nanogui::Screen { ftl::Configurable *root_; std::string status_; ftl::gui::Camera *camera_; + + GLuint leftEye_; + GLuint rightEye_; + + #ifdef HAVE_OPENVR + vr::IVRSystem *HMD_; + #endif }; } diff --git a/components/common/cpp/include/ftl/config.h.in b/components/common/cpp/include/ftl/config.h.in index 025ad576f9878019a41e0aa46269645c442780cd..ff965cbb011c5a52d9e7aed4b45c9e73774e847a 100644 --- a/components/common/cpp/include/ftl/config.h.in +++ b/components/common/cpp/include/ftl/config.h.in @@ -22,6 +22,7 @@ #cmakedefine HAVE_REALSENSE #cmakedefine HAVE_NANOGUI #cmakedefine HAVE_LIBARCHIVE +#cmakedefine HAVE_OPENVR extern const char *FTL_BRANCH; extern const char *FTL_VERSION_LONG;