From 78598b41009aeabb7f9b4b4ddc05b68e7edd6eb6 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 18 Sep 2016 02:34:32 +0300 Subject: [PATCH] Implement a basic OpenVR driver There's still work to be done but it can render to the HMD and provide tracking. --- Build | 10 ++++++ source/openvr/openvrcamera.cpp | 24 +++++++++++++ source/openvr/openvrcamera.h | 26 ++++++++++++++ source/openvr/openvrcombiner.cpp | 57 +++++++++++++++++++++++++++++ source/openvr/openvrcombiner.h | 28 +++++++++++++++ source/openvr/openvrdevice.cpp | 61 ++++++++++++++++++++++++++++++++ source/openvr/openvrdevice.h | 35 ++++++++++++++++++ 7 files changed, 241 insertions(+) create mode 100644 source/openvr/openvrcamera.cpp create mode 100644 source/openvr/openvrcamera.h create mode 100644 source/openvr/openvrcombiner.cpp create mode 100644 source/openvr/openvrcombiner.h create mode 100644 source/openvr/openvrdevice.cpp create mode 100644 source/openvr/openvrdevice.h diff --git a/Build b/Build index 33363fc..85616de 100644 --- a/Build +++ b/Build @@ -7,6 +7,7 @@ package "mspvr" require "mspgui"; feature "libovr" "Support Oculus Rift through LibOVR"; + feature "openvr" "Support HTC Vive and other devices through OpenVR"; if_feature "libovr" { @@ -19,6 +20,11 @@ package "mspvr" }; }; + if_feature "openvr" + { + require "openvr"; + }; + library "mspvr" { source "source"; @@ -26,6 +32,10 @@ package "mspvr" { source "source/ovr"; }; + if_feature "openvr" + { + source "source/openvr"; + }; install true; install_map { diff --git a/source/openvr/openvrcamera.cpp b/source/openvr/openvrcamera.cpp new file mode 100644 index 0000000..6166d3a --- /dev/null +++ b/source/openvr/openvrcamera.cpp @@ -0,0 +1,24 @@ +#include +#include "openvrcamera.h" +#include "openvrdevice.h" + +namespace Msp { +namespace VR { + +OpenVRCamera::OpenVRCamera(const OpenVRDevice &d, const GL::Camera &c): + HeadTrackingCamera(c), + device(d) +{ } + +void OpenVRCamera::reset_tracking() +{ + vr::VRSystem()->ResetSeatedZeroPose(); +} + +void OpenVRCamera::update() +{ + update_from_matrix(device.get_hmd_matrix()); +} + +} // namespace VR +} // namespace Msp diff --git a/source/openvr/openvrcamera.h b/source/openvr/openvrcamera.h new file mode 100644 index 0000000..ff86817 --- /dev/null +++ b/source/openvr/openvrcamera.h @@ -0,0 +1,26 @@ +#ifndef MSP_VR_OPENVRCAMERA_H_ +#define MSP_VR_OPENVRCAMERA_H_ + +#include + +namespace Msp { +namespace VR { + +class OpenVRDevice; + +class OpenVRCamera: public HeadTrackingCamera +{ +private: + const OpenVRDevice &device; + +public: + OpenVRCamera(const OpenVRDevice &, const GL::Camera &); + + virtual void reset_tracking(); + virtual void update(); +}; + +} // namespace VR +} // namespace Msp + +#endif diff --git a/source/openvr/openvrcombiner.cpp b/source/openvr/openvrcombiner.cpp new file mode 100644 index 0000000..2272a1a --- /dev/null +++ b/source/openvr/openvrcombiner.cpp @@ -0,0 +1,57 @@ +#include +#include "openvrcombiner.h" +#include "openvrdevice.h" + +namespace Msp { +namespace VR { + +struct OpenVRCombiner::Private +{ + static Frustum get_projection(vr::EVREye); +}; + + +OpenVRCombiner::OpenVRCombiner(OpenVRDevice &d): + device(d) +{ + vr::IVRSystem *vr_sys = vr::VRSystem(); + uint32_t w, h; + vr_sys->GetRecommendedRenderTargetSize(&w, &h); + target_width = w; + target_height = h; + + Frustum left_frustum = Private::get_projection(vr::Eye_Left); + Frustum right_frustum = Private::get_projection(vr::Eye_Right); + configure_eye_frustums(left_frustum, right_frustum); +} + +void OpenVRCombiner::prepare() const +{ + device.update_pose_matrices(); +} + +void OpenVRCombiner::render(const GL::Texture2D &left, const GL::Texture2D &right) const +{ + vr::Texture_t tex; + tex.eType = vr::API_OpenGL; + tex.eColorSpace = vr::ColorSpace_Gamma; + + vr::IVRCompositor *compositor = vr::VRCompositor(); + tex.handle = reinterpret_cast(left.get_id()); + compositor->Submit(vr::Eye_Left, &tex); + tex.handle = reinterpret_cast(right.get_id()); + compositor->Submit(vr::Eye_Right, &tex); +} + + +StereoCombiner::Frustum OpenVRCombiner::Private::get_projection(vr::EVREye eye) +{ + Frustum frustum; + /* The parameter order is documented as left, right, top, bottom; however + the third parameter is actually negative and fourth one positive. */ + vr::VRSystem()->GetProjectionRaw(eye, &frustum.left, &frustum.right, &frustum.bottom, &frustum.top); + return frustum; +} + +} // namespace VR +} // namespace Msp diff --git a/source/openvr/openvrcombiner.h b/source/openvr/openvrcombiner.h new file mode 100644 index 0000000..ad4a37d --- /dev/null +++ b/source/openvr/openvrcombiner.h @@ -0,0 +1,28 @@ +#ifndef MSP_VR_OPENVRCOMBINER_H_ +#define MSP_VR_OPENVRCOMBINER_H_ + +#include + +namespace Msp { +namespace VR { + +class OpenVRDevice; + +class OpenVRCombiner: public StereoCombiner +{ +private: + struct Private; + + OpenVRDevice &device; + +public: + OpenVRCombiner(OpenVRDevice &); + + virtual void prepare() const; + virtual void render(const GL::Texture2D &, const GL::Texture2D &) const; +}; + +} // namespace VR +} // namespace Msp + +#endif diff --git a/source/openvr/openvrdevice.cpp b/source/openvr/openvrdevice.cpp new file mode 100644 index 0000000..1081a04 --- /dev/null +++ b/source/openvr/openvrdevice.cpp @@ -0,0 +1,61 @@ +#include +#include "openvrdevice.h" + +using namespace std; + +namespace Msp { +namespace VR { + +unsigned OpenVRDevice::n_instances = 0; + +OpenVRDevice::OpenVRDevice() +{ + if(!n_instances) + { + vr::EVRInitError init_err; + vr::VR_Init(&init_err, vr::VRApplication_Scene); + if(init_err!=vr::VRInitError_None) + throw runtime_error("OpenVR initialization failed"); + } + ++n_instances; + + vr::IVRCompositor *compositor = vr::VRCompositor(); + if(!compositor) + throw runtime_error("OpenVR compositor initialization failed"); + + vr::VRCompositor()->SetTrackingSpace(vr::TrackingUniverseSeated); +} + +OpenVRDevice::~OpenVRDevice() +{ + if(!--n_instances) + vr::VR_Shutdown(); +} + +OpenVRCamera *OpenVRDevice::create_camera(const GL::Camera &bc) +{ + return new OpenVRCamera(*this, bc); +} + +OpenVRCombiner *OpenVRDevice::create_combiner(GL::View &) +{ + return new OpenVRCombiner(*this); +} + +void OpenVRDevice::update_pose_matrices() +{ + vector poses; + poses.resize(vr::k_unTrackedDeviceIndex_Hmd+1); + vr::VRCompositor()->WaitGetPoses(&poses[0], poses.size(), 0, 0); + + vr::TrackedDevicePose_t &hmd_pose = poses[vr::k_unTrackedDeviceIndex_Hmd]; + if(hmd_pose.bPoseIsValid) + { + for(unsigned i=0; i<3; ++i) + for(unsigned j=0; j<4; ++j) + hmd_matrix(i, j) = hmd_pose.mDeviceToAbsoluteTracking.m[i][j]; + } +} + +} // namespace VR +} // namespace Msp diff --git a/source/openvr/openvrdevice.h b/source/openvr/openvrdevice.h new file mode 100644 index 0000000..a1ee0db --- /dev/null +++ b/source/openvr/openvrdevice.h @@ -0,0 +1,35 @@ +#ifndef MSP_VR_OPENVRDEVICE_H_ +#define MSP_VR_OPENVRDEVICE_H_ + +#include +#include +#include "openvrcamera.h" +#include "openvrcombiner.h" + +namespace Msp { +namespace VR { + +class OpenVRDevice: public DisplayDevice +{ +private: + GL::Matrix hmd_matrix; + + static unsigned n_instances; + +public: + OpenVRDevice(); + ~OpenVRDevice(); + + virtual void configure_window(Graphics::Window &) const { } + virtual void configure_view(StereoView &) const { } + virtual OpenVRCamera *create_camera(const GL::Camera &); + virtual OpenVRCombiner *create_combiner(GL::View &); + + void update_pose_matrices(); + const GL::Matrix &get_hmd_matrix() const { return hmd_matrix; } +}; + +} // namespace VR +} // namespace Msp + +#endif -- 2.43.0