Initial pass at OpenVR

This commit is contained in:
Brad Davis 2015-06-12 17:29:05 -07:00
parent a26373bd3a
commit 15d214f335
23 changed files with 280 additions and 305 deletions

View file

@ -23,16 +23,19 @@ if (WIN32)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/win32/openvr_api.lib CACHE TYPE INTERNAL)
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/win32)
elseif(APPLE)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/osx32/libopenvr_api.dylib CACHE TYPE INTERNAL)
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/osx32)
elseif(NOT ANDROID)
# FIXME need to account for different architectures
set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${SOURCE_DIR}/lib/linux32/libopenvr_api.so CACHE TYPE INTERNAL)
add_paths_to_fixup_libs(${SOURCE_DIR}/bin/linux32)
endif()

View file

@ -865,7 +865,7 @@ void Application::paintGL() {
auto displayPlugin = getActiveDisplayPlugin();
displayPlugin->preRender();
_glWidget->makeCurrent();
_offscreenContext->makeCurrent();
auto lodManager = DependencyManager::get<LODManager>();
gpu::Context context(new gpu::GLBackend());
@ -875,7 +875,6 @@ void Application::paintGL() {
PerformanceTimer perfTimer("paintGL");
_offscreenContext->makeCurrent();
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::paintGL()");
@ -938,7 +937,7 @@ void Application::paintGL() {
}
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
DependencyManager::get<GlowEffect>()->prepare();
DependencyManager::get<GlowEffect>()->prepare(&renderArgs);
// Primary rendering pass
auto primaryFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
auto finalFbo = primaryFbo;
@ -963,13 +962,13 @@ void Application::paintGL() {
eyeCamera.setTransform(displayPlugin->getModelview(eye, _myCamera.getTransform()));
eyeCamera.setProjection(displayPlugin->getProjection(eye, _myCamera.getProjection()));
displaySide(eyeCamera);
displaySide(&renderArgs, eyeCamera);
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
_rearMirrorTools->render(true, QPoint(mpos.x, mpos.y));
_rearMirrorTools->render(&renderArgs, true, QPoint(mpos.x, mpos.y));
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
renderRearViewMirror(_mirrorViewRect);
renderRearViewMirror(&renderArgs, _mirrorViewRect);
}
}, [&] {
r.moveLeft(r.width());
@ -977,15 +976,15 @@ void Application::paintGL() {
glDisable(GL_SCISSOR_TEST);
} else {
glViewport(0, 0, size.width(), size.height());
displaySide(_myCamera);
displaySide(&renderArgs, _myCamera);
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
_rearMirrorTools->render(true, QPoint(mpos.x, mpos.y));
_rearMirrorTools->render(&renderArgs, true, QPoint(mpos.x, mpos.y));
} else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
renderRearViewMirror(_mirrorViewRect);
renderRearViewMirror(&renderArgs, _mirrorViewRect);
}
}
finalFbo = DependencyManager::get<GlowEffect>()->render();
finalFbo = DependencyManager::get<GlowEffect>()->render(&renderArgs);
}
glPopMatrix();
@ -3030,7 +3029,8 @@ void Application::updateShadowMap(RenderArgs* renderArgs) {
glMatrixMode(GL_MODELVIEW);
}
glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
glViewport(0, 0, getDeviceSize().width(), getDeviceSize().height());
activeRenderingThread = nullptr;
}
@ -3271,7 +3271,7 @@ namespace render {
PerformanceTimer perfTimer("atmosphere");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... atmosphere...");
background->_environment->renderAtmospheres(*(args->_viewFrustum));
background->_environment->renderAtmospheres(args->_viewFrustum->getPosition());
}
}
@ -3291,7 +3291,7 @@ namespace render {
}
void Application::displaySide(RenderArgs* renderArgs, const Camera& theCamera, bool selfAvatarOnly) {
void Application::displaySide(RenderArgs* renderArgs, const Camera& theCamera, bool selfAvatarOnly, bool billboard) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("display");
@ -3555,32 +3555,6 @@ bool Application::getCascadeShadowsEnabled() {
return Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
}
glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
float horizontalScale = _glWidget->getDeviceWidth() / 2.0f;
float verticalScale = _glWidget->getDeviceHeight() / 2.0f;
// -1,-1 is 0,windowHeight
// 1,1 is windowWidth,0
// -1,1 1,1
// +-----------------------+
// | | |
// | | |
// | -1,0 | |
// |-----------+-----------|
// | 0,0 |
// | | |
// | | |
// | | |
// +-----------------------+
// -1,-1 1,-1
glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,
((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());
return screenPoint;
}
void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard) {
// Grab current viewport to reset it at the end
int viewport[4];
@ -3643,7 +3617,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
glPopMatrix();
if (!billboard) {
_rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos()));
_rearMirrorTools->render(renderArgs, false, getActiveDisplayPlugin()->getWindow()->mapFromGlobal(QCursor::pos()));
}
// reset Viewport and projection matrix
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
@ -4829,7 +4803,6 @@ void Application::updateDisplayMode() {
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->setMouseTranslator(getActiveDisplayPlugin()->getMouseTranslator());
updateCursorVisibility();
}
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
}

View file

@ -21,6 +21,8 @@
#else
#endif
#include <display-plugins/openvr/OpenVrDisplayPlugin.h>
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
auto menu = Menu::getInstance();
@ -56,7 +58,8 @@ const DisplayPluginList& getDisplayPlugins() {
#endif
new SideBySideStereoDisplayPlugin(),
new InterleavedStereoDisplayPlugin(),
new OculusWin32DisplayPlugin(),
// new OculusWin32DisplayPlugin(),
new OpenVrDisplayPlugin(),
nullptr
};
for (int i = 0; PLUGIN_POOL[i]; ++i) {

View file

@ -1,158 +0,0 @@
//
// TV3DManager.cpp
// interface/src/devices
//
// Created by Brad Hefta-Gaub on 12/24/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InterfaceConfig.h"
#include <glm/glm.hpp>
#include <GlowEffect.h>
#include "gpu/GLBackend.h"
#include "Application.h"
#include "TV3DManager.h"
#include "Menu.h"
int TV3DManager::_screenWidth = 1;
int TV3DManager::_screenHeight = 1;
double TV3DManager::_aspect = 1.0;
eyeFrustum TV3DManager::_leftEye;
eyeFrustum TV3DManager::_rightEye;
eyeFrustum* TV3DManager::_activeEye = NULL;
bool TV3DManager::isConnected() {
return Menu::getInstance()->isOptionChecked(MenuOption::Enable3DTVMode);
}
void TV3DManager::connect() {
auto deviceSize = qApp->getDeviceSize();
configureCamera(*(qApp->getCamera()), deviceSize.width(), deviceSize.height());
}
// The basic strategy of this stereoscopic rendering is explained here:
// http://www.orthostereo.com/geometryopengl.html
void TV3DManager::setFrustum(const Camera& whichCamera) {
const double DTR = 0.0174532925; // degree to radians
const double IOD = 0.05; //intraocular distance
double fovy = DEFAULT_FIELD_OF_VIEW_DEGREES; // field of view in y-axis
double nearZ = DEFAULT_NEAR_CLIP; // near clipping plane
double screenZ = 0.25f; // screen projection plane
double top = nearZ * tan(DTR * fovy / 2.0); //sets top of frustum based on fovy and near clipping plane
double right = _aspect * top; // sets right of frustum based on aspect ratio
double frustumshift = (IOD / 2) * nearZ / screenZ;
_leftEye.top = top;
_leftEye.bottom = -top;
_leftEye.left = -right + frustumshift;
_leftEye.right = right + frustumshift;
_leftEye.modelTranslation = IOD / 2;
_rightEye.top = top;
_rightEye.bottom = -top;
_rightEye.left = -right - frustumshift;
_rightEye.right = right - frustumshift;
_rightEye.modelTranslation = -IOD / 2;
}
void TV3DManager::configureCamera(Camera& whichCamera_, int screenWidth, int screenHeight) {
const Camera& whichCamera = whichCamera_;
if (screenHeight == 0) {
screenHeight = 1; // prevent divide by 0
}
_screenWidth = screenWidth;
_screenHeight = screenHeight;
_aspect= (double)_screenWidth / (double)_screenHeight;
setFrustum(whichCamera);
glViewport (0, 0, _screenWidth, _screenHeight); // sets drawing viewport
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) {
double nearZ = DEFAULT_NEAR_CLIP; // near clipping plane
double farZ = DEFAULT_FAR_CLIP; // far clipping plane
// left eye portal
int portalX = 0;
int portalY = 0;
QSize deviceSize = qApp->getDeviceSize() *
qApp->getRenderResolutionScale();
int portalW = deviceSize.width() / 2;
int portalH = deviceSize.height();
DependencyManager::get<GlowEffect>()->prepare(renderArgs);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Camera eyeCamera;
eyeCamera.setRotation(whichCamera.getRotation());
eyeCamera.setPosition(whichCamera.getPosition());
glEnable(GL_SCISSOR_TEST);
glPushMatrix();
forEachEye([&](eyeFrustum& eye){
_activeEye = &eye;
glViewport(portalX, portalY, portalW, portalH);
glScissor(portalX, portalY, portalW, portalH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // reset projection matrix
glFrustum(eye.left, eye.right, eye.bottom, eye.top, nearZ, farZ); // set left view frustum
GLfloat p[4][4];
// Really?
glGetFloatv(GL_PROJECTION_MATRIX, &(p[0][0]));
float cotangent = p[1][1];
GLfloat fov = atan(1.0f / cotangent);
glTranslatef(eye.modelTranslation, 0.0, 0.0); // translate to cancel parallax
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
renderArgs->_renderSide = RenderArgs::MONO;
qApp->displaySide(renderArgs, eyeCamera, false);
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
_activeEye = NULL;
}, [&]{
// render right side view
portalX = deviceSize.width() / 2;
});
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
auto finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);
auto fboSize = finalFbo->getSize();
// Get the ACTUAL device size for the BLIT
deviceSize = qApp->getDeviceSize();
glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fboSize.x, fboSize.y,
0, 0, deviceSize.width(), deviceSize.height(),
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// reset the viewport to how we started
glViewport(0, 0, deviceSize.width(), deviceSize.height());
}
void TV3DManager::overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) {
if (_activeEye) {
left = _activeEye->left;
right = _activeEye->right;
bottom = _activeEye->bottom;
top = _activeEye->top;
}
}

View file

@ -1,62 +0,0 @@
//
// TV3DManager.h
// interface/src/devices
//
// Created by Brad Hefta-Gaub on 12/24/2013.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_TV3DManager_h
#define hifi_TV3DManager_h
#include <iostream>
#include <glm/glm.hpp>
class Camera;
struct eyeFrustum {
double left;
double right;
double bottom;
double top;
float modelTranslation;
};
/// Handles interaction with 3D TVs
class TV3DManager {
public:
static void connect();
static bool isConnected();
static void configureCamera(Camera& camera, int screenWidth, int screenHeight);
static void display(RenderArgs* renderArgs, Camera& whichCamera);
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
private:
static void setFrustum(const Camera& whichCamera);
static int _screenWidth;
static int _screenHeight;
static double _aspect;
static eyeFrustum _leftEye;
static eyeFrustum _rightEye;
static eyeFrustum* _activeEye;
// The first function is the code executed for each eye
// while the second is code to be executed between the two eyes.
// The use case here is to modify the output viewport coordinates
// for the new eye.
// FIXME: we'd like to have a default empty lambda for the second parameter,
// but gcc 4.8.1 complains about it due to a bug. See
// http://stackoverflow.com/questions/25490662/lambda-as-default-parameter-to-a-member-function-template
template<typename F, typename FF>
static void forEachEye(F f, FF ff) {
f(_leftEye);
ff();
f(_rightEye);
}
};
#endif // hifi_TV3DManager_h

View file

@ -621,9 +621,6 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
//Renders optional pointers
void ApplicationOverlay::renderPointers() {
//lazily load crosshair texture
if (_crosshairTexture == 0) {
_crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -791,16 +788,16 @@ void ApplicationOverlay::renderControllerPointers() {
}
void ApplicationOverlay::renderPointersOculus() {
#if 0
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
bindCursorTexture();
glMatrixMode(GL_MODELVIEW);
//Controller Pointers
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
@ -825,6 +822,7 @@ void ApplicationOverlay::renderPointersOculus() {
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
#endif
}
//Renders a small magnification of the currently bound texture at the coordinates

View file

@ -81,8 +81,6 @@ private:
void renderDomainConnectionStatusBorder();
void bindCursorTexture(gpu::Batch& batch, uint8_t cursorId = 0);
TexturedHemisphere _overlays;
float _textureFov;
float _textureAspectRatio;

View file

@ -45,10 +45,12 @@ void LocalModelsOverlay::render(RenderArgs* args) {
glPushMatrix(); {
Application* app = Application::getInstance();
#if 0
glm::vec3 oldTranslation = app->getViewMatrixTranslation();
app->setViewMatrixTranslation(oldTranslation + _position);
_entityTreeRenderer->render(args);
Application::getInstance()->setViewMatrixTranslation(oldTranslation);
#endif
} glPopMatrix();
}
}

View file

@ -9,6 +9,6 @@
const QString Basic2DWindowOpenGLDisplayPlugin::NAME("2D Display");
const QString & Basic2DWindowOpenGLDisplayPlugin::getName() {
const QString & Basic2DWindowOpenGLDisplayPlugin::getName() const {
return NAME;
}

View file

@ -13,7 +13,7 @@ class Basic2DWindowOpenGLDisplayPlugin : public MainWindowOpenGLDisplayPlugin {
Q_OBJECT
public:
virtual const QString & getName() override;
virtual const QString & getName() const override;
private:
static const QString NAME;

View file

@ -11,7 +11,7 @@
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
const QString & NullDisplayPlugin::getName() {
const QString & NullDisplayPlugin::getName() const {
return NAME;
}
@ -27,10 +27,6 @@ bool NullDisplayPlugin::hasFocus() const {
return false;
}
glm::ivec2 NullDisplayPlugin::getRelativeMousePosition() const {
return glm::ivec2();
}
glm::ivec2 NullDisplayPlugin::getTrueMousePosition() const {
return glm::ivec2();
}

View file

@ -11,24 +11,26 @@
class NullDisplayPlugin : public DisplayPlugin {
public:
static const QString NAME;
virtual ~NullDisplayPlugin() final {}
virtual const QString & getName();
virtual const QString & getName() const override;
void activate(PluginContainer * container);
void deactivate();
void activate(PluginContainer * container) override;
void deactivate() override;
virtual QSize getDeviceSize() const;
virtual glm::ivec2 getCanvasSize() const;
virtual bool hasFocus() const;
virtual glm::ivec2 getRelativeMousePosition() const;
virtual glm::ivec2 getTrueMousePosition() const;
virtual PickRay computePickRay(const glm::vec2 & pos) const;
virtual bool isMouseOnScreen() const;
virtual QWindow* getWindow() const;
virtual void preRender();
virtual void preDisplay();
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize);
virtual void finishFrame();
virtual QSize getDeviceSize() const override;
virtual glm::ivec2 getCanvasSize() const override;
virtual bool hasFocus() const override;
// virtual glm::ivec2 getRelativeMousePosition() const override;
virtual glm::ivec2 getTrueMousePosition() const override;
virtual PickRay computePickRay(const glm::vec2 & pos) const override;
virtual bool isMouseOnScreen() const override;
virtual QWindow* getWindow() const override;
virtual void preRender() override;
virtual void preDisplay() override;
virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override;
virtual void finishFrame() override;
private:
static const QString NAME;
};

View file

@ -18,7 +18,7 @@ public:
WidgetOpenGLDisplayPlugin();
virtual const QString & getName() override;
virtual const QString & getName() const override;
virtual glm::ivec2 getTrueMousePosition() const override;
virtual QSize getDeviceSize() const override;
virtual glm::ivec2 getCanvasSize() const override;

View file

@ -146,11 +146,11 @@ private:
const QString OculusWin32DisplayPlugin::NAME("Oculus Rift");
const QString & OculusWin32DisplayPlugin::getName() {
const QString & OculusWin32DisplayPlugin::getName() const {
return NAME;
}
bool OculusWin32DisplayPlugin::isSupported() {
bool OculusWin32DisplayPlugin::isSupported() const {
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
return false;
}

View file

@ -20,8 +20,8 @@ using MirrorFboPtr = QSharedPointer<MirrorFramebufferWrapper>;
class OculusWin32DisplayPlugin : public OculusBaseDisplayPlugin {
public:
virtual bool isSupported();
virtual const QString & getName();
virtual bool isSupported() const override;
virtual const QString & getName() const override;
virtual void activate(PluginContainer * container) override;
virtual void deactivate() override;

View file

@ -0,0 +1,165 @@
//
// Created by Bradley Austin Davis on 2015/05/12
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OpenVrDisplayPlugin.h"
#include <memory>
#include <QMainWindow>
#include <QGLWidget>
#include <GLMHelpers.h>
#include <GlWindow.h>
#include <QEvent>
#include <QResizeEvent>
#include <PerfStat.h>
#include <plugins/PluginContainer.h>
#include <ViewFrustum.h>
#include "OpenVrHelpers.h"
#include "../OglplusHelpers.h"
const QString OpenVrDisplayPlugin::NAME("OpenVR (Vive)");
const QString & OpenVrDisplayPlugin::getName() const {
return NAME;
}
static vr::IVRSystem *_hmd{ nullptr };
static vr::IVRCompositor* _compositor{ nullptr };
static vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
static mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount];
static uvec2 _windowSize;
static ivec2 _windowPosition;
static uvec2 _renderTargetSize;
struct PerEyeData {
uvec2 _viewportOrigin;
uvec2 _viewportSize;
mat4 _projectionMatrix;
mat4 _eyeOffset;
mat4 _pose;
};
static PerEyeData _eyesData[2];
template<typename F>
void openvr_for_each_eye(F f) {
f(vr::Hmd_Eye::Eye_Left);
f(vr::Hmd_Eye::Eye_Right);
}
mat4 toGlm(const vr::HmdMatrix44_t& m) {
return glm::transpose(glm::make_mat4(&m.m[0][0]));
}
mat4 toGlm(const vr::HmdMatrix34_t& m) {
mat4 result = mat4(
m.m[0][0], m.m[1][0], m.m[2][0], 0.0,
m.m[0][1], m.m[1][1], m.m[2][1], 0.0,
m.m[0][2], m.m[1][2], m.m[2][2], 0.0,
m.m[0][3], m.m[1][3], m.m[2][3], 1.0f);
return result;
}
bool OpenVrDisplayPlugin::isSupported() const {
return vr::VR_IsHmdPresent();
}
void OpenVrDisplayPlugin::activate(PluginContainer * container) {
vr::HmdError eError = vr::HmdError_None;
_hmd = vr::VR_Init(&eError);
Q_ASSERT(eError == vr::HmdError_None);
Q_ASSERT(_hmd);
_hmd->GetWindowBounds(&_windowPosition.x, &_windowPosition.y, &_windowSize.x, &_windowSize.y);
_hmd->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
openvr_for_each_eye([&](vr::Hmd_Eye eye) {
PerEyeData& eyeData = _eyesData[eye];
_hmd->GetEyeOutputViewport(eye,
&eyeData._viewportOrigin.x, &eyeData._viewportOrigin.y,
&eyeData._viewportSize.x, &eyeData._viewportSize.y);
eyeData._projectionMatrix = toGlm(_hmd->GetProjectionMatrix(eye, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, vr::API_OpenGL));
eyeData._eyeOffset = toGlm(_hmd->GetEyeToHeadTransform(eye));
});
_compositor = (vr::IVRCompositor*)vr::VR_GetGenericInterface(vr::IVRCompositor_Version, &eError);
Q_ASSERT(eError == vr::HmdError_None);
Q_ASSERT(_compositor);
_compositor->SetGraphicsDevice(vr::Compositor_DeviceType_OpenGL, NULL);
uint32_t unSize = _compositor->GetLastError(NULL, 0);
if (unSize > 1) {
char* buffer = new char[unSize];
_compositor->GetLastError(buffer, unSize);
printf("Compositor - %s\n", buffer);
delete[] buffer;
}
Q_ASSERT(unSize <= 1);
MainWindowOpenGLDisplayPlugin::activate(container);
}
void OpenVrDisplayPlugin::deactivate() {
vr::VR_Shutdown();
_hmd = nullptr;
_compositor = nullptr;
}
QSize OpenVrDisplayPlugin::getRecommendedFramebufferSize() const {
return QSize(_renderTargetSize.x, _renderTargetSize.y);
}
mat4 OpenVrDisplayPlugin::getProjection(Eye eye, const mat4& baseProjection) const {
return _eyesData[eye]._projectionMatrix;
}
glm::mat4 OpenVrDisplayPlugin::getModelview(Eye eye, const mat4& baseModelview) const {
return baseModelview * _eyesData[eye]._pose;
}
void OpenVrDisplayPlugin::preRender() {
}
void OpenVrDisplayPlugin::resetSensors() {
_hmd->ResetSeatedZeroPose();
}
glm::mat4 OpenVrDisplayPlugin::getEyePose(Eye eye) const {
return _eyesData[eye]._pose;
}
glm::mat4 OpenVrDisplayPlugin::getHeadPose() const {
return _trackedDevicePoseMat4[0];
}
void OpenVrDisplayPlugin::customizeContext(PluginContainer * container) {
MainWindowOpenGLDisplayPlugin::customizeContext(container);
}
void OpenVrDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
// Flip y-axis since GL UV coords are backwards.
static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 };
static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 };
_compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds);
_compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds);
glFinish();
}
void OpenVrDisplayPlugin::finishFrame() {
// swapBuffers();
doneCurrent();
_compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount);
_trackedDevicePoseMat4[0] = toGlm(_trackedDevicePose[0].mDeviceToAbsoluteTracking);
openvr_for_each_eye([&](vr::Hmd_Eye eye) {
_eyesData[eye]._pose = _trackedDevicePoseMat4[0];
});
};

View file

@ -0,0 +1,41 @@
//
// Created by Bradley Austin Davis on 2015/06/12
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include "../MainWindowOpenGLDisplayPlugin.h"
class OpenVrDisplayPlugin : public MainWindowOpenGLDisplayPlugin {
public:
virtual bool isSupported() const override;
virtual const QString & getName() const override;
virtual void activate(PluginContainer * container) override;
virtual void deactivate() override;
// Stereo specific methods
virtual bool isHmd() const override { return true; }
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
virtual glm::mat4 getModelview(Eye eye, const glm::mat4& baseModelview) const override;
virtual void preRender() override;
virtual QSize getRecommendedFramebufferSize() const override;
virtual void resetSensors() override;
virtual glm::ivec2 getCanvasSize() const override { return ivec2(1920, 1080); }
virtual glm::mat4 getEyePose(Eye eye) const override;
virtual glm::mat4 getHeadPose() const override;
protected:
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
virtual void customizeContext(PluginContainer * container) override;
// Do not perform swap in finish
virtual void finishFrame() override;
private:
static const QString NAME;
};

View file

@ -0,0 +1,14 @@
//
// Created by Bradley Austin Davis on 2015/06/12
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include <openvr.h>
#include <GLMHelpers.h>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>

View file

@ -19,7 +19,7 @@
const QString InterleavedStereoDisplayPlugin::NAME("Interleaved Stereo Display");
const QString & InterleavedStereoDisplayPlugin::getName() {
const QString & InterleavedStereoDisplayPlugin::getName() const {
return NAME;
}

View file

@ -13,7 +13,7 @@ class InterleavedStereoDisplayPlugin : public StereoDisplayPlugin {
Q_OBJECT
public:
InterleavedStereoDisplayPlugin();
virtual const QString & getName() override;
virtual const QString & getName() const override;
// initialize OpenGL context settings needed by the plugin
virtual void customizeContext(PluginContainer * container) override;

View file

@ -19,7 +19,7 @@
const QString SideBySideStereoDisplayPlugin::NAME("SBS Stereo Display");
const QString & SideBySideStereoDisplayPlugin::getName() {
const QString & SideBySideStereoDisplayPlugin::getName() const {
return NAME;
}

View file

@ -13,7 +13,7 @@ class SideBySideStereoDisplayPlugin : public StereoDisplayPlugin {
Q_OBJECT
public:
SideBySideStereoDisplayPlugin();
virtual const QString & getName() override;
virtual const QString & getName() const override;
private:
static const QString NAME;
};

View file

@ -7,7 +7,7 @@ class PluginContainer;
class Plugin : public QObject {
public:
virtual const QString& getName() = 0;
virtual const QString& getName() const = 0;
virtual bool isSupported() const;
/// Called when plugin is initially loaded, typically at application start