From c5406c47a6550c0e6a9ef3293070f9066a6fce01 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 26 Nov 2013 11:59:06 -0800 Subject: [PATCH] Moved Oculus code out of Application, started on using StereoConfig to get actual values to replace the magic numbers. --- interface/resources/shaders/oculus.frag | 36 +++++ interface/src/Application.cpp | 177 +++--------------------- interface/src/Application.h | 13 +- interface/src/devices/OculusManager.cpp | 132 +++++++++++++++++- interface/src/devices/OculusManager.h | 21 ++- 5 files changed, 205 insertions(+), 174 deletions(-) create mode 100644 interface/resources/shaders/oculus.frag diff --git a/interface/resources/shaders/oculus.frag b/interface/resources/shaders/oculus.frag new file mode 100644 index 0000000000..3e7d1a4c3e --- /dev/null +++ b/interface/resources/shaders/oculus.frag @@ -0,0 +1,36 @@ +#version 120 + +// +// oculus.frag +// fragment shader +// +// Created by Andrzej Kapolka on 11/26/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// +// this shader is an adaptation (HLSL -> GLSL, removed conditional) of the one in the Oculus sample +// code (Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp), which is under the Apache license +// (http://www.apache.org/licenses/LICENSE-2.0) +// + +uniform sampler2D texture; + +uniform vec2 lensCenter; +uniform vec2 screenCenter; +uniform vec2 scale; +uniform vec2 scaleIn; +uniform vec4 hmdWarpParam; + +vec2 hmdWarp(vec2 in01) { + vec2 theta = (in01 - lensCenter) * scaleIn; + float rSq = theta.x * theta.x + theta.y * theta.y; + vec2 theta1 = theta * (hmdWarpParam.x + hmdWarpParam.y * rSq + + hmdWarpParam.z * rSq * rSq + hmdWarpParam.w * rSq * rSq * rSq); + return lensCenter + scale * theta1; +} + +void main(void) { + vec2 tc = hmdWarp(gl_TexCoord[0].st); + vec2 below = step(screenCenter.st + vec2(-0.25, -0.5), tc.st); + vec2 above = vec2(1.0, 1.0) - step(screenCenter.st + vec2(0.25, 0.5), tc.st); + gl_FragColor = mix(vec4(0.0, 0.0, 0.0, 1.0), texture2D(texture, tc), above.s * above.t * below.s * below.t); +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c1fc39de41..3681541244 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -133,8 +133,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _lookatIndicatorScale(1.0f), _perfStatsOn(false), _chatEntryOn(false), - _oculusProgram(0), - _oculusDistortionScale(1.25), #ifndef _WIN32 _audio(&_audioScope, STARTUP_JITTER_SAMPLES), #endif @@ -252,7 +250,6 @@ Application::~Application() { VoxelNode::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown delete Menu::getInstance(); - delete _oculusProgram; delete _settings; delete _followMode; delete _glWidget; @@ -429,7 +426,7 @@ void Application::paintGL() { } if (OculusManager::isConnected()) { - displayOculus(whichCamera); + OculusManager::display(whichCamera); } else { _glowEffect.prepare(); @@ -520,14 +517,11 @@ void Application::paintGL() { } void Application::resetCamerasOnResizeGL(Camera& camera, int width, int height) { - float aspectRatio = ((float)width/(float)height); // based on screen resize - if (OculusManager::isConnected()) { - // more magic numbers; see Oculus SDK docs, p. 32 - camera.setAspectRatio(aspectRatio *= 0.5); - camera.setFieldOfView(2 * atan((0.0468 * _oculusDistortionScale) / 0.041) * (180 / PIf)); + OculusManager::configureCamera(camera, width, height); + } else { - camera.setAspectRatio(aspectRatio); + camera.setAspectRatio((float)width / height); camera.setFieldOfView(Menu::getInstance()->getFieldOfView()); } } @@ -2860,146 +2854,7 @@ void Application::updateShadowMap() { glViewport(0, 0, _glWidget->width(), _glWidget->height()); } - -// this shader is an adaptation (HLSL -> GLSL, removed conditional) of the one in the Oculus sample -// code (Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp), which is under the Apache license -// (http://www.apache.org/licenses/LICENSE-2.0) -static const char* DISTORTION_FRAGMENT_SHADER = - "#version 120\n" - "uniform sampler2D texture;" - "uniform vec2 lensCenter;" - "uniform vec2 screenCenter;" - "uniform vec2 scale;" - "uniform vec2 scaleIn;" - "uniform vec4 hmdWarpParam;" - "vec2 hmdWarp(vec2 in01) {" - " vec2 theta = (in01 - lensCenter) * scaleIn;" - " float rSq = theta.x * theta.x + theta.y * theta.y;" - " vec2 theta1 = theta * (hmdWarpParam.x + hmdWarpParam.y * rSq + " - " hmdWarpParam.z * rSq * rSq + hmdWarpParam.w * rSq * rSq * rSq);" - " return lensCenter + scale * theta1;" - "}" - "void main(void) {" - " vec2 tc = hmdWarp(gl_TexCoord[0].st);" - " vec2 below = step(screenCenter.st + vec2(-0.25, -0.5), tc.st);" - " vec2 above = vec2(1.0, 1.0) - step(screenCenter.st + vec2(0.25, 0.5), tc.st);" - " gl_FragColor = mix(vec4(0.0, 0.0, 0.0, 1.0), texture2D(texture, tc), " - " above.s * above.t * below.s * below.t);" - "}"; -void Application::displayOculus(Camera& whichCamera) { - _glowEffect.prepare(); - - // magic numbers ahoy! in order to avoid pulling in the Oculus utility library that calculates - // the rendering parameters from the hardware stats, i just folded their calculations into - // constants using the stats for the current-model hardware as contained in the SDK file - // LibOVR/Src/Util/Util_Render_Stereo.cpp - - // eye - - // render the left eye view to the left side of the screen - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glTranslatef(0.151976, 0, 0); // +h, see Oculus SDK docs p. 26 - gluPerspective(whichCamera.getFieldOfView(), whichCamera.getAspectRatio(), - whichCamera.getNearClip(), whichCamera.getFarClip()); - - glViewport(0, 0, _glWidget->width() / 2, _glWidget->height()); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glTranslatef(0.032, 0, 0); // dip/2, see p. 27 - - displaySide(whichCamera); - - // and the right eye to the right side - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glTranslatef(-0.151976, 0, 0); // -h - gluPerspective(whichCamera.getFieldOfView(), whichCamera.getAspectRatio(), - whichCamera.getNearClip(), whichCamera.getFarClip()); - - glViewport(_glWidget->width() / 2, 0, _glWidget->width() / 2, _glWidget->height()); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(-0.032, 0, 0); - - displaySide(whichCamera); - - glPopMatrix(); - - // restore our normal viewport - glViewport(0, 0, _glWidget->width(), _glWidget->height()); - - QOpenGLFramebufferObject* fbo = _glowEffect.render(true); - glBindTexture(GL_TEXTURE_2D, fbo->texture()); - - if (_oculusProgram == 0) { - _oculusProgram = new ProgramObject(); - _oculusProgram->addShaderFromSourceCode(QGLShader::Fragment, DISTORTION_FRAGMENT_SHADER); - _oculusProgram->link(); - - _textureLocation = _oculusProgram->uniformLocation("texture"); - _lensCenterLocation = _oculusProgram->uniformLocation("lensCenter"); - _screenCenterLocation = _oculusProgram->uniformLocation("screenCenter"); - _scaleLocation = _oculusProgram->uniformLocation("scale"); - _scaleInLocation = _oculusProgram->uniformLocation("scaleIn"); - _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluOrtho2D(0, _glWidget->width(), 0, _glWidget->height()); - glDisable(GL_DEPTH_TEST); - - // for reference on setting these values, see SDK file Samples/OculusRoomTiny/RenderTiny_Device.cpp - - float scaleFactor = 1.0 / _oculusDistortionScale; - float aspectRatio = (_glWidget->width() * 0.5) / _glWidget->height(); - - glDisable(GL_BLEND); - _oculusProgram->bind(); - _oculusProgram->setUniformValue(_textureLocation, 0); - _oculusProgram->setUniformValue(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 - _oculusProgram->setUniformValue(_screenCenterLocation, 0.25, 0.5); - _oculusProgram->setUniformValue(_scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); - _oculusProgram->setUniformValue(_scaleInLocation, 4, 2 / aspectRatio); - _oculusProgram->setUniformValue(_hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); - - glColor3f(1, 0, 1); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2f(0, 0); - glTexCoord2f(0.5, 0); - glVertex2f(_glWidget->width()/2, 0); - glTexCoord2f(0.5, 1); - glVertex2f(_glWidget->width() / 2, _glWidget->height()); - glTexCoord2f(0, 1); - glVertex2f(0, _glWidget->height()); - glEnd(); - - _oculusProgram->setUniformValue(_lensCenterLocation, 0.787994, 0.5); - _oculusProgram->setUniformValue(_screenCenterLocation, 0.75, 0.5); - - glBegin(GL_QUADS); - glTexCoord2f(0.5, 0); - glVertex2f(_glWidget->width() / 2, 0); - glTexCoord2f(1, 0); - glVertex2f(_glWidget->width(), 0); - glTexCoord2f(1, 1); - glVertex2f(_glWidget->width(), _glWidget->height()); - glTexCoord2f(0.5, 1); - glVertex2f(_glWidget->width() / 2, _glWidget->height()); - glEnd(); - - glEnable(GL_BLEND); - glBindTexture(GL_TEXTURE_2D, 0); - _oculusProgram->release(); - - glPopMatrix(); -} - const GLfloat WHITE_SPECULAR_COLOR[] = { 1.0f, 1.0f, 1.0f, 1.0f }; const GLfloat NO_SPECULAR_COLOR[] = { 0.0f, 0.0f, 0.0f, 1.0f }; @@ -3022,18 +2877,6 @@ void Application::setupWorldLight() { glMateriali(GL_FRONT, GL_SHININESS, 96); } -void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { - glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix); - glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y, - translation.z + _viewMatrixTranslation.z); -} - -void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, - float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { - - _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, near, far, nearClipPlane, farClipPlane); -} - void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); // transform by eye offset @@ -3277,6 +3120,18 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } } +void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { + glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix); + glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y, + translation.z + _viewMatrixTranslation.z); +} + +void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, + float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { + + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, near, far, nearClipPlane, farClipPlane); +} + void Application::displayOverlay() { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()"); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4695a1bf80..2213045bc9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -155,6 +155,8 @@ public: void setupWorldLight(); + void displaySide(Camera& whichCamera, bool selfAvatarOnly = false); + /// Loads a view matrix that incorporates the specified model translation without the precision issues that can /// result from matrix multiplication at high translation magnitudes. void loadTranslatedViewMatrix(const glm::vec3& translation); @@ -272,8 +274,6 @@ private: glm::vec3 getSunDirection(); void updateShadowMap(); - void displayOculus(Camera& whichCamera); - void displaySide(Camera& whichCamera, bool selfAvatarOnly = false); void displayOverlay(); void displayStats(); void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false); @@ -416,15 +416,6 @@ private: ChatEntry _chatEntry; // chat entry field bool _chatEntryOn; // Whether to show the chat entry - ProgramObject* _oculusProgram; // The GLSL program containing the distortion shader - float _oculusDistortionScale; // Controls the Oculus field of view - int _textureLocation; - int _lensCenterLocation; - int _screenCenterLocation; - int _scaleLocation; - int _scaleInLocation; - int _hmdWarpParamLocation; - GeometryCache _geometryCache; TextureCache _textureCache; diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 68023e84e4..e82c84c324 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -6,20 +6,33 @@ // Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // +#include + #include +#include "Application.h" +#include "InterfaceConfig.h" #include "OculusManager.h" using namespace OVR; +using namespace OVR::Util::Render; +ProgramObject OculusManager::_program; +int OculusManager::_textureLocation; +int OculusManager::_lensCenterLocation; +int OculusManager::_screenCenterLocation; +int OculusManager::_scaleLocation; +int OculusManager::_scaleInLocation; +int OculusManager::_hmdWarpParamLocation; bool OculusManager::_isConnected = false; +float OculusManager::_yawOffset = 0; #ifdef HAVE_LIBOVR Ptr OculusManager::_deviceManager; Ptr OculusManager::_hmdDevice; Ptr OculusManager::_sensorDevice; SensorFusion* OculusManager::_sensorFusion; -float OculusManager::_yawOffset = 0; +StereoConfig OculusManager::_stereoConfig; #endif void OculusManager::connect() { @@ -34,10 +47,127 @@ void OculusManager::connect() { _sensorDevice = *_hmdDevice->GetSensor(); _sensorFusion = new SensorFusion; _sensorFusion->AttachToSensor(_sensorDevice); + + switchToResourcesParentIfRequired(); + _program.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/oculus.frag"); + _program.link(); + + _textureLocation = _program.uniformLocation("texture"); + _lensCenterLocation = _program.uniformLocation("lensCenter"); + _screenCenterLocation = _program.uniformLocation("screenCenter"); + _scaleLocation = _program.uniformLocation("scale"); + _scaleInLocation = _program.uniformLocation("scaleIn"); + _hmdWarpParamLocation = _program.uniformLocation("hmdWarpParam"); } #endif } +void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { +#ifdef HAVE_LIBOVR + _stereoConfig.SetFullViewport(Viewport(0, 0, screenWidth, screenHeight)); + camera.setAspectRatio(_stereoConfig.GetAspect()); + camera.setFieldOfView(_stereoConfig.GetYFOVDegrees()); +#endif +} + +void OculusManager::display(Camera& whichCamera) { +#ifdef HAVE_LIBOVR + Application::getInstance()->getGlowEffect()->prepare(); + + // render the left eye view to the left side of the screen + const StereoEyeParams& leftEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Left); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0.151976, 0, 0); // +h, see Oculus SDK docs p. 26 + gluPerspective(whichCamera.getFieldOfView(), whichCamera.getAspectRatio(), + whichCamera.getNearClip(), whichCamera.getFarClip()); + + glViewport(leftEyeParams.VP.x, leftEyeParams.VP.y, leftEyeParams.VP.w, leftEyeParams.VP.h); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTranslatef(0.032, 0, 0); // dip/2, see p. 27 + + Application::getInstance()->displaySide(whichCamera); + + // and the right eye to the right side + const StereoEyeParams& rightEyeParams = _stereoConfig.GetEyeRenderParams(StereoEye_Right); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glTranslatef(-0.151976, 0, 0); // -h + gluPerspective(whichCamera.getFieldOfView(), whichCamera.getAspectRatio(), + whichCamera.getNearClip(), whichCamera.getFarClip()); + + glViewport(rightEyeParams.VP.x, rightEyeParams.VP.y, rightEyeParams.VP.w, rightEyeParams.VP.h); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(-0.032, 0, 0); + + Application::getInstance()->displaySide(whichCamera); + + glPopMatrix(); + + // restore our normal viewport + const Viewport& fullViewport = _stereoConfig.GetFullViewport(); + glViewport(fullViewport.x, fullViewport.y, fullViewport.w, fullViewport.h); + + QOpenGLFramebufferObject* fbo = Application::getInstance()->getGlowEffect()->render(true); + glBindTexture(GL_TEXTURE_2D, fbo->texture()); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(fullViewport.x, fullViewport.x + fullViewport.w, fullViewport.y, fullViewport.y + fullViewport.h); + glDisable(GL_DEPTH_TEST); + + // for reference on setting these values, see SDK file Samples/OculusRoomTiny/RenderTiny_Device.cpp + + float scaleFactor = 1.0 / _stereoConfig.GetDistortionScale(); + float aspectRatio = _stereoConfig.GetAspect(); + + glDisable(GL_BLEND); + _program.bind(); + _program.setUniformValue(_textureLocation, 0); + _program.setUniformValue(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 + _program.setUniformValue(_screenCenterLocation, 0.25, 0.5); + _program.setUniformValue(_scaleLocation, 0.25 * scaleFactor, 0.5 * scaleFactor * aspectRatio); + _program.setUniformValue(_scaleInLocation, 4, 2 / aspectRatio); + _program.setUniformValue(_hmdWarpParamLocation, 1.0, 0.22, 0.24, 0); + + glColor3f(1, 0, 1); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(0, 0); + glTexCoord2f(0.5, 0); + glVertex2f(leftEyeParams.VP.w, 0); + glTexCoord2f(0.5, 1); + glVertex2f(leftEyeParams.VP.w, leftEyeParams.VP.h); + glTexCoord2f(0, 1); + glVertex2f(0, leftEyeParams.VP.h); + glEnd(); + + _program.setUniformValue(_lensCenterLocation, 0.787994, 0.5); + _program.setUniformValue(_screenCenterLocation, 0.75, 0.5); + + glBegin(GL_QUADS); + glTexCoord2f(0.5, 0); + glVertex2f(leftEyeParams.VP.w, 0); + glTexCoord2f(1, 0); + glVertex2f(fullViewport.w, 0); + glTexCoord2f(1, 1); + glVertex2f(fullViewport.w, leftEyeParams.VP.h); + glTexCoord2f(0.5, 1); + glVertex2f(leftEyeParams.VP.w, leftEyeParams.VP.h); + glEnd(); + + glEnable(GL_BLEND); + glBindTexture(GL_TEXTURE_2D, 0); + _program.release(); + + glPopMatrix(); +#endif +} + void OculusManager::reset() { #ifdef HAVE_LIBOVR _sensorFusion->Reset(); diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h index c50e665f30..7ba0a2e93a 100644 --- a/interface/src/devices/OculusManager.h +++ b/interface/src/devices/OculusManager.h @@ -10,25 +10,44 @@ #define __hifi__OculusManager__ #include + #include +#include "renderer/ProgramObject.h" + +class Camera; + +/// Handles interaction with the Oculus Rift. class OculusManager { public: static void connect(); static bool isConnected() { return _isConnected; } + static void configureCamera(Camera& camera, int screenWidth, int screenHeight); + + static void display(Camera& whichCamera); + static void reset(); static void getEulerAngles(float& yaw, float& pitch, float& roll); static void updateYawOffset(); -private: + +private: + static ProgramObject _program; + static int _textureLocation; + static int _lensCenterLocation; + static int _screenCenterLocation; + static int _scaleLocation; + static int _scaleInLocation; + static int _hmdWarpParamLocation; static bool _isConnected; static OVR::Ptr _deviceManager; static OVR::Ptr _hmdDevice; static OVR::Ptr _sensorDevice; static OVR::SensorFusion* _sensorFusion; + static OVR::Util::Render::StereoConfig _stereoConfig; static float _yawOffset; };