Basic screen space ambient occlusion effect. Defaults to off, because at the moment it slows things down substantially.
Unified · Split
| @@ -0,0 +1,66 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // ambient_occlusion.frag | ||
| 5 | // fragment shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 7/5/13. | ||
| 8 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 9 | // | ||
| 10 | |||
| 11 | // the depth texture | ||
| 12 | uniform sampler2D depthTexture; | ||
| 13 | |||
| 14 | // the random rotation texture | ||
| 15 | uniform sampler2D rotationTexture; | ||
| 16 | |||
| 17 | // the sample kernel containing the unit offset vectors | ||
| 18 | const int SAMPLE_KERNEL_SIZE = 16; | ||
| 19 | uniform vec3 sampleKernel[SAMPLE_KERNEL_SIZE]; | ||
| 20 | |||
| 21 | // the distance to the near clip plane | ||
| 22 | uniform float near; | ||
| 23 | |||
| 24 | // the distance to the far clip plane | ||
| 25 | uniform float far; | ||
| 26 | |||
| 27 | // the left and bottom edges of the view window | ||
| 28 | uniform vec2 leftBottom; | ||
| 29 | |||
| 30 | // the right and top edges of the view window | ||
| 31 | uniform vec2 rightTop; | ||
| 32 | |||
| 33 | // the radius of the effect | ||
| 34 | uniform float radius; | ||
| 35 | |||
| 36 | // the scale for the noise texture | ||
| 37 | uniform vec2 noiseScale; | ||
| 38 | |||
| 39 | // given a texture coordinate, returns the 3D view space z coordinate | ||
| 40 | float texCoordToViewSpaceZ(vec2 texCoord) { | ||
| 41 | return (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far); | ||
| 42 | } | ||
| 43 | |||
| 44 | // given a texture coordinate, returns the 3D view space coordinate | ||
| 45 | vec3 texCoordToViewSpace(vec2 texCoord) { | ||
| 46 | float z = texCoordToViewSpaceZ(texCoord); | ||
| 47 | return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); | ||
| 48 | } | ||
| 49 | |||
| 50 | void main(void) { | ||
| 51 | vec3 rotationX = texture2D(rotationTexture, gl_TexCoord[0].st * noiseScale).rgb; | ||
| 52 | vec3 rotationY = normalize(cross(rotationX, vec3(0.0, 0.0, 1.0))); | ||
| 53 | mat3 rotation = mat3(rotationX, rotationY, cross(rotationX, rotationY)); | ||
| 54 | |||
| 55 | vec3 center = texCoordToViewSpace(gl_TexCoord[0].st); | ||
| 56 | |||
| 57 | float occlusion = 4.0; | ||
| 58 | for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { | ||
| 59 | vec3 offset = center + rotation * (radius * sampleKernel[i]); | ||
| 60 | vec4 projected = gl_ProjectionMatrix * vec4(offset, 1.0); | ||
| 61 | float depth = texCoordToViewSpaceZ(projected.xy * 0.5 / projected.w + vec2(0.5, 0.5)); | ||
| 62 | occlusion += 1.0 - step(offset.z, depth); // * step(abs(center.z - depth), radius); | ||
| 63 | } | ||
| 64 | |||
| 65 | gl_FragColor = vec4(occlusion, occlusion, occlusion, 0.0) / 16.0; | ||
| 66 | } | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // ambient_occlusion.vert | ||
| 5 | // vertex shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 8/16/13. | ||
| 8 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 9 | // | ||
| 10 | |||
| 11 | void main(void) { | ||
| 12 | gl_TexCoord[0] = gl_MultiTexCoord0; | ||
| 13 | gl_Position = gl_Vertex; | ||
| 14 | } | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // occlusion_blur.frag | ||
| 5 | // fragment shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 8/16/13. | ||
| 8 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 9 | // | ||
| 10 | |||
| 11 | // the original texture | ||
| 12 | uniform sampler2D originalTexture; | ||
| 13 | |||
| 14 | void main(void) { | ||
| 15 | float ds = dFdx(gl_TexCoord[0].s); | ||
| 16 | float dt = dFdy(gl_TexCoord[0].t); | ||
| 17 | vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); | ||
| 18 | for (int i = 0; i < 4; i++) { | ||
| 19 | for (int j = 0; j < 4; j++) { | ||
| 20 | sum += texture2D(originalTexture, gl_TexCoord[0].st + | ||
| 21 | vec2(ds, dt) * vec2(-2.0 + float(i), -2.0 + float(j))); | ||
| 22 | } | ||
| 23 | } | ||
| 24 | gl_FragColor = sum / 16.0; | ||
| 25 | } | ||
| @@ -1449,6 +1449,7 @@ void Application::init() { · 1448 unmodified lines | |||
| 1449 | _environment.init(); | 1449 | _environment.init(); |
| 1450 | 1450 | ||
| 1451 | _glowEffect.init(); | 1451 | _glowEffect.init(); |
| 1452 | _ambientOcclusionEffect.init(); | ||
| 1452 | 1453 | ||
| 1453 | _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); | 1454 | _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); |
| 1454 | 1455 | ||
| @@ -2375,6 +2376,11 @@ void Application::displaySide(Camera& whichCamera) { · 920 unmodified lines | |||
| 2375 | renderWorldBox(); | 2376 | renderWorldBox(); |
| 2376 | } | 2377 | } |
| 2377 | 2378 | ||
| 2379 | // render the ambient occlusion effect if enabled | ||
| 2380 | if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { | ||
| 2381 | _ambientOcclusionEffect.render(); | ||
| 2382 | } | ||
| 2383 | |||
| 2378 | // brad's frustum for debugging | 2384 | // brad's frustum for debugging |
| 2379 | if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { | 2385 | if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { |
| 2380 | renderViewFrustum(_viewFrustum); | 2386 | renderViewFrustum(_viewFrustum); |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | |||
| 32 | #include "Environment.h" | 32 | #include "Environment.h" |
| 33 | #include "GLCanvas.h" | 33 | #include "GLCanvas.h" |
| 34 | #include "PacketHeaders.h" | 34 | #include "PacketHeaders.h" |
| 35 | #include "PieMenu.h" | ||
| 35 | #include "SerialInterface.h" | 36 | #include "SerialInterface.h" |
| 36 | #include "Stars.h" | 37 | #include "Stars.h" |
| 37 | #include "Swatch.h" | 38 | #include "Swatch.h" |
| @@ -42,9 +43,9 @@ · 4 unmodified lines | |||
| 42 | #include "VoxelPacketProcessor.h" | 43 | #include "VoxelPacketProcessor.h" |
| 43 | #include "VoxelSystem.h" | 44 | #include "VoxelSystem.h" |
| 44 | #include "Webcam.h" | 45 | #include "Webcam.h" |
| 45 | #include "PieMenu.h" | ||
| 46 | #include "avatar/Avatar.h" | 46 | #include "avatar/Avatar.h" |
| 47 | #include "avatar/HandControl.h" | 47 | #include "avatar/HandControl.h" |
| 48 | #include "renderer/AmbientOcclusionEffect.h" | ||
| 48 | #include "renderer/GeometryCache.h" | 49 | #include "renderer/GeometryCache.h" |
| 49 | #include "renderer/GlowEffect.h" | 50 | #include "renderer/GlowEffect.h" |
| 50 | #include "renderer/TextureCache.h" | 51 | #include "renderer/TextureCache.h" |
| @@ -314,6 +315,7 @@ private: · 263 unmodified lines | |||
| 314 | TextureCache _textureCache; | 315 | TextureCache _textureCache; |
| 315 | 316 | ||
| 316 | GlowEffect _glowEffect; | 317 | GlowEffect _glowEffect; |
| 318 | AmbientOcclusionEffect _ambientOcclusionEffect; | ||
| 317 | 319 | ||
| 318 | #ifndef _WIN32 | 320 | #ifndef _WIN32 |
| 319 | Audio _audio; | 321 | Audio _audio; |
| @@ -163,6 +163,7 @@ Menu::Menu() : · 162 unmodified lines | |||
| 163 | appInstance->getGlowEffect(), | 163 | appInstance->getGlowEffect(), |
| 164 | SLOT(cycleRenderMode())); | 164 | SLOT(cycleRenderMode())); |
| 165 | 165 | ||
| 166 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::AmbientOcclusion); | ||
| 166 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FrameTimer); | 167 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FrameTimer); |
| 167 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors); | 168 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors); |
| 168 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtIndicator, 0, true); | 169 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtIndicator, 0, true); |
| @@ -108,6 +108,7 @@ private: · 107 unmodified lines | |||
| 108 | 108 | ||
| 109 | namespace MenuOption { | 109 | namespace MenuOption { |
| 110 | 110 | ||
| 111 | const QString AmbientOcclusion = "Ambient Occlusion"; | ||
| 111 | const QString Avatars = "Avatars"; | 112 | const QString Avatars = "Avatars"; |
| 112 | const QString AvatarAsBalls = "Avatar as Balls"; | 113 | const QString AvatarAsBalls = "Avatar as Balls"; |
| 113 | const QString Atmosphere = "Atmosphere"; | 114 | const QString Atmosphere = "Atmosphere"; |
| @@ -0,0 +1,145 @@ | |||
| 1 | // | ||
| 2 | // AmbientOcclusionEffect.cpp | ||
| 3 | // interface | ||
| 4 | // | ||
| 5 | // Created by Andrzej Kapolka on 7/14/13. | ||
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 7 | // | ||
| 8 | |||
| 9 | // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL | ||
| 10 | #include "InterfaceConfig.h" | ||
| 11 | |||
| 12 | #include <QOpenGLFramebufferObject> | ||
| 13 | |||
| 14 | #include <glm/gtc/random.hpp> | ||
| 15 | |||
| 16 | #include <SharedUtil.h> | ||
| 17 | |||
| 18 | #include "AmbientOcclusionEffect.h" | ||
| 19 | #include "Application.h" | ||
| 20 | #include "InterfaceConfig.h" | ||
| 21 | #include "ProgramObject.h" | ||
| 22 | #include "RenderUtil.h" | ||
| 23 | |||
| 24 | const int ROTATION_WIDTH = 4; | ||
| 25 | const int ROTATION_HEIGHT = 4; | ||
| 26 | |||
| 27 | void AmbientOcclusionEffect::init() { | ||
| 28 | switchToResourcesParentIfRequired(); | ||
| 29 | |||
| 30 | _occlusionProgram = new ProgramObject(); | ||
| 31 | _occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert"); | ||
| 32 | _occlusionProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag"); | ||
| 33 | _occlusionProgram->link(); | ||
| 34 | |||
| 35 | _blurProgram = new ProgramObject(); | ||
| 36 | _blurProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert"); | ||
| 37 | _blurProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/occlusion_blur.frag"); | ||
| 38 | _blurProgram->link(); | ||
| 39 | |||
| 40 | _blurProgram->bind(); | ||
| 41 | _blurProgram->setUniformValue("originalTexture", 0); | ||
| 42 | _blurProgram->release(); | ||
| 43 | |||
| 44 | // create the sample kernel: an array of spherically distributed offset vectors | ||
| 45 | const int SAMPLE_KERNEL_SIZE = 16; | ||
| 46 | QVector3D sampleKernel[SAMPLE_KERNEL_SIZE]; | ||
| 47 | for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { | ||
| 48 | // square the length in order to increase density towards the center | ||
| 49 | glm::vec3 vector = glm::sphericalRand(1.0f); | ||
| 50 | float scale = randFloat(); | ||
| 51 | const float MIN_VECTOR_LENGTH = 0.01f; | ||
| 52 | const float MAX_VECTOR_LENGTH = 1.0f; | ||
| 53 | vector *= glm::mix(MIN_VECTOR_LENGTH, MAX_VECTOR_LENGTH, scale * scale); | ||
| 54 | sampleKernel[i] = QVector3D(vector.x, vector.y, vector.z); | ||
| 55 | } | ||
| 56 | |||
| 57 | _occlusionProgram->bind(); | ||
| 58 | _occlusionProgram->setUniformValue("depthTexture", 0); | ||
| 59 | _occlusionProgram->setUniformValue("rotationTexture", 1); | ||
| 60 | _occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE); | ||
| 61 | _occlusionProgram->setUniformValue("radius", 0.1f); | ||
| 62 | _occlusionProgram->release(); | ||
| 63 | |||
| 64 | _nearLocation = _occlusionProgram->uniformLocation("near"); | ||
| 65 | _farLocation = _occlusionProgram->uniformLocation("far"); | ||
| 66 | _leftBottomLocation = _occlusionProgram->uniformLocation("leftBottom"); | ||
| 67 | _rightTopLocation = _occlusionProgram->uniformLocation("rightTop"); | ||
| 68 | _noiseScaleLocation = _occlusionProgram->uniformLocation("noiseScale"); | ||
| 69 | |||
| 70 | // generate the random rotation texture | ||
| 71 | glGenTextures(1, &_rotationTextureID); | ||
| 72 | glBindTexture(GL_TEXTURE_2D, _rotationTextureID); | ||
| 73 | const int ELEMENTS_PER_PIXEL = 3; | ||
| 74 | unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL]; | ||
| 75 | unsigned char* rotation = rotationData; | ||
| 76 | for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) { | ||
| 77 | glm::vec3 randvec = glm::sphericalRand(1.0f); | ||
| 78 | *rotation++ = ((randvec.x + 1.0f) / 2.0f) * 255.0f; | ||
| 79 | *rotation++ = ((randvec.y + 1.0f) / 2.0f) * 255.0f; | ||
| 80 | *rotation++ = ((randvec.z + 1.0f) / 2.0f) * 255.0f; | ||
| 81 | } | ||
| 82 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData); | ||
| 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
| 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
| 85 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 86 | } | ||
| 87 | |||
| 88 | void AmbientOcclusionEffect::render() { | ||
| 89 | glDisable(GL_BLEND); | ||
| 90 | glDisable(GL_DEPTH_TEST); | ||
| 91 | glDepthMask(GL_FALSE); | ||
| 92 | |||
| 93 | glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); | ||
| 94 | |||
| 95 | glActiveTexture(GL_TEXTURE1); | ||
| 96 | glBindTexture(GL_TEXTURE_2D, _rotationTextureID); | ||
| 97 | |||
| 98 | // render with the occlusion shader to the secondary buffer | ||
| 99 | QOpenGLFramebufferObject* secondaryFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); | ||
| 100 | secondaryFBO->bind(); | ||
| 101 | |||
| 102 | float left, right, bottom, top, nearVal, farVal; | ||
| 103 | glm::vec4 nearClipPlane, farClipPlane; | ||
| 104 | Application::getInstance()->getViewFrustum()->computeOffAxisFrustum( | ||
| 105 | left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); | ||
| 106 | |||
| 107 | _occlusionProgram->bind(); | ||
| 108 | _occlusionProgram->setUniformValue(_nearLocation, nearVal); | ||
| 109 | _occlusionProgram->setUniformValue(_farLocation, farVal); | ||
| 110 | _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); | ||
| 111 | _occlusionProgram->setUniformValue(_rightTopLocation, right, top); | ||
| 112 | QSize size = Application::getInstance()->getGLWidget()->size(); | ||
| 113 | _occlusionProgram->setUniformValue(_noiseScaleLocation, size.width() / (float)ROTATION_WIDTH, | ||
| 114 | size.height() / (float)ROTATION_HEIGHT); | ||
| 115 | |||
| 116 | renderFullscreenQuad(); | ||
| 117 | |||
| 118 | _occlusionProgram->release(); | ||
| 119 | |||
| 120 | secondaryFBO->release(); | ||
| 121 | |||
| 122 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 123 | glActiveTexture(GL_TEXTURE0); | ||
| 124 | |||
| 125 | // now render secondary to primary with 4x4 blur | ||
| 126 | Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); | ||
| 127 | |||
| 128 | glEnable(GL_BLEND); | ||
| 129 | glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); | ||
| 130 | |||
| 131 | glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); | ||
| 132 | |||
| 133 | _blurProgram->bind(); | ||
| 134 | |||
| 135 | renderFullscreenQuad(); | ||
| 136 | |||
| 137 | _blurProgram->release(); | ||
| 138 | |||
| 139 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 140 | |||
| 141 | //glEnable(GL_BLEND); | ||
| 142 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | ||
| 143 | glEnable(GL_DEPTH_TEST); | ||
| 144 | glDepthMask(GL_TRUE); | ||
| 145 | } | ||
| @@ -0,0 +1,39 @@ | |||
| 1 | // | ||
| 2 | // AmbientOcclusionEffect.h | ||
| 3 | // interface | ||
| 4 | // | ||
| 5 | // Created by Andrzej Kapolka on 7/14/13. | ||
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 7 | // | ||
| 8 | |||
| 9 | #ifndef __interface__AmbientOcclusionEffect__ | ||
| 10 | #define __interface__AmbientOcclusionEffect__ | ||
| 11 | |||
| 12 | #include "InterfaceConfig.h" | ||
| 13 | |||
| 14 | class ProgramObject; | ||
| 15 | |||
| 16 | /// A screen space ambient occlusion effect. See John Chapman's tutorial at | ||
| 17 | /// http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html for reference. | ||
| 18 | class AmbientOcclusionEffect { | ||
| 19 | public: | ||
| 20 | |||
| 21 | void init(); | ||
| 22 | |||
| 23 | void render(); | ||
| 24 | |||
| 25 | private: | ||
| 26 | |||
| 27 | ProgramObject* _occlusionProgram; | ||
| 28 | int _nearLocation; | ||
| 29 | int _farLocation; | ||
| 30 | int _leftBottomLocation; | ||
| 31 | int _rightTopLocation; | ||
| 32 | int _noiseScaleLocation; | ||
| 33 | |||
| 34 | ProgramObject* _blurProgram; | ||
| 35 | |||
| 36 | GLuint _rotationTextureID; | ||
| 37 | }; | ||
| 38 | |||
| 39 | #endif /* defined(__interface__AmbientOcclusionEffect__) */ | ||
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | // Created by Andrzej Kapolka on 8/7/13. | 5 | // Created by Andrzej Kapolka on 8/7/13. |
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. |
| 7 | 7 | ||
| 8 | // include this before QGLWidget, which includes an earlier version of OpenGL | 8 | // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL |
| 9 | #include "InterfaceConfig.h" | 9 | #include "InterfaceConfig.h" |
| 10 | 10 | ||
| 11 | #include <QOpenGLFramebufferObject> | 11 | #include <QOpenGLFramebufferObject> |
| @@ -13,6 +13,7 @@ · 1 unmodified line | |||
| 13 | #include "Application.h" | 13 | #include "Application.h" |
| 14 | #include "GlowEffect.h" | 14 | #include "GlowEffect.h" |
| 15 | #include "ProgramObject.h" | 15 | #include "ProgramObject.h" |
| 16 | #include "RenderUtil.h" | ||
| 16 | 17 | ||
| 17 | GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) { | 18 | GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) { |
| 18 | } | 19 | } |
| @@ -68,19 +69,6 @@ void GlowEffect::end() { · 49 unmodified lines | |||
| 68 | glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); | 69 | glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | static void renderFullscreenQuad() { | ||
| 72 | glBegin(GL_QUADS); | ||
| 73 | glTexCoord2f(0.0f, 0.0f); | ||
| 74 | glVertex2f(-1.0f, -1.0f); | ||
| 75 | glTexCoord2f(1.0f, 0.0f); | ||
| 76 | glVertex2f(1.0f, -1.0f); | ||
| 77 | glTexCoord2f(1.0f, 1.0f); | ||
| 78 | glVertex2f(1.0f, 1.0f); | ||
| 79 | glTexCoord2f(0.0f, 1.0f); | ||
| 80 | glVertex2f(-1.0f, 1.0f); | ||
| 81 | glEnd(); | ||
| 82 | } | ||
| 83 | |||
| 84 | void GlowEffect::render() { | 72 | void GlowEffect::render() { |
| 85 | QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); | 73 | QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); |
| 86 | primaryFBO->release(); | 74 | primaryFBO->release(); |
| @@ -95,6 +83,7 @@ void GlowEffect::render() { · 8 unmodified lines | |||
| 95 | 83 | ||
| 96 | glDisable(GL_BLEND); | 84 | glDisable(GL_BLEND); |
| 97 | glDisable(GL_DEPTH_TEST); | 85 | glDisable(GL_DEPTH_TEST); |
| 86 | glDepthMask(GL_FALSE); | ||
| 98 | 87 | ||
| 99 | if (_isEmpty) { | 88 | if (_isEmpty) { |
| 100 | // copy the primary to the screen | 89 | // copy the primary to the screen |
| @@ -210,6 +199,7 @@ void GlowEffect::render() { · 109 unmodified lines | |||
| 210 | 199 | ||
| 211 | glEnable(GL_BLEND); | 200 | glEnable(GL_BLEND); |
| 212 | glEnable(GL_DEPTH_TEST); | 201 | glEnable(GL_DEPTH_TEST); |
| 202 | glDepthMask(GL_TRUE); | ||
| 213 | glBindTexture(GL_TEXTURE_2D, 0); | 203 | glBindTexture(GL_TEXTURE_2D, 0); |
| 214 | } | 204 | } |
| 215 | 205 | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | // | ||
| 2 | // RenderUtil.cpp | ||
| 3 | // interface | ||
| 4 | // | ||
| 5 | // Created by Andrzej Kapolka on 8/15/13. | ||
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 7 | |||
| 8 | #include "InterfaceConfig.h" | ||
| 9 | #include "RenderUtil.h" | ||
| 10 | |||
| 11 | void renderFullscreenQuad() { | ||
| 12 | glBegin(GL_QUADS); | ||
| 13 | glTexCoord2f(0.0f, 0.0f); | ||
| 14 | glVertex2f(-1.0f, -1.0f); | ||
| 15 | glTexCoord2f(1.0f, 0.0f); | ||
| 16 | glVertex2f(1.0f, -1.0f); | ||
| 17 | glTexCoord2f(1.0f, 1.0f); | ||
| 18 | glVertex2f(1.0f, 1.0f); | ||
| 19 | glTexCoord2f(0.0f, 1.0f); | ||
| 20 | glVertex2f(-1.0f, 1.0f); | ||
| 21 | glEnd(); | ||
| 22 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | // | ||
| 2 | // RenderUtil.h | ||
| 3 | // interface | ||
| 4 | // | ||
| 5 | // Created by Andrzej Kapolka on 8/15/13. | ||
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | ||
| 7 | // | ||
| 8 | |||
| 9 | #ifndef __interface__RenderUtil__ | ||
| 10 | #define __interface__RenderUtil__ | ||
| 11 | |||
| 12 | /// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (0, 0) to (1, 1). | ||
| 13 | void renderFullscreenQuad(); | ||
| 14 | |||
| 15 | #endif /* defined(__interface__RenderUtil__) */ | ||
| @@ -5,6 +5,9 @@ · 4 unmodified lines | |||
| 5 | // Created by Andrzej Kapolka on 8/6/13. | 5 | // Created by Andrzej Kapolka on 8/6/13. |
| 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | 6 | // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. |
| 7 | 7 | ||
| 8 | // include this before QGLWidget, which includes an earlier version of OpenGL | ||
| 9 | #include "InterfaceConfig.h" | ||
| 10 | |||
| 8 | #include <QGLWidget> | 11 | #include <QGLWidget> |
| 9 | #include <QOpenGLFramebufferObject> | 12 | #include <QOpenGLFramebufferObject> |
| 10 | 13 | ||
| @@ -23,6 +26,7 @@ TextureCache::~TextureCache() { · 12 unmodified lines | |||
| 23 | } | 26 | } |
| 24 | if (_primaryFramebufferObject != NULL) { | 27 | if (_primaryFramebufferObject != NULL) { |
| 25 | delete _primaryFramebufferObject; | 28 | delete _primaryFramebufferObject; |
| 29 | glDeleteTextures(1, &_primaryDepthTextureID); | ||
| 26 | } | 30 | } |
| 27 | if (_secondaryFramebufferObject != NULL) { | 31 | if (_secondaryFramebufferObject != NULL) { |
| 28 | delete _secondaryFramebufferObject; | 32 | delete _secondaryFramebufferObject; |
| @@ -60,13 +64,31 @@ GLuint TextureCache::getPermutationNormalTextureID() { · 31 unmodified lines | |||
| 60 | 64 | ||
| 61 | QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { | 65 | QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { |
| 62 | if (_primaryFramebufferObject == NULL) { | 66 | if (_primaryFramebufferObject == NULL) { |
| 63 | _primaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size(), | 67 | QSize size = Application::getInstance()->getGLWidget()->size(); |
| 64 | QOpenGLFramebufferObject::Depth); | 68 | _primaryFramebufferObject = new QOpenGLFramebufferObject(size); |
| 65 | Application::getInstance()->getGLWidget()->installEventFilter(this); | 69 | Application::getInstance()->getGLWidget()->installEventFilter(this); |
| 70 | |||
| 71 | glGenTextures(1, &_primaryDepthTextureID); | ||
| 72 | glBindTexture(GL_TEXTURE_2D, _primaryDepthTextureID); | ||
| 73 | glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size.width(), size.height(), | ||
| 74 | 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); | ||
| 75 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||
| 76 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||
| 77 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 78 | |||
| 79 | _primaryFramebufferObject->bind(); | ||
| 80 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0); | ||
| 81 | _primaryFramebufferObject->release(); | ||
| 66 | } | 82 | } |
| 67 | return _primaryFramebufferObject; | 83 | return _primaryFramebufferObject; |
| 68 | } | 84 | } |
| 69 | 85 | ||
| 86 | GLuint TextureCache::getPrimaryDepthTextureID() { | ||
| 87 | // ensure that the primary framebuffer object is initialized before returning the depth texture id | ||
| 88 | getPrimaryFramebufferObject(); | ||
| 89 | return _primaryDepthTextureID; | ||
| 90 | } | ||
| 91 | |||
| 70 | QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { | 92 | QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { |
| 71 | if (_secondaryFramebufferObject == NULL) { | 93 | if (_secondaryFramebufferObject == NULL) { |
| 72 | _secondaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); | 94 | _secondaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); |
| @@ -89,6 +111,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) { · 16 unmodified lines | |||
| 89 | if (_primaryFramebufferObject != NULL && _primaryFramebufferObject->size() != size) { | 111 | if (_primaryFramebufferObject != NULL && _primaryFramebufferObject->size() != size) { |
| 90 | delete _primaryFramebufferObject; | 112 | delete _primaryFramebufferObject; |
| 91 | _primaryFramebufferObject = NULL; | 113 | _primaryFramebufferObject = NULL; |
| 114 | glDeleteTextures(1, &_primaryDepthTextureID); | ||
| 92 | } | 115 | } |
| 93 | if (_secondaryFramebufferObject != NULL && _secondaryFramebufferObject->size() != size) { | 116 | if (_secondaryFramebufferObject != NULL && _secondaryFramebufferObject->size() != size) { |
| 94 | delete _secondaryFramebufferObject; | 117 | delete _secondaryFramebufferObject; |
| @@ -15,16 +15,31 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | class QOpenGLFramebufferObject; | 16 | class QOpenGLFramebufferObject; |
| 17 | 17 | ||
| 18 | /// Stored cached textures, including render-to-texture targets. | ||
| 18 | class TextureCache : public QObject { | 19 | class TextureCache : public QObject { |
| 19 | public: | 20 | public: |
| 20 | 21 | ||
| 21 | TextureCache(); | 22 | TextureCache(); |
| 22 | ~TextureCache(); | 23 | ~TextureCache(); |
| 23 | 24 | ||
| 25 | /// Returns the ID of the permutation/normal texture used for Perlin noise shader programs. This texture | ||
| 26 | /// has two lines: the first, a set of random numbers in [0, 255] to be used as permutation offsets, and | ||
| 27 | /// the second, a set of random unit vectors to be used as noise gradients. | ||
| 24 | GLuint getPermutationNormalTextureID(); | 28 | GLuint getPermutationNormalTextureID(); |
| 25 | 29 | ||
| 30 | /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is | ||
| 31 | /// used for scene rendering. | ||
| 26 | QOpenGLFramebufferObject* getPrimaryFramebufferObject(); | 32 | QOpenGLFramebufferObject* getPrimaryFramebufferObject(); |
| 33 | |||
| 34 | /// Returns the ID of the primary framebuffer object's depth texture. This contains the Z buffer used in rendering. | ||
| 35 | GLuint getPrimaryDepthTextureID(); | ||
| 36 | |||
| 37 | /// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full | ||
| 38 | /// screen effects. | ||
| 27 | QOpenGLFramebufferObject* getSecondaryFramebufferObject(); | 39 | QOpenGLFramebufferObject* getSecondaryFramebufferObject(); |
| 40 | |||
| 41 | /// Returns a pointer to the tertiary framebuffer object, used as an additional render target when performing full | ||
| 42 | /// screen effects. | ||
| 28 | QOpenGLFramebufferObject* getTertiaryFramebufferObject(); | 43 | QOpenGLFramebufferObject* getTertiaryFramebufferObject(); |
| 29 | 44 | ||
| 30 | virtual bool eventFilter(QObject* watched, QEvent* event); | 45 | virtual bool eventFilter(QObject* watched, QEvent* event); |
| @@ -34,6 +49,7 @@ private: · 3 unmodified lines | |||
| 34 | GLuint _permutationNormalTextureID; | 49 | GLuint _permutationNormalTextureID; |
| 35 | 50 | ||
| 36 | QOpenGLFramebufferObject* _primaryFramebufferObject; | 51 | QOpenGLFramebufferObject* _primaryFramebufferObject; |
| 52 | GLuint _primaryDepthTextureID; | ||
| 37 | QOpenGLFramebufferObject* _secondaryFramebufferObject; | 53 | QOpenGLFramebufferObject* _secondaryFramebufferObject; |
| 38 | QOpenGLFramebufferObject* _tertiaryFramebufferObject; | 54 | QOpenGLFramebufferObject* _tertiaryFramebufferObject; |
| 39 | }; | 55 | }; |