From b294b33ac7ecc0c1d19b44f45833b27bd243792d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 5 Jul 2013 18:21:59 -0700 Subject: [PATCH 1/8] Started on ambient occlusion shader. --- .../resources/shaders/ambient_occlusion.frag | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 interface/resources/shaders/ambient_occlusion.frag diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag new file mode 100644 index 0000000000..2f7a322b05 --- /dev/null +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -0,0 +1,34 @@ +#version 120 + +// +// ambient_occlusion.frag +// fragment shader +// +// Created by Andrzej Kapolka on 7/5/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the depth texture +uniform sampler2D depth; + +// the distance to the near clip plane +uniform float near; + +// the distance to the far clip plane +uniform float far; + +// the left and bottom edges of the view window +uniform vec2 leftBottom; + +// the right and top edges of the view window +uniform vec2 rightTop; + +// given a texture coordinate, returns the 3D view space coordinate +vec3 texCoordToViewSpace(vec2 texCoord) { + float z = (far * near) / (texture2D(depth, texCoord).r * (far - near) - far); + return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); +} + +void main(void) { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} From 84bb2aa26518430560b66cf2bf366e6aa82016ec Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 14 Jul 2013 18:21:18 -0700 Subject: [PATCH 2/8] Started on C++ side of SSAO effect. --- .../resources/shaders/ambient_occlusion.frag | 7 +- interface/src/Application.cpp | 2 + interface/src/Application.h | 2 + .../src/renderer/AmbientOcclusionEffect.cpp | 70 +++++++++++++++++++ .../src/renderer/AmbientOcclusionEffect.h | 30 ++++++++ 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 interface/src/renderer/AmbientOcclusionEffect.cpp create mode 100644 interface/src/renderer/AmbientOcclusionEffect.h diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index 2f7a322b05..2707415646 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -9,7 +9,7 @@ // // the depth texture -uniform sampler2D depth; +uniform sampler2D depthTexture; // the distance to the near clip plane uniform float near; @@ -25,10 +25,11 @@ uniform vec2 rightTop; // given a texture coordinate, returns the 3D view space coordinate vec3 texCoordToViewSpace(vec2 texCoord) { - float z = (far * near) / (texture2D(depth, texCoord).r * (far - near) - far); + float z = (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far); return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); } void main(void) { - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + float depth = texture2D(depthTexture, gl_TexCoord[0].st).r; + gl_FragColor = vec4(depth, depth, depth, 1.0); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f70c89f3b..c67590f019 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2463,6 +2463,8 @@ void Application::displaySide(Camera& whichCamera) { // Render the world box if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { render_world_box(); } + _ambientOcclusionEffect.render(_glWidget->width(), _glWidget->height()); + // brad's frustum for debugging if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum); diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..6eaa9ee5ca 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -37,6 +37,7 @@ #include "VoxelSystem.h" #include "PacketHeaders.h" #include "Webcam.h" +#include "renderer/AmbientOcclusionEffect.h" #include "renderer/GeometryCache.h" #include "ui/ChatEntry.h" #include "ToolsPalette.h" @@ -366,6 +367,7 @@ private: int _hmdWarpParamLocation; GeometryCache _geometryCache; + AmbientOcclusionEffect _ambientOcclusionEffect; ParticleSystem _particleSystem; diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp new file mode 100644 index 0000000000..74c25235d8 --- /dev/null +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -0,0 +1,70 @@ +// +// AmbientOcclusionEffect.cpp +// interface +// +// Created by Andrzej Kapolka on 7/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "AmbientOcclusionEffect.h" +#include "ProgramObject.h" + +ProgramObject* AmbientOcclusionEffect::_program = 0; + +AmbientOcclusionEffect::AmbientOcclusionEffect() : _depthTextureID(0) { +} + +void AmbientOcclusionEffect::render(int screenWidth, int screenHeight) { + // copy the z buffer into a depth texture + if (_depthTextureID == 0) { + glGenTextures(1, &_depthTextureID); + glBindTexture(GL_TEXTURE_2D, _depthTextureID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, screenWidth, screenHeight, 0); + + } else { + glBindTexture(GL_TEXTURE_2D, _depthTextureID); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight); + } + + // now render a full screen quad with that texture + if (_program == 0) { + switchToResourcesParentIfRequired(); + _program = new ProgramObject(); + _program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); + _program->link(); + + _program->bind(); + _program->setUniformValue("depthTexture", 0); + + } else { + _program->bind(); + } + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + 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(); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + _program->release(); + glBindTexture(GL_TEXTURE_2D, 0); +} diff --git a/interface/src/renderer/AmbientOcclusionEffect.h b/interface/src/renderer/AmbientOcclusionEffect.h new file mode 100644 index 0000000000..4c05e348e6 --- /dev/null +++ b/interface/src/renderer/AmbientOcclusionEffect.h @@ -0,0 +1,30 @@ +// +// AmbientOcclusionEffect.h +// interface +// +// Created by Andrzej Kapolka on 7/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__AmbientOcclusionEffect__ +#define __interface__AmbientOcclusionEffect__ + +#include "InterfaceConfig.h" + +class ProgramObject; + +class AmbientOcclusionEffect { +public: + + AmbientOcclusionEffect(); + + void render(int screenWidth, int screenHeight); + +private: + + GLuint _depthTextureID; + + static ProgramObject* _program; +}; + +#endif /* defined(__interface__AmbientOcclusionEffect__) */ From 94e5c8d4a1192b245a65f2482a4452887e184dbc Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 15 Aug 2013 10:10:14 -0700 Subject: [PATCH 3/8] Missed a spot in the merge. --- interface/src/Application.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index a2db40123f..fbdbbc9ae5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -32,6 +32,7 @@ #include "Environment.h" #include "PacketHeaders.h" #include "ParticleSystem.h" +#include "PieMenu.h" #include "SerialInterface.h" #include "Stars.h" #include "Swatch.h" @@ -40,13 +41,9 @@ #include "VoxelFade.h" #include "VoxelSystem.h" #include "Webcam.h" -<<<<<<< HEAD -#include "renderer/AmbientOcclusionEffect.h" -======= -#include "PieMenu.h" #include "avatar/Avatar.h" #include "avatar/HandControl.h" ->>>>>>> 8238d0d380944c07a14c5fd42efa1a5d3eb468ed +#include "renderer/AmbientOcclusionEffect.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" #include "renderer/TextureCache.h" From 28d306a228d956ceb5373fd981ec7819b9f97570 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 15 Aug 2013 13:10:48 -0700 Subject: [PATCH 4/8] Remove the code here; will be replacing it based on glow effect work. --- interface/src/Application.cpp | 2 +- .../src/renderer/AmbientOcclusionEffect.cpp | 58 +------------------ .../src/renderer/AmbientOcclusionEffect.h | 10 +--- 3 files changed, 4 insertions(+), 66 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0beb7fedd0..4461443287 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3193,7 +3193,7 @@ void Application::displaySide(Camera& whichCamera) { // Render the world box if (!_lookingInMirror->isChecked() && _renderStatsOn->isChecked()) { renderWorldBox(); } - _ambientOcclusionEffect.render(_glWidget->width(), _glWidget->height()); + _ambientOcclusionEffect.render(); // brad's frustum for debugging if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum); diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 74c25235d8..5aac065647 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -11,60 +11,6 @@ #include "AmbientOcclusionEffect.h" #include "ProgramObject.h" -ProgramObject* AmbientOcclusionEffect::_program = 0; - -AmbientOcclusionEffect::AmbientOcclusionEffect() : _depthTextureID(0) { -} - -void AmbientOcclusionEffect::render(int screenWidth, int screenHeight) { - // copy the z buffer into a depth texture - if (_depthTextureID == 0) { - glGenTextures(1, &_depthTextureID); - glBindTexture(GL_TEXTURE_2D, _depthTextureID); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, screenWidth, screenHeight, 0); - - } else { - glBindTexture(GL_TEXTURE_2D, _depthTextureID); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight); - } - - // now render a full screen quad with that texture - if (_program == 0) { - switchToResourcesParentIfRequired(); - _program = new ProgramObject(); - _program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); - _program->link(); - - _program->bind(); - _program->setUniformValue("depthTexture", 0); - - } else { - _program->bind(); - } - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - 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(); - - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - _program->release(); - glBindTexture(GL_TEXTURE_2D, 0); +void AmbientOcclusionEffect::render() { + } diff --git a/interface/src/renderer/AmbientOcclusionEffect.h b/interface/src/renderer/AmbientOcclusionEffect.h index 4c05e348e6..f8e4be4edc 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.h +++ b/interface/src/renderer/AmbientOcclusionEffect.h @@ -16,15 +16,7 @@ class ProgramObject; class AmbientOcclusionEffect { public: - AmbientOcclusionEffect(); - - void render(int screenWidth, int screenHeight); - -private: - - GLuint _depthTextureID; - - static ProgramObject* _program; + void render(); }; #endif /* defined(__interface__AmbientOcclusionEffect__) */ From 3ddab484e0903aa5528ca2fc65d4b5116c571bb0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 15 Aug 2013 17:52:31 -0700 Subject: [PATCH 5/8] 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; }; From b41fa1e03ce5045fa13b98f329d6b0b2e0112457 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 16 Aug 2013 17:26:47 -0700 Subject: [PATCH 6/8] Basic ambient occlusion effect up and running; needs tweaking and optimization. --- .../resources/shaders/ambient_occlusion.frag | 42 ++++-- .../resources/shaders/ambient_occlusion.vert | 14 ++ .../resources/shaders/occlusion_blur.frag | 25 ++++ .../src/renderer/AmbientOcclusionEffect.cpp | 126 +++++++++++++----- .../src/renderer/AmbientOcclusionEffect.h | 9 +- interface/src/renderer/GlowEffect.cpp | 2 +- 6 files changed, 177 insertions(+), 41 deletions(-) create mode 100644 interface/resources/shaders/ambient_occlusion.vert create mode 100644 interface/resources/shaders/occlusion_blur.frag diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index b01f7f2db7..b59c87d797 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -11,6 +11,13 @@ // the depth texture uniform sampler2D depthTexture; +// the random rotation texture +uniform sampler2D rotationTexture; + +// the sample kernel containing the unit offset vectors +const int SAMPLE_KERNEL_SIZE = 16; +uniform vec3 sampleKernel[SAMPLE_KERNEL_SIZE]; + // the distance to the near clip plane uniform float near; @@ -23,20 +30,37 @@ uniform vec2 leftBottom; // the right and top edges of the view window uniform vec2 rightTop; +// the radius of the effect +uniform float radius; + +// the scale for the noise texture +uniform vec2 noiseScale; + +// given a texture coordinate, returns the 3D view space z coordinate +float texCoordToViewSpaceZ(vec2 texCoord) { + return (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far); +} + // given a texture coordinate, returns the 3D view space coordinate vec3 texCoordToViewSpace(vec2 texCoord) { - float z = (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far); + float z = texCoordToViewSpaceZ(texCoord); return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); } void main(void) { - float ds = dFdx(gl_TexCoord[0].s); - float dt = dFdy(gl_TexCoord[0].t); + vec3 rotationX = texture2D(rotationTexture, gl_TexCoord[0].st * noiseScale).rgb; + vec3 rotationY = normalize(cross(rotationX, vec3(0.0, 0.0, 1.0))); + mat3 rotation = mat3(rotationX, rotationY, cross(rotationX, rotationY)); + 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); + + float occlusion = 4.0; + for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { + vec3 offset = center + rotation * (radius * sampleKernel[i]); + vec4 projected = gl_ProjectionMatrix * vec4(offset, 1.0); + float depth = texCoordToViewSpaceZ(projected.xy * 0.5 / projected.w + vec2(0.5, 0.5)); + occlusion += 1.0 - step(offset.z, depth); // * step(abs(center.z - depth), radius); + } + + gl_FragColor = vec4(occlusion, occlusion, occlusion, 0.0) / 16.0; } diff --git a/interface/resources/shaders/ambient_occlusion.vert b/interface/resources/shaders/ambient_occlusion.vert new file mode 100644 index 0000000000..ca6af718bd --- /dev/null +++ b/interface/resources/shaders/ambient_occlusion.vert @@ -0,0 +1,14 @@ +#version 120 + +// +// ambient_occlusion.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/16/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +void main(void) { + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = gl_Vertex; +} diff --git a/interface/resources/shaders/occlusion_blur.frag b/interface/resources/shaders/occlusion_blur.frag new file mode 100644 index 0000000000..2ee5eaf2cb --- /dev/null +++ b/interface/resources/shaders/occlusion_blur.frag @@ -0,0 +1,25 @@ +#version 120 + +// +// occlusion_blur.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/16/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the original texture +uniform sampler2D originalTexture; + +void main(void) { + float ds = dFdx(gl_TexCoord[0].s); + float dt = dFdy(gl_TexCoord[0].t); + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + sum += texture2D(originalTexture, gl_TexCoord[0].st + + vec2(ds, dt) * vec2(-2.0 + float(i), -2.0 + float(j))); + } + } + gl_FragColor = sum / 16.0; +} diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 8719350ec8..83ed2fdbec 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -6,6 +6,13 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include + +#include + #include #include "AmbientOcclusionEffect.h" @@ -14,61 +21,120 @@ #include "ProgramObject.h" #include "RenderUtil.h" +const int ROTATION_WIDTH = 4; +const int ROTATION_HEIGHT = 4; + void AmbientOcclusionEffect::init() { switchToResourcesParentIfRequired(); - _program = new ProgramObject(); - _program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); - _program->link(); + _occlusionProgram = new ProgramObject(); + _occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert"); + _occlusionProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); + _occlusionProgram->link(); - _nearLocation = _program->uniformLocation("near"); - _farLocation = _program->uniformLocation("far"); - _leftBottomLocation = _program->uniformLocation("leftBottom"); - _rightTopLocation = _program->uniformLocation("rightTop"); + _blurProgram = new ProgramObject(); + _blurProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert"); + _blurProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/occlusion_blur.frag"); + _blurProgram->link(); - _program->bind(); - _program->setUniformValue("depthTexture", 0); - _program->release(); + _blurProgram->bind(); + _blurProgram->setUniformValue("originalTexture", 0); + _blurProgram->release(); + + // create the sample kernel: an array of spherically distributed offset vectors + const int SAMPLE_KERNEL_SIZE = 16; + QVector3D sampleKernel[SAMPLE_KERNEL_SIZE]; + for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { + glm::vec3 vector = glm::ballRand(1.0f); + sampleKernel[i] = QVector3D(vector.x, vector.y, vector.z); + } + + _occlusionProgram->bind(); + _occlusionProgram->setUniformValue("depthTexture", 0); + _occlusionProgram->setUniformValue("rotationTexture", 1); + _occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE); + _occlusionProgram->setUniformValue("radius", 0.1f); + _occlusionProgram->release(); + + _nearLocation = _occlusionProgram->uniformLocation("near"); + _farLocation = _occlusionProgram->uniformLocation("far"); + _leftBottomLocation = _occlusionProgram->uniformLocation("leftBottom"); + _rightTopLocation = _occlusionProgram->uniformLocation("rightTop"); + _noiseScaleLocation = _occlusionProgram->uniformLocation("noiseScale"); + + // generate the random rotation texture + glGenTextures(1, &_rotationTextureID); + glBindTexture(GL_TEXTURE_2D, _rotationTextureID); + const int ELEMENTS_PER_PIXEL = 3; + unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL]; + unsigned char* rotation = rotationData; + for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) { + glm::vec3 randvec = glm::sphericalRand(1.0f); + *rotation++ = ((randvec.x + 1.0f) / 2.0f) * 255.0f; + *rotation++ = ((randvec.y + 1.0f) / 2.0f) * 255.0f; + *rotation++ = ((randvec.z + 1.0f) / 2.0f) * 255.0f; + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData); + 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); } 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()); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _rotationTextureID); + + // render with the occlusion shader to the secondary buffer + QOpenGLFramebufferObject* secondaryFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); + secondaryFBO->bind(); + 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); + _occlusionProgram->bind(); + _occlusionProgram->setUniformValue(_nearLocation, nearVal); + _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); renderFullscreenQuad(); - _program->release(); + _occlusionProgram->release(); - glPopMatrix(); + secondaryFBO->release(); + + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + + // now render secondary to primary with 4x4 blur + Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glEnable(GL_BLEND); - //glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); + + glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + + _blurProgram->bind(); + + renderFullscreenQuad(); + + _blurProgram->release(); + + glBindTexture(GL_TEXTURE_2D, 0); + + //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 8fba351827..4891a6eb2c 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.h +++ b/interface/src/renderer/AmbientOcclusionEffect.h @@ -9,6 +9,8 @@ #ifndef __interface__AmbientOcclusionEffect__ #define __interface__AmbientOcclusionEffect__ +#include "InterfaceConfig.h" + class ProgramObject; /// A screen space ambient occlusion effect. @@ -21,11 +23,16 @@ public: private: - ProgramObject* _program; + ProgramObject* _occlusionProgram; int _nearLocation; int _farLocation; int _leftBottomLocation; int _rightTopLocation; + int _noiseScaleLocation; + + ProgramObject* _blurProgram; + + GLuint _rotationTextureID; }; #endif /* defined(__interface__AmbientOcclusionEffect__) */ diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 35d1777be3..85c4eb27b2 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -5,7 +5,7 @@ // Created by Andrzej Kapolka on 8/7/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// include this before QGLWidget, which includes an earlier version of OpenGL +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include "InterfaceConfig.h" #include From e7dab88d69269ac7a778543676a436eae146ba73 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Aug 2013 10:32:56 -0700 Subject: [PATCH 7/8] Square vector lengths to bunch them up towards the center, add a minimum length, include the URL of the SSAO tutorial. --- interface/src/renderer/AmbientOcclusionEffect.cpp | 7 ++++++- interface/src/renderer/AmbientOcclusionEffect.h | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 83ed2fdbec..ff86615b26 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -45,7 +45,12 @@ void AmbientOcclusionEffect::init() { const int SAMPLE_KERNEL_SIZE = 16; QVector3D sampleKernel[SAMPLE_KERNEL_SIZE]; for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { - glm::vec3 vector = glm::ballRand(1.0f); + // square the length in order to increase density towards the center + glm::vec3 vector = glm::sphericalRand(1.0f); + float scale = randFloat(); + const float MIN_VECTOR_LENGTH = 0.01f; + const float MAX_VECTOR_LENGTH = 1.0f; + vector *= glm::mix(MIN_VECTOR_LENGTH, MAX_VECTOR_LENGTH, scale * scale); sampleKernel[i] = QVector3D(vector.x, vector.y, vector.z); } diff --git a/interface/src/renderer/AmbientOcclusionEffect.h b/interface/src/renderer/AmbientOcclusionEffect.h index 4891a6eb2c..d41bb65381 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.h +++ b/interface/src/renderer/AmbientOcclusionEffect.h @@ -13,7 +13,8 @@ class ProgramObject; -/// A screen space ambient occlusion effect. +/// A screen space ambient occlusion effect. See John Chapman's tutorial at +/// http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html for reference. class AmbientOcclusionEffect { public: From dec4a4c4222bc9d26ec67a60604494ab9fa1f9f9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 19 Aug 2013 11:45:43 -0700 Subject: [PATCH 8/8] Added toggle for ambient occlusion (defaults to off). --- interface/src/Application.cpp | 5 ++++- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc7fd14d49..47248ecaeb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2378,7 +2378,10 @@ void Application::displaySide(Camera& whichCamera) { renderWorldBox(); } - _ambientOcclusionEffect.render(); + // render the ambient occlusion effect if enabled + if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { + _ambientOcclusionEffect.render(); + } // brad's frustum for debugging if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 56317b86a2..d49d322f34 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -157,6 +157,7 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); + addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FrameTimer); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors); addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtIndicator, 0, true); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2d871fd890..e7ecbcaf79 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -107,6 +107,7 @@ private: namespace MenuOption { + const QString AmbientOcclusion = "Ambient Occlusion"; const QString Avatars = "Avatars"; const QString AvatarAsBalls = "Avatar as Balls"; const QString Atmosphere = "Atmosphere";