From d63bb3afaae15e2d027d35dca8fcc18b0f6c3af3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Aug 2013 15:44:57 -0700 Subject: [PATCH] Fixed glow/ambient occlusion with Oculus. --- .../resources/shaders/ambient_occlusion.frag | 3 +- interface/src/Application.cpp | 45 +++++++------------ interface/src/Application.h | 1 - interface/src/OculusManager.cpp | 1 + .../src/renderer/AmbientOcclusionEffect.cpp | 18 +++++--- interface/src/renderer/GlowEffect.cpp | 36 ++++++++++++++- interface/src/renderer/GlowEffect.h | 4 +- interface/src/renderer/RenderUtil.cpp | 10 ++--- interface/src/renderer/RenderUtil.h | 4 +- 9 files changed, 74 insertions(+), 48 deletions(-) diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index a62d1d3a71..4e87ac3221 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -44,7 +44,8 @@ float texCoordToViewSpaceZ(vec2 texCoord) { // given a texture coordinate, returns the 3D view space coordinate vec3 texCoordToViewSpace(vec2 texCoord) { float z = texCoordToViewSpaceZ(texCoord); - return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); + return vec3(((texCoord * 2.0 - vec2(1.0 - gl_ProjectionMatrix[2][0], 1.0)) * + (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); } void main(void) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index adc5bb1b71..b606ce47eb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -112,7 +113,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _lookatIndicatorScale(1.0f), _perfStatsOn(false), _chatEntryOn(false), - _oculusTextureID(0), _oculusProgram(0), _oculusDistortionScale(1.25), #ifndef _WIN32 @@ -370,13 +370,18 @@ void Application::paintGL() { if (OculusManager::isConnected()) { displayOculus(whichCamera); + } else { + _glowEffect.prepare(); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); displaySide(whichCamera); glPopMatrix(); + _glowEffect.render(); + displayOverlay(); } @@ -400,13 +405,6 @@ void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_viewFrustumOffsetCamera, width, height); resetCamerasOnResizeGL(_myCamera, width, height); - // resize the render texture - if (OculusManager::isConnected() && _oculusTextureID != 0) { - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - // Tell our viewFrustum about this change, using the application camera loadViewFrustum(_myCamera, _viewFrustum); @@ -2056,6 +2054,8 @@ static const char* DISTORTION_FRAGMENT_SHADER = "}"; 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 @@ -2098,12 +2098,10 @@ void Application::displayOculus(Camera& whichCamera) { // restore our normal viewport glViewport(0, 0, _glWidget->width(), _glWidget->height()); - if (_oculusTextureID == 0) { - glGenTextures(1, &_oculusTextureID); - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _glWidget->width(), _glWidget->height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + 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(); @@ -2113,18 +2111,13 @@ void Application::displayOculus(Camera& whichCamera) { _screenCenterLocation = _oculusProgram->uniformLocation("screenCenter"); _scaleLocation = _oculusProgram->uniformLocation("scale"); _scaleInLocation = _oculusProgram->uniformLocation("scaleIn"); - _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); - - } else { - glBindTexture(GL_TEXTURE_2D, _oculusTextureID); + _hmdWarpParamLocation = _oculusProgram->uniformLocation("hmdWarpParam"); } - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, _glWidget->width(), _glWidget->height()); - + glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, _glWidget->width(), 0, _glWidget->height()); glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); // for reference on setting these values, see SDK file Samples/OculusRoomTiny/RenderTiny_Device.cpp @@ -2132,7 +2125,6 @@ void Application::displayOculus(Camera& whichCamera) { float aspectRatio = (_glWidget->width() * 0.5) / _glWidget->height(); glDisable(GL_BLEND); - glEnable(GL_TEXTURE_2D); _oculusProgram->bind(); _oculusProgram->setUniformValue(_textureLocation, 0); _oculusProgram->setUniformValue(_lensCenterLocation, 0.287994, 0.5); // see SDK docs, p. 29 @@ -2168,7 +2160,6 @@ void Application::displayOculus(Camera& whichCamera) { glEnd(); glEnable(GL_BLEND); - glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); _oculusProgram->release(); @@ -2229,9 +2220,6 @@ void Application::displaySide(Camera& whichCamera) { // Setup 3D lights (after the camera transform, so that they are positioned in world space) setupWorldLight(whichCamera); - // prepare the glow effect - _glowEffect.prepare(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { if (!_stars.getFileLoaded()) { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); @@ -2372,7 +2360,7 @@ void Application::displaySide(Camera& whichCamera) { _myAvatar.renderScreenTint(SCREEN_TINT_AFTER_AVATARS, whichCamera); // Render the world box - if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { renderWorldBox(); } @@ -2399,9 +2387,6 @@ void Application::displaySide(Camera& whichCamera) { } renderFollowIndicator(); - - // render the glow effect - _glowEffect.render(); } void Application::displayOverlay() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 51606ce75a..39fca6e532 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -301,7 +301,6 @@ private: ChatEntry _chatEntry; // chat entry field bool _chatEntryOn; // Whether to show the chat entry - GLuint _oculusTextureID; // The texture to which we render for Oculus distortion ProgramObject* _oculusProgram; // The GLSL program containing the distortion shader float _oculusDistortionScale; // Controls the Oculus field of view int _textureLocation; diff --git a/interface/src/OculusManager.cpp b/interface/src/OculusManager.cpp index 17775b9f9c..046e1684fb 100644 --- a/interface/src/OculusManager.cpp +++ b/interface/src/OculusManager.cpp @@ -46,6 +46,7 @@ void OculusManager::updateYawOffset() { } void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { + yaw = pitch = roll = 0.0f; #ifdef __APPLE__ _sensorFusion.GetOrientation().GetEulerAngles(&yaw, &pitch, &roll); diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 309816191b..2169ec00af 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -111,11 +111,17 @@ void AmbientOcclusionEffect::render() { _occlusionProgram->setUniformValue(_farLocation, farVal); _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); _occlusionProgram->setUniformValue(_rightTopLocation, right, top); - QSize size = Application::getInstance()->getGLWidget()->size(); - _occlusionProgram->setUniformValue(_noiseScaleLocation, size.width() / (float)ROTATION_WIDTH, - size.height() / (float)ROTATION_HEIGHT); + QSize widgetSize = Application::getInstance()->getGLWidget()->size(); + _occlusionProgram->setUniformValue(_noiseScaleLocation, widgetSize.width() / (float)ROTATION_WIDTH, + widgetSize.height() / (float)ROTATION_HEIGHT); - renderFullscreenQuad(); + int viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + const int VIEWPORT_X_INDEX = 0; + const int VIEWPORT_WIDTH_INDEX = 2; + float sMin = viewport[VIEWPORT_X_INDEX] / (float)widgetSize.width(); + float sMax = (viewport[VIEWPORT_X_INDEX] + viewport[VIEWPORT_WIDTH_INDEX]) / (float)widgetSize.width(); + renderFullscreenQuad(sMin, sMax); _occlusionProgram->release(); @@ -133,9 +139,9 @@ void AmbientOcclusionEffect::render() { glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); _blurProgram->bind(); - _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / size.width(), 1.0f / size.height()); + _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / widgetSize.width(), 1.0f / widgetSize.height()); - renderFullscreenQuad(); + renderFullscreenQuad(sMin, sMax); _blurProgram->release(); diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 936364f8c0..e35896c975 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -78,7 +78,19 @@ void GlowEffect::end() { glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); } -void GlowEffect::render() { +static void maybeBind(QOpenGLFramebufferObject* fbo) { + if (fbo != NULL) { + fbo->bind(); + } +} + +static void maybeRelease(QOpenGLFramebufferObject* fbo) { + if (fbo != NULL) { + fbo->release(); + } +} + +QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); @@ -94,23 +106,29 @@ void GlowEffect::render() { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); + QOpenGLFramebufferObject* destFBO = toTexture ? + Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject() : NULL; if (_isEmpty) { // copy the primary to the screen if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { - QOpenGLFramebufferObject::blitFramebuffer(NULL, primaryFBO); + QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { + maybeBind(destFBO); glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glColor3f(1.0f, 1.0f, 1.0f); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); + maybeRelease(destFBO); } } else if (_renderMode == ADD_MODE) { + maybeBind(destFBO); _addProgram->bind(); renderFullscreenQuad(); _addProgram->release(); + maybeRelease(destFBO); } else if (_renderMode == DIFFUSE_ADD_MODE) { // diffuse into the secondary/tertiary (alternating between frames) @@ -139,9 +157,14 @@ void GlowEffect::render() { // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture()); + if (toTexture) { + destFBO = oldDiffusedFBO; + } + maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); + maybeRelease(destFBO); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); @@ -163,9 +186,14 @@ void GlowEffect::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + if (toTexture) { + destFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); + } + maybeBind(destFBO); _verticalBlurAddProgram->bind(); renderFullscreenQuad(); _verticalBlurAddProgram->release(); + maybeRelease(destFBO); } else { // _renderMode == BLUR_PERSIST_ADD_MODE // render the secondary to the tertiary with horizontal blur and persistence @@ -196,9 +224,11 @@ void GlowEffect::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture()); + maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); + maybeRelease(destFBO); } glBindTexture(GL_TEXTURE_2D, 0); @@ -214,6 +244,8 @@ void GlowEffect::render() { glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); + + return destFBO; } void GlowEffect::cycleRenderMode() { diff --git a/interface/src/renderer/GlowEffect.h b/interface/src/renderer/GlowEffect.h index 73119365e8..2cf1efe9d7 100644 --- a/interface/src/renderer/GlowEffect.h +++ b/interface/src/renderer/GlowEffect.h @@ -40,7 +40,9 @@ public: void end(); /// Renders the glow effect. To be called after rendering the scene. - void render(); + /// \param toTexture whether to render to a texture, rather than to the frame buffer + /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer + QOpenGLFramebufferObject* render(bool toTexture = false); public slots: diff --git a/interface/src/renderer/RenderUtil.cpp b/interface/src/renderer/RenderUtil.cpp index 4b53fb4d12..11ec8b572c 100644 --- a/interface/src/renderer/RenderUtil.cpp +++ b/interface/src/renderer/RenderUtil.cpp @@ -8,15 +8,15 @@ #include "InterfaceConfig.h" #include "RenderUtil.h" -void renderFullscreenQuad() { +void renderFullscreenQuad(float sMin, float sMax) { glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); + glTexCoord2f(sMin, 0.0f); glVertex2f(-1.0f, -1.0f); - glTexCoord2f(1.0f, 0.0f); + glTexCoord2f(sMax, 0.0f); glVertex2f(1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); + glTexCoord2f(sMax, 1.0f); glVertex2f(1.0f, 1.0f); - glTexCoord2f(0.0f, 1.0f); + glTexCoord2f(sMin, 1.0f); glVertex2f(-1.0f, 1.0f); glEnd(); } diff --git a/interface/src/renderer/RenderUtil.h b/interface/src/renderer/RenderUtil.h index 51e31fe260..5e7e9b5d64 100644 --- a/interface/src/renderer/RenderUtil.h +++ b/interface/src/renderer/RenderUtil.h @@ -9,7 +9,7 @@ #ifndef __interface__RenderUtil__ #define __interface__RenderUtil__ -/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (0, 0) to (1, 1). -void renderFullscreenQuad(); +/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, 0) to (sMax, 1). +void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f); #endif /* defined(__interface__RenderUtil__) */