Moved Oculus code out of Application, started on using StereoConfig to get

actual values to replace the magic numbers.
This commit is contained in:
Andrzej Kapolka 2013-11-26 11:59:06 -08:00
parent 1aaf6f2620
commit c5406c47a6
5 changed files with 205 additions and 174 deletions

View file

@ -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);
}

View file

@ -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()");

View file

@ -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;

View file

@ -6,20 +6,33 @@
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
//
#include <QOpenGLFramebufferObject>
#include <glm/glm.hpp>
#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<DeviceManager> OculusManager::_deviceManager;
Ptr<HMDDevice> OculusManager::_hmdDevice;
Ptr<SensorDevice> 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();

View file

@ -10,25 +10,44 @@
#define __hifi__OculusManager__
#include <iostream>
#include <OVR.h>
#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<OVR::DeviceManager> _deviceManager;
static OVR::Ptr<OVR::HMDDevice> _hmdDevice;
static OVR::Ptr<OVR::SensorDevice> _sensorDevice;
static OVR::SensorFusion* _sensorFusion;
static OVR::Util::Render::StereoConfig _stereoConfig;
static float _yawOffset;
};