diff --git a/interface/resources/shaders/glow_add.frag b/interface/resources/shaders/glow_add.frag new file mode 100644 index 0000000000..0947292109 --- /dev/null +++ b/interface/resources/shaders/glow_add.frag @@ -0,0 +1,17 @@ +#version 120 + +// +// glow_add.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the texture containing the original color +uniform sampler2D originalTexture; + +void main(void) { + vec4 color = texture2D(originalTexture, gl_TexCoord[0].st); + gl_FragColor = color * (1.0 + color.a); +} diff --git a/interface/resources/shaders/glow_add_separate.frag b/interface/resources/shaders/glow_add_separate.frag new file mode 100644 index 0000000000..7b7f538a03 --- /dev/null +++ b/interface/resources/shaders/glow_add_separate.frag @@ -0,0 +1,20 @@ +#version 120 + +// +// glow_add_separate.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the texture containing the original color +uniform sampler2D originalTexture; + +// the texture containing the blurred color +uniform sampler2D blurredTexture; + +void main(void) { + vec4 blurred = texture2D(blurredTexture, gl_TexCoord[0].st); + gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5); +} diff --git a/interface/resources/shaders/vertical_blur.frag b/interface/resources/shaders/vertical_blur.frag index 6e49c5b553..96ab95ea9e 100644 --- a/interface/resources/shaders/vertical_blur.frag +++ b/interface/resources/shaders/vertical_blur.frag @@ -4,25 +4,21 @@ // vertical_blur.frag // fragment shader // -// Created by Andrzej Kapolka on 8/8/13. +// Created by Andrzej Kapolka on 8/14/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -// the texture containing the original color -uniform sampler2D originalTexture; - // the texture containing the horizontally blurred color -uniform sampler2D horizontallyBlurredTexture; +uniform sampler2D originalTexture; void main(void) { float dt = dFdy(gl_TexCoord[0].t); - vec4 blurred = (texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) + - texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0; - gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5); + gl_FragColor = (texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) + + texture2D(originalTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0; } diff --git a/interface/resources/shaders/vertical_blur_add.frag b/interface/resources/shaders/vertical_blur_add.frag new file mode 100644 index 0000000000..5cda2622b4 --- /dev/null +++ b/interface/resources/shaders/vertical_blur_add.frag @@ -0,0 +1,28 @@ +#version 120 + +// +// vertical_blur_add.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/8/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the texture containing the original color +uniform sampler2D originalTexture; + +// the texture containing the horizontally blurred color +uniform sampler2D horizontallyBlurredTexture; + +void main(void) { + float dt = dFdy(gl_TexCoord[0].t); + vec4 blurred = (texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -7.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -5.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -3.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * -1.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 1.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 3.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 5.5)) + + texture2D(horizontallyBlurredTexture, gl_TexCoord[0].st + vec2(0.0, dt * 7.5))) / 8.0; + gl_FragColor = blurred * blurred.a + texture2D(originalTexture, gl_TexCoord[0].st) * (1.0 + blurred.a * 0.5); +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eebb7ba744..65b2da4c24 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2011,6 +2011,7 @@ void Application::initMenu() { _renderAvatarBalls->setChecked(false); renderMenu->addAction("Cycle Voxel Mode", _myAvatar.getVoxels(), SLOT(cycleMode())); renderMenu->addAction("Cycle Face Mode", &_myAvatar.getHead().getFace(), SLOT(cycleRenderMode())); + renderMenu->addAction("Cycle Glow Mode", &_glowEffect, SLOT(cycleRenderMode())); (_renderFrameTimerOn = renderMenu->addAction("Show Timer"))->setCheckable(true); _renderFrameTimerOn->setChecked(false); (_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true); @@ -3162,7 +3163,9 @@ void Application::displaySide(Camera& whichCamera) { if (isLookingAtMyAvatar(avatar)) { avatar->getHead().setLookAtPosition(_myCamera.getPosition()); } + _glowEffect.begin(); avatar->render(false, _renderAvatarBalls->isChecked()); + _glowEffect.end(); avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked()); } @@ -3173,7 +3176,9 @@ void Application::displaySide(Camera& whichCamera) { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); } + _glowEffect.begin(); _myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked()); + _glowEffect.end(); _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); diff --git a/interface/src/renderer/GlowEffect.cpp b/interface/src/renderer/GlowEffect.cpp index 11c73dd12d..8233fe1984 100644 --- a/interface/src/renderer/GlowEffect.cpp +++ b/interface/src/renderer/GlowEffect.cpp @@ -14,9 +14,12 @@ #include "GlowEffect.h" #include "ProgramObject.h" -static ProgramObject* createBlurProgram(const QString& direction) { +GlowEffect::GlowEffect() : _renderMode(BLUR_ADD_MODE) { +} + +static ProgramObject* createProgram(const QString& name) { ProgramObject* program = new ProgramObject(); - program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/" + direction + "_blur.frag"); + program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/" + name + ".frag"); program->link(); program->bind(); @@ -28,12 +31,20 @@ static ProgramObject* createBlurProgram(const QString& direction) { void GlowEffect::init() { switchToResourcesParentIfRequired(); - _horizontalBlurProgram = createBlurProgram("horizontal"); - _verticalBlurProgram = createBlurProgram("vertical"); - _verticalBlurProgram->bind(); - _verticalBlurProgram->setUniformValue("horizontallyBlurredTexture", 1); - _verticalBlurProgram->release(); + _addProgram = createProgram("glow_add"); + _horizontalBlurProgram = createProgram("horizontal_blur"); + _verticalBlurAddProgram = createProgram("vertical_blur_add"); + _verticalBlurProgram = createProgram("vertical_blur"); + _addSeparateProgram = createProgram("glow_add_separate"); + + _verticalBlurAddProgram->bind(); + _verticalBlurAddProgram->setUniformValue("horizontallyBlurredTexture", 1); + _verticalBlurAddProgram->release(); + + _addSeparateProgram->bind(); + _addSeparateProgram->setUniformValue("blurredTexture", 1); + _addSeparateProgram->release(); } void GlowEffect::prepare() { @@ -93,7 +104,12 @@ void GlowEffect::render() { glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); } - } else { + } else if (_renderMode == ADD_MODE) { + _addProgram->bind(); + renderFullscreenQuad(); + _addProgram->release(); + + } else { // _renderMode == BLUR_ADD_MODE || _renderMode == BLUR_PERSIST_ADD_MODE // render the primary to the secondary with the horizontal blur QOpenGLFramebufferObject* secondaryFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); @@ -105,13 +121,48 @@ void GlowEffect::render() { secondaryFBO->release(); - // render the secondary to the screen with the vertical blur - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + if (_renderMode == BLUR_ADD_MODE) { + // render the secondary to the screen with the vertical blur + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + + _verticalBlurAddProgram->bind(); + renderFullscreenQuad(); + _verticalBlurAddProgram->release(); + + } else { // _renderMode == BLUR_PERSIST_ADD_MODE + // render the secondary to the tertiary with horizontal blur and persistence + QOpenGLFramebufferObject* tertiaryFBO = + Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); + tertiaryFBO->bind(); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA); + const float PERSISTENCE_SMOOTHING = 0.9f; + glBlendColor(0.0f, 0.0f, 0.0f, PERSISTENCE_SMOOTHING); + + glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); + + _verticalBlurProgram->bind(); + renderFullscreenQuad(); + _verticalBlurProgram->release(); - _verticalBlurProgram->bind(); - renderFullscreenQuad(); - _verticalBlurProgram->release(); + glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glDisable(GL_BLEND); + + // now add the tertiary to the primary buffer + tertiaryFBO->release(); + + glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture()); + + _addSeparateProgram->bind(); + renderFullscreenQuad(); + _addSeparateProgram->release(); + } glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); @@ -126,3 +177,7 @@ void GlowEffect::render() { glEnable(GL_DEPTH_TEST); glBindTexture(GL_TEXTURE_2D, 0); } + +void GlowEffect::cycleRenderMode() { + _renderMode = (RenderMode)((_renderMode + 1) % RENDER_MODE_COUNT); +} diff --git a/interface/src/renderer/GlowEffect.h b/interface/src/renderer/GlowEffect.h index 06ca6e5712..d8ea3d18c2 100644 --- a/interface/src/renderer/GlowEffect.h +++ b/interface/src/renderer/GlowEffect.h @@ -9,11 +9,17 @@ #ifndef __interface__GlowEffect__ #define __interface__GlowEffect__ +#include + class ProgramObject; -class GlowEffect { +class GlowEffect : public QObject { + Q_OBJECT + public: + GlowEffect(); + void init(); void prepare(); @@ -23,10 +29,20 @@ public: void render(); +public slots: + + void cycleRenderMode(); + private: + enum RenderMode { ADD_MODE, BLUR_ADD_MODE, BLUR_PERSIST_ADD_MODE, RENDER_MODE_COUNT }; + + RenderMode _renderMode; + ProgramObject* _addProgram; ProgramObject* _horizontalBlurProgram; + ProgramObject* _verticalBlurAddProgram; ProgramObject* _verticalBlurProgram; + ProgramObject* _addSeparateProgram; bool _isEmpty; }; diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 8ff1673d18..d4cc97edbf 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -14,7 +14,7 @@ #include "TextureCache.h" TextureCache::TextureCache() : _permutationNormalTextureID(0), - _primaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL) { + _primaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL), _tertiaryFramebufferObject(NULL) { } TextureCache::~TextureCache() { @@ -27,6 +27,9 @@ TextureCache::~TextureCache() { if (_secondaryFramebufferObject != NULL) { delete _secondaryFramebufferObject; } + if (_tertiaryFramebufferObject != NULL) { + delete _tertiaryFramebufferObject; + } } GLuint TextureCache::getPermutationNormalTextureID() { @@ -72,6 +75,14 @@ QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { return _secondaryFramebufferObject; } +QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() { + if (_tertiaryFramebufferObject == NULL) { + _tertiaryFramebufferObject = new QOpenGLFramebufferObject(Application::getInstance()->getGLWidget()->size()); + Application::getInstance()->getGLWidget()->installEventFilter(this); + } + return _tertiaryFramebufferObject; +} + bool TextureCache::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Resize) { QSize size = static_cast(event)->size(); @@ -83,6 +94,10 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) { delete _secondaryFramebufferObject; _secondaryFramebufferObject = NULL; } + if (_tertiaryFramebufferObject != NULL && _tertiaryFramebufferObject->size() != size) { + delete _tertiaryFramebufferObject; + _tertiaryFramebufferObject = NULL; + } } return false; } diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 29920e1f1f..716f087992 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -25,7 +25,8 @@ public: QOpenGLFramebufferObject* getPrimaryFramebufferObject(); QOpenGLFramebufferObject* getSecondaryFramebufferObject(); - + QOpenGLFramebufferObject* getTertiaryFramebufferObject(); + virtual bool eventFilter(QObject* watched, QEvent* event); private: @@ -34,6 +35,7 @@ private: QOpenGLFramebufferObject* _primaryFramebufferObject; QOpenGLFramebufferObject* _secondaryFramebufferObject; + QOpenGLFramebufferObject* _tertiaryFramebufferObject; }; #endif /* defined(__interface__TextureCache__) */