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 | 1449 | _environment.init(); |
| 1450 | 1450 | |
| 1451 | 1451 | _glowEffect.init(); |
| 1452 | + _ambientOcclusionEffect.init(); | |
| 1452 | 1453 | |
| 1453 | 1454 | _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); |
| 1454 | 1455 | |
| @@ -2375,6 +2376,11 @@ void Application::displaySide(Camera& whichCamera) { · 920 unmodified lines | ||
| 2375 | 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 | 2384 | // brad's frustum for debugging |
| 2379 | 2385 | if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { |
| 2380 | 2386 | renderViewFrustum(_viewFrustum); |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "Environment.h" |
| 33 | 33 | #include "GLCanvas.h" |
| 34 | 34 | #include "PacketHeaders.h" |
| 35 | +#include "PieMenu.h" | |
| 35 | 36 | #include "SerialInterface.h" |
| 36 | 37 | #include "Stars.h" |
| 37 | 38 | #include "Swatch.h" |
| @@ -42,9 +43,9 @@ · 4 unmodified lines | ||
| 42 | 43 | #include "VoxelPacketProcessor.h" |
| 43 | 44 | #include "VoxelSystem.h" |
| 44 | 45 | #include "Webcam.h" |
| 45 | −#include "PieMenu.h" | |
| 46 | 46 | #include "avatar/Avatar.h" |
| 47 | 47 | #include "avatar/HandControl.h" |
| 48 | +#include "renderer/AmbientOcclusionEffect.h" | |
| 48 | 49 | #include "renderer/GeometryCache.h" |
| 49 | 50 | #include "renderer/GlowEffect.h" |
| 50 | 51 | #include "renderer/TextureCache.h" |
| @@ -314,6 +315,7 @@ private: · 263 unmodified lines | ||
| 314 | 315 | TextureCache _textureCache; |
| 315 | 316 | |
| 316 | 317 | GlowEffect _glowEffect; |
| 318 | + AmbientOcclusionEffect _ambientOcclusionEffect; | |
| 317 | 319 | |
| 318 | 320 | #ifndef _WIN32 |
| 319 | 321 | Audio _audio; |
| @@ -163,6 +163,7 @@ Menu::Menu() : · 162 unmodified lines | ||
| 163 | 163 | appInstance->getGlowEffect(), |
| 164 | 164 | SLOT(cycleRenderMode())); |
| 165 | 165 | |
| 166 | + addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::AmbientOcclusion); | |
| 166 | 167 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::FrameTimer); |
| 167 | 168 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtVectors); |
| 168 | 169 | addCheckableActionToQMenuAndActionHash(renderMenu, MenuOption::LookAtIndicator, 0, true); |
| @@ -108,6 +108,7 @@ private: · 107 unmodified lines | ||
| 108 | 108 | |
| 109 | 109 | namespace MenuOption { |
| 110 | 110 | |
| 111 | + const QString AmbientOcclusion = "Ambient Occlusion"; | |
| 111 | 112 | const QString Avatars = "Avatars"; |
| 112 | 113 | const QString AvatarAsBalls = "Avatar as Balls"; |
| 113 | 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 | 5 | // Created by Andrzej Kapolka on 8/7/13. |
| 6 | 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 | 9 | #include "InterfaceConfig.h" |
| 10 | 10 | |
| 11 | 11 | #include <QOpenGLFramebufferObject> |
| @@ -13,6 +13,7 @@ · 1 unmodified line | ||
| 13 | 13 | #include "Application.h" |
| 14 | 14 | #include "GlowEffect.h" |
| 15 | 15 | #include "ProgramObject.h" |
| 16 | +#include "RenderUtil.h" | |
| 16 | 17 | |
| 17 | 18 | GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) { |
| 18 | 19 | } |
| @@ -68,19 +69,6 @@ void GlowEffect::end() { · 49 unmodified lines | ||
| 68 | 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 | 72 | void GlowEffect::render() { |
| 85 | 73 | QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); |
| 86 | 74 | primaryFBO->release(); |
| @@ -95,6 +83,7 @@ void GlowEffect::render() { · 8 unmodified lines | ||
| 95 | 83 | |
| 96 | 84 | glDisable(GL_BLEND); |
| 97 | 85 | glDisable(GL_DEPTH_TEST); |
| 86 | + glDepthMask(GL_FALSE); | |
| 98 | 87 | |
| 99 | 88 | if (_isEmpty) { |
| 100 | 89 | // copy the primary to the screen |
| @@ -210,6 +199,7 @@ void GlowEffect::render() { · 109 unmodified lines | ||
| 210 | 199 | |
| 211 | 200 | glEnable(GL_BLEND); |
| 212 | 201 | glEnable(GL_DEPTH_TEST); |
| 202 | + glDepthMask(GL_TRUE); | |
| 213 | 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 | 5 | // Created by Andrzej Kapolka on 8/6/13. |
| 6 | 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 | 11 | #include <QGLWidget> |
| 9 | 12 | #include <QOpenGLFramebufferObject> |
| 10 | 13 | |
| @@ -23,6 +26,7 @@ TextureCache::~TextureCache() { · 12 unmodified lines | ||
| 23 | 26 | } |
| 24 | 27 | if (_primaryFramebufferObject != NULL) { |
| 25 | 28 | delete _primaryFramebufferObject; |
| 29 | + glDeleteTextures(1, &_primaryDepthTextureID); | |
| 26 | 30 | } |
| 27 | 31 | if (_secondaryFramebufferObject != NULL) { |
| 28 | 32 | delete _secondaryFramebufferObject; |
| @@ -60,13 +64,31 @@ GLuint TextureCache::getPermutationNormalTextureID() { · 31 unmodified lines | ||
| 60 | 64 | |
| 61 | 65 | QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() { |
| 62 | 66 | if (_primaryFramebufferObject == NULL) { |
| 63 | − _primaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size(), | |
| 64 | − QOpenGLFramebufferObject::Depth); | |
| 67 | + QSize size = Application::getInstance()->getGLWidget()->size(); | |
| 68 | + _primaryFramebufferObject = new QOpenGLFramebufferObject(size); | |
| 65 | 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 | 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 | 92 | QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { |
| 71 | 93 | if (_secondaryFramebufferObject == NULL) { |
| 72 | 94 | _secondaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); |
| @@ -89,6 +111,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) { · 16 unmodified lines | ||
| 89 | 111 | if (_primaryFramebufferObject != NULL && _primaryFramebufferObject->size() != size) { |
| 90 | 112 | delete _primaryFramebufferObject; |
| 91 | 113 | _primaryFramebufferObject = NULL; |
| 114 | + glDeleteTextures(1, &_primaryDepthTextureID); | |
| 92 | 115 | } |
| 93 | 116 | if (_secondaryFramebufferObject != NULL && _secondaryFramebufferObject->size() != size) { |
| 94 | 117 | delete _secondaryFramebufferObject; |
| @@ -15,16 +15,31 @@ · 14 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | class QOpenGLFramebufferObject; |
| 17 | 17 | |
| 18 | +/// Stored cached textures, including render-to-texture targets. | |
| 18 | 19 | class TextureCache : public QObject { |
| 19 | 20 | public: |
| 20 | 21 | |
| 21 | 22 | TextureCache(); |
| 22 | 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 | 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 | 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 | 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 | 43 | QOpenGLFramebufferObject* getTertiaryFramebufferObject(); |
| 29 | 44 | |
| 30 | 45 | virtual bool eventFilter(QObject* watched, QEvent* event); |
| @@ -34,6 +49,7 @@ private: · 3 unmodified lines | ||
| 34 | 49 | GLuint _permutationNormalTextureID; |
| 35 | 50 | |
| 36 | 51 | QOpenGLFramebufferObject* _primaryFramebufferObject; |
| 52 | + GLuint _primaryDepthTextureID; | |
| 37 | 53 | QOpenGLFramebufferObject* _secondaryFramebufferObject; |
| 38 | 54 | QOpenGLFramebufferObject* _tertiaryFramebufferObject; |
| 39 | 55 | }; |