From 3ddab484e0903aa5528ca2fc65d4b5116c571bb0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 15 Aug 2013 17:52:31 -0700 Subject: [PATCH] Beginnings of ambient occlusion. Looks like an architectural drawing. --- .../resources/shaders/ambient_occlusion.frag | 11 +++- interface/src/Application.cpp | 1 + .../src/renderer/AmbientOcclusionEffect.cpp | 58 +++++++++++++++++++ .../src/renderer/AmbientOcclusionEffect.h | 13 ++++- interface/src/renderer/GlowEffect.cpp | 16 +---- interface/src/renderer/RenderUtil.cpp | 22 +++++++ interface/src/renderer/RenderUtil.h | 15 +++++ interface/src/renderer/TextureCache.cpp | 27 ++++++++- interface/src/renderer/TextureCache.h | 16 +++++ 9 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 interface/src/renderer/RenderUtil.cpp create mode 100644 interface/src/renderer/RenderUtil.h diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index 2707415646..b01f7f2db7 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -30,6 +30,13 @@ vec3 texCoordToViewSpace(vec2 texCoord) { } void main(void) { - float depth = texture2D(depthTexture, gl_TexCoord[0].st).r; - gl_FragColor = vec4(depth, depth, depth, 1.0); + float ds = dFdx(gl_TexCoord[0].s); + float dt = dFdy(gl_TexCoord[0].t); + vec3 center = texCoordToViewSpace(gl_TexCoord[0].st); + vec3 left = texCoordToViewSpace(gl_TexCoord[0].st - vec2(-ds, 0.0)) - center; + vec3 right = texCoordToViewSpace(gl_TexCoord[0].st - vec2(ds, 0.0)) - center; + vec3 up = texCoordToViewSpace(gl_TexCoord[0].st - vec2(0.0, dt)) - center; + vec3 down = texCoordToViewSpace(gl_TexCoord[0].st - vec2(0.0, -dt)) - center; + float occlusion = 0.5 - (left.z / length(left) + right.z / length(right) + up.z / length(up) + down.z / length(down)) / 8.0; + gl_FragColor = vec4(occlusion, occlusion, occlusion, 0.0); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4bf760139d..a701fde1f2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2121,6 +2121,7 @@ void Application::init() { _environment.init(); _glowEffect.init(); + _ambientOcclusionEffect.init(); _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 5aac065647..8719350ec8 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -9,8 +9,66 @@ #include #include "AmbientOcclusionEffect.h" +#include "Application.h" +#include "InterfaceConfig.h" #include "ProgramObject.h" +#include "RenderUtil.h" + +void AmbientOcclusionEffect::init() { + switchToResourcesParentIfRequired(); + + _program = new ProgramObject(); + _program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); + _program->link(); + + _nearLocation = _program->uniformLocation("near"); + _farLocation = _program->uniformLocation("far"); + _leftBottomLocation = _program->uniformLocation("leftBottom"); + _rightTopLocation = _program->uniformLocation("rightTop"); + + _program->bind(); + _program->setUniformValue("depthTexture", 0); + _program->release(); +} void AmbientOcclusionEffect::render() { + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_BLEND); + //glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); + + float left, right, bottom, top, nearVal, farVal; + glm::vec4 nearClipPlane, farClipPlane; + Application::getInstance()->getViewFrustum()->computeOffAxisFrustum( + left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + + _program->bind(); + _program->setUniformValue(_nearLocation, nearVal); + _program->setUniformValue(_farLocation, farVal); + _program->setUniformValue(_leftBottomLocation, left, bottom); + _program->setUniformValue(_rightTopLocation, right, top); + + renderFullscreenQuad(); + + _program->release(); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + glEnable(GL_BLEND); + //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/interface/src/renderer/AmbientOcclusionEffect.h b/interface/src/renderer/AmbientOcclusionEffect.h index f8e4be4edc..8fba351827 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.h +++ b/interface/src/renderer/AmbientOcclusionEffect.h @@ -9,14 +9,23 @@ #ifndef __interface__AmbientOcclusionEffect__ #define __interface__AmbientOcclusionEffect__ -#include "InterfaceConfig.h" - class ProgramObject; +/// A screen space ambient occlusion effect. class AmbientOcclusionEffect { public: + void init(); + void render(); + +private: + + ProgramObject* _program; + int _nearLocation; + int _farLocation; + int _leftBottomLocation; + int _rightTopLocation; }; #endif /* defined(__interface__AmbientOcclusionEffect__) */ diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index ce069bc20b..35d1777be3 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -13,6 +13,7 @@ #include "Application.h" #include "GlowEffect.h" #include "ProgramObject.h" +#include "RenderUtil.h" GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) { } @@ -68,19 +69,6 @@ void GlowEffect::end() { glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); } -static void renderFullscreenQuad() { - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); - glVertex2f(-1.0f, -1.0f); - glTexCoord2f(1.0f, 0.0f); - glVertex2f(1.0f, -1.0f); - glTexCoord2f(1.0f, 1.0f); - glVertex2f(1.0f, 1.0f); - glTexCoord2f(0.0f, 1.0f); - glVertex2f(-1.0f, 1.0f); - glEnd(); -} - void GlowEffect::render() { QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); @@ -95,6 +83,7 @@ void GlowEffect::render() { glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); if (_isEmpty) { // copy the primary to the screen @@ -210,6 +199,7 @@ void GlowEffect::render() { glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/interface/src/renderer/RenderUtil.cpp b/interface/src/renderer/RenderUtil.cpp new file mode 100644 index 0000000000..4b53fb4d12 --- /dev/null +++ b/interface/src/renderer/RenderUtil.cpp @@ -0,0 +1,22 @@ +// +// RenderUtil.cpp +// interface +// +// Created by Andrzej Kapolka on 8/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include "InterfaceConfig.h" +#include "RenderUtil.h" + +void renderFullscreenQuad() { + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(-1.0f, -1.0f); + glTexCoord2f(1.0f, 0.0f); + glVertex2f(1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex2f(-1.0f, 1.0f); + glEnd(); +} diff --git a/interface/src/renderer/RenderUtil.h b/interface/src/renderer/RenderUtil.h new file mode 100644 index 0000000000..51e31fe260 --- /dev/null +++ b/interface/src/renderer/RenderUtil.h @@ -0,0 +1,15 @@ +// +// RenderUtil.h +// interface +// +// Created by Andrzej Kapolka on 8/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#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(); + +#endif /* defined(__interface__RenderUtil__) */ diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index d4cc97edbf..5696475487 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -5,6 +5,9 @@ // Created by Andrzej Kapolka on 8/6/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + #include #include @@ -23,6 +26,7 @@ TextureCache::~TextureCache() { } if (_primaryFramebufferObject != NULL) { delete _primaryFramebufferObject; + glDeleteTextures(1, &_primaryDepthTextureID); } if (_secondaryFramebufferObject != NULL) { delete _secondaryFramebufferObject; @@ -60,13 +64,31 @@ GLuint TextureCache::getPermutationNormalTextureID() { QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { if (_primaryFramebufferObject == NULL) { - _primaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size(), - QOpenGLFramebufferObject::Depth); + QSize size = Application::getInstance()->getGLWidget()->size(); + _primaryFramebufferObject = new QOpenGLFramebufferObject(size); Application::getInstance()->getGLWidget()->installEventFilter(this); + + glGenTextures(1, &_primaryDepthTextureID); + glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size.width(), size.height(), + 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); + + _primaryFramebufferObject->bind(); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0); + _primaryFramebufferObject->release(); } return _primaryFramebufferObject; } +GLuint TextureCache::getPrimaryDepthTextureID() { + // ensure that the primary framebuffer object is initialized before returning the depth texture id + getPrimaryFramebufferObject(); + return _primaryDepthTextureID; +} + QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { if (_secondaryFramebufferObject == NULL) { _secondaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); @@ -89,6 +111,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) { if (_primaryFramebufferObject != NULL && _primaryFramebufferObject->size() != size) { delete _primaryFramebufferObject; _primaryFramebufferObject = NULL; + glDeleteTextures(1, &_primaryDepthTextureID); } if (_secondaryFramebufferObject != NULL && _secondaryFramebufferObject->size() != size) { delete _secondaryFramebufferObject; diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 716f087992..1f2fc96ac5 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -15,16 +15,31 @@ class QOpenGLFramebufferObject; +/// Stored cached textures, including render-to-texture targets. class TextureCache : public QObject { public: TextureCache(); ~TextureCache(); + /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture + /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and + /// the second, a set of random unit vectors to be used as noise gradients. GLuint getPermutationNormalTextureID(); + /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is + /// used for scene rendering. QOpenGLFramebufferObject* getPrimaryFramebufferObject(); + + /// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering. + GLuint getPrimaryDepthTextureID(); + + /// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full + /// screen effects. QOpenGLFramebufferObject* getSecondaryFramebufferObject(); + + /// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full + /// screen effects. QOpenGLFramebufferObject* getTertiaryFramebufferObject(); virtual bool eventFilter(QObject* watched, QEvent* event); @@ -34,6 +49,7 @@ private: GLuint _permutationNormalTextureID; QOpenGLFramebufferObject* _primaryFramebufferObject; + GLuint _primaryDepthTextureID; QOpenGLFramebufferObject* _secondaryFramebufferObject; QOpenGLFramebufferObject* _tertiaryFramebufferObject; };