diff --git a/modules/postprocessing/CMakeLists.txt b/modules/postprocessing/CMakeLists.txt new file mode 100644 index 0000000000..d6e0130e63 --- /dev/null +++ b/modules/postprocessing/CMakeLists.txt @@ -0,0 +1,52 @@ +########################################################################################## +# # +# OpenSpace # +# # +# Copyright (c) 2014-2018 # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy of this # +# software and associated documentation files (the "Software"), to deal in the Software # +# without restriction, including without limitation the rights to use, copy, modify, # +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # +# permit persons to whom the Software is furnished to do so, subject to the following # +# conditions: # +# # +# The above copyright notice and this permission notice shall be included in all copies # +# or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +########################################################################################## + +include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/postprocessingrenderer.h +) +source_group("Header Files" FILES ${HEADER_FILES}) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/postprocessingrenderer.cpp +) +source_group("Source Files" FILES ${SOURCE_FILES}) + +set(SHADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/blend_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/bloom_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/blur_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/lensflare_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/pass_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/pass_vs.glsl +) +source_group("Shader Files" FILES ${SHADER_FILES}) + +create_new_module( + "Postprocessing" + postprocessing_module + STATIC + ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} +) diff --git a/modules/postprocessing/include.cmake b/modules/postprocessing/include.cmake new file mode 100644 index 0000000000..fe510d8881 --- /dev/null +++ b/modules/postprocessing/include.cmake @@ -0,0 +1 @@ +set (DEFAULT_MODULE OFF) diff --git a/modules/postprocessing/postprocessingmodule.cpp b/modules/postprocessing/postprocessingmodule.cpp new file mode 100644 index 0000000000..407b056f69 --- /dev/null +++ b/modules/postprocessing/postprocessingmodule.cpp @@ -0,0 +1,59 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace { + constexpr const char* _loggerCat = "Postprocessing"; +} // namespace + +namespace openspace { + +PostprocessingRenderer PostprocessingModule::_postprocessingRenderer; + +PostprocessingModule::PostprocessingModule() : OpenSpaceModule(Name) { +} + +PostprocessingRenderer& PostprocessingModule::renderer(){ + return _postprocessingRenderer; +} + +void PostprocessingModule::internalInitialize(const ghoul::Dictionary& d) { + LDEBUG("PostprocessingModule::internalInitialize"); + _postprocessingRenderer.initialize(d); +} + +void PostprocessingModule::internalInitializeGL() { + LDEBUG("PostprocessingModule::internalInitializeGL"); + _postprocessingRenderer.initializeGL(); +} + +void PostprocessingModule::internalDeinitializeGL() { + LDEBUG("PostprocessingModule::internalDeinitializeGL"); + _postprocessingRenderer.deinitializeGL(); +} + +} // namespace openspace diff --git a/modules/postprocessing/postprocessingmodule.h b/modules/postprocessing/postprocessingmodule.h new file mode 100644 index 0000000000..c569f186ba --- /dev/null +++ b/modules/postprocessing/postprocessingmodule.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_MODULE___H__ +#define __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_MODULE___H__ + +#include + +#include + +#include +#include +#include + +namespace openspace { + +class PostprocessingModule : public OpenSpaceModule { + +public: + constexpr static const char* Name = "Postprocessing"; + PostprocessingModule(); + + static PostprocessingRenderer& renderer(); + +private: + void internalInitialize(const ghoul::Dictionary&) override; + void internalInitializeGL() override; + void internalDeinitializeGL() override; + + static PostprocessingRenderer _postprocessingRenderer; + +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_MODULE___H__ diff --git a/modules/postprocessing/rendering/postprocessingrenderer.cpp b/modules/postprocessing/rendering/postprocessingrenderer.cpp new file mode 100644 index 0000000000..75037f79c2 --- /dev/null +++ b/modules/postprocessing/rendering/postprocessingrenderer.cpp @@ -0,0 +1,667 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + + constexpr const char* _loggerCat = "Postprocessing"; + + constexpr const std::array lensflarePassUniformNames = { "mainColorTexture" }; + constexpr const std::array lensflareFeatureUniformNames = { + "mainColorTexture", "aspectRatio", "chromaticDistortion", "colorGradientAlpha", "dustAlpha", + "dustTexture", "ghostsAlpha", "ghostsDispersal", "ghostsNumber", "ghostsWeight", + "gradientTexture", "haloAlpha", "haloWidth", "haloWeight", "starAlpha", + "starRotation", "starTexture", "thesholdBias", "thesholdScale" + }; + constexpr const std::array blurUniformNames = { "mainColorTexture", "blurDirection", "blurMagnitude" }; + constexpr const std::array blendUniformNames = { "mainColorTexture", "effectsColorTexture", "exposure", "gamma" }; + constexpr const std::array bloomUniformNames = { "mainColorTexture", "threshold" }; + + constexpr const char* PassthroughVertexShaderPath = "${MODULES}/postprocessing/shaders/pass_vs.glsl"; + constexpr const char* PassthroughFragmentShaderPath = "${MODULES}/postprocessing/shaders/pass_fs.glsl"; + constexpr const char* BloomShaderPath = "${MODULES}/postprocessing/shaders/bloom_fs.glsl"; + constexpr const char* LensflareShaderPath = "${MODULES}/postprocessing/shaders/lensflare_fs.glsl"; + constexpr const char* BlurShaderPath = "${MODULES}/postprocessing/shaders/blur_fs.glsl"; + constexpr const char* BlendShaderPath = "${MODULES}/postprocessing/shaders/blend_fs.glsl"; + constexpr const char* LenscolorImagePath = "${MODULES}/postprocessing/textures/lenscolor.png"; + constexpr const char* LensdirtImagePath = "${MODULES}/postprocessing/textures/lensdirt.png"; + constexpr const char* LensstarImagePath = "${MODULES}/postprocessing/textures/lensstar.png"; + + constexpr openspace::properties::Property::PropertyInfo EnableLensFlareInfo = { + "enableLensFlare", + "Enable Lens Flare", + "" + }; + constexpr openspace::properties::Property::PropertyInfo ChromaticDistortionInfo = { + "chromaticDistortion", + "Chromatic Distortion", + "The separation of red, green, and blue channels in lens flare" + }; + constexpr openspace::properties::Property::PropertyInfo ColorGradientAlphaInfo = { + "colorGradientAlpha", + "Color Gradient Alpha", + "Amount of radial gradient colorization applied globally to lens flare" + }; + constexpr openspace::properties::Property::PropertyInfo DownsampleInfo = { + "downsample", + "Downsample", + "Amount to downsample the lens flare effects" + }; + constexpr openspace::properties::Property::PropertyInfo DustAlphaInfo = { + "dustAlpha", + "Dust Alpha", + "Amount of dust and dirt applied globally to lens flare" + }; + constexpr openspace::properties::Property::PropertyInfo GhostsAlphaInfo = { + "ghostsAlpha", + "Ghosts Alpha", + "Intensity of lens flare internal reflections" + }; + constexpr openspace::properties::Property::PropertyInfo GhostsDispersalInfo = { + "ghostsDispersal", + "Ghosts Dispersal", + "Distance between lens flare internal reflections" + }; + constexpr openspace::properties::Property::PropertyInfo GhostsNumberInfo = { + "ghostsNumber", + "Ghosts Number", + "Number of lens flare internal reflections" + }; + constexpr openspace::properties::Property::PropertyInfo GhostsWeightInfo = { + "ghostsWeight", + "Ghosts Weight", + "Amount of radial falloff applied to lens flare internal reflections" + }; + constexpr openspace::properties::Property::PropertyInfo HaloAlphaInfo = { + "haloAlpha", + "Halo Alpha", + "Intensity of lens flare halo" + }; + constexpr openspace::properties::Property::PropertyInfo HaloWidthInfo = { + "haloWidth", + "Halo Width", + "Width of lens flare halo" + }; + constexpr openspace::properties::Property::PropertyInfo HaloWeightInfo = { + "haloWeight", + "Halo Weight", + "Amount of radial falloff applied to lens flare halo" + }; + constexpr openspace::properties::Property::PropertyInfo StarAlphaInfo = { + "starAlpha", + "Star Alpha", + "Intensity of lens flare starburst" + }; + constexpr openspace::properties::Property::PropertyInfo ThresholdBiasInfo = { + "thresholdBias", + "Threshold Bias", + "Bias of threshold that limits input to lens flare" + }; + constexpr openspace::properties::Property::PropertyInfo ThresholdScaleInfo = { + "thresholdScale", + "Threshold Scale", + "Scale of threshold that limits input to lens flare" + }; + + constexpr openspace::properties::Property::PropertyInfo EnableBloomInfo = { + "enableBloom", + "Enable Bloom", + "" + }; + constexpr openspace::properties::Property::PropertyInfo BloomThresholdInfo = { + "bloomThreshold", + "Bloom threshold", + "Threshold of the bloom effect" + }; + + constexpr openspace::properties::Property::PropertyInfo BlurPassNumberInfo = { + "blurPassNumber", + "Blur Pass Number", + "Number of blur passes" + }; + + constexpr openspace::properties::Property::PropertyInfo BlurMagnitudeInfo = { + "blurMagnitude", + "Blur Magnitude", + "Spread of blur" + }; + + constexpr openspace::properties::Property::PropertyInfo ExposureInfo = { + "exposure", + "Exposure", + "" + }; + constexpr openspace::properties::Property::PropertyInfo GammaInfo = { + "gamma", + "Gamma", + "" + }; + +} // namespace + +namespace openspace { + +PostprocessingRenderer::PostprocessingRenderer() + : properties::PropertyOwner({ "PostprocessingRenderer", "Postprocessing", "Renderer for post-processing effects" }) + , _enableLensFlareP(EnableLensFlareInfo, false) + , _chromaticDistortionP(ChromaticDistortionInfo, -2.25f, -100.0f, 100.0f) + , _colorGradientAlphaP(ColorGradientAlphaInfo, 0.5f, 0.0f, 1.0f) + , _downsampleP(DownsampleInfo, 2.0f, 1.0f, 8.0f) + , _dustAlphaP(DustAlphaInfo, 0.75f, 0.0f, 1.0f) + , _ghostsAlphaP(GhostsAlphaInfo, 10.0f, 0.0f, 100.0f) + , _ghostsDispersalP(GhostsDispersalInfo, 0.7f, 0.0f, 2.0f) + , _ghostsNumberP(GhostsNumberInfo, 3, 1, 9) + , _ghostsWeightP(GhostsWeightInfo, 127.5f, 0.0f, 200.0f) + , _haloAlphaP(HaloAlphaInfo, 0.125f, 0.0f, 10.0f) + , _haloWidthP(HaloWidthInfo, 0.75f, -1.0f, 1.0f) + , _haloWeightP(HaloWeightInfo, 0.375f, 0.0f, 2.0f) + , _starAlphaP(StarAlphaInfo, 9.0f, 0.0f, 10.0f) + , _thesholdBiasP(ThresholdBiasInfo, -0.6f, -1.0f, 1.0f) + , _thesholdScaleP(ThresholdScaleInfo, 9.0f, 0.0f, 20.0f) + , _enableBloomP(EnableBloomInfo, false) + , _bloomThresholdP(BloomThresholdInfo, 0.75f, 0.0f, 1.0f) + , _blurPassNumberP(BlurPassNumberInfo, 3, 0, 10) + , _blurMagnitudeP(BlurMagnitudeInfo, 0.001f, 0.0f, 0.01f) + , _exposureP(ExposureInfo, 0.0f, 0.0f, 10.0f) + , _gammaP(GammaInfo, 1.0f, 0.0f, 10.0f) +{ + LDEBUG("PostprocessingRenderer::PostprocessingRenderer"); + + addProperty(_enableLensFlareP); + addProperty(_chromaticDistortionP); + addProperty(_colorGradientAlphaP); + _downsampleP.onChange([this]{ updateResolution(); }); + addProperty(_downsampleP); + addProperty(_dustAlphaP); + addProperty(_ghostsAlphaP); + addProperty(_ghostsDispersalP); + addProperty(_ghostsNumberP); + addProperty(_ghostsWeightP); + addProperty(_haloAlphaP); + addProperty(_haloWidthP); + addProperty(_haloWeightP); + addProperty(_starAlphaP); + addProperty(_thesholdBiasP); + addProperty(_thesholdScaleP); + + addProperty(_enableBloomP); + addProperty(_bloomThresholdP); + + addProperty(_blurPassNumberP); + addProperty(_blurMagnitudeP); + + addProperty(_exposureP); + addProperty(_gammaP); + +} + +bool PostprocessingRenderer::isEnabled(){ + bool enabled = false; + enabled |= _enableBloomP; + enabled |= _enableLensFlareP; + return enabled; +} + +void PostprocessingRenderer::bindFramebuffer(){ + glBindFramebuffer(GL_FRAMEBUFFER, _sceneFramebuffer); + GLenum db[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, db); +} + +GLuint PostprocessingRenderer::framebuffer(){ + return _sceneFramebuffer; +} + +void PostprocessingRenderer::initialize(const ghoul::Dictionary&) { + LDEBUG("PostprocessingRenderer::initialize"); + global::screenSpaceRootPropertyOwner.addPropertySubOwner(this); +} + +void PostprocessingRenderer::initializeGL() { + LDEBUG("PostprocessingRenderer::initializeGL"); + + const GLfloat vertexData[] = { + // x y + -1.f, -1.f, + 1.f, 1.f, + -1.f, 1.f, + -1.f, -1.f, + 1.f, -1.f, + 1.f, 1.f, + }; + + glGenVertexArrays(1, &_screenQuad); + glBindVertexArray(_screenQuad); + + glGenBuffers(1, &_vertexPositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr); + glEnableVertexAttribArray(0); + + // Post processing framebuffer + glGenTextures(1, &_sceneTexture); + glGenFramebuffers(1, &_sceneFramebuffer); + + // Lens flare framebuffers + glGenTextures(_postTexturesNumber, _postTextures); + glGenFramebuffers(1, &_postFramebuffer); + + updateResolution(); + + glBindFramebuffer(GL_FRAMEBUFFER, _sceneFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + _sceneTexture, + 0 + ); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Post processing framebuffer is not complete"); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + for (int i = 0; i < _postTexturesNumber; i++ ){ + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0+i, + GL_TEXTURE_2D, + _postTextures[i], + 0 + ); + } + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Lensflare framebuffer is not complete"); + } + + _bloomProgram = ghoul::opengl::ProgramObject::Build( + "Bloom", + absPath(PassthroughVertexShaderPath), + absPath(BloomShaderPath) + ); + ghoul::opengl::updateUniformLocations(*_bloomProgram, _bloomUniformCache, bloomUniformNames); + + _lensflarePassProgram = ghoul::opengl::ProgramObject::Build( + "Lens Flare Passthrough", + absPath(PassthroughVertexShaderPath), + absPath(PassthroughFragmentShaderPath) + ); + ghoul::opengl::updateUniformLocations(*_lensflarePassProgram, _lensflarePassUniformCache, lensflarePassUniformNames); + + _lensflareFeatureProgram = ghoul::opengl::ProgramObject::Build( + "Lens Flare Features", + absPath(PassthroughVertexShaderPath), + absPath(LensflareShaderPath) + ); + ghoul::opengl::updateUniformLocations(*_lensflareFeatureProgram, _lensflareFeatureUniformCache, lensflareFeatureUniformNames); + + _blurProgram = ghoul::opengl::ProgramObject::Build( + "Lens Flare Blur", + absPath(PassthroughVertexShaderPath), + absPath(BlurShaderPath) + ); + ghoul::opengl::updateUniformLocations(*_blurProgram, _blurUniformCache, blurUniformNames); + + _blendProgram = ghoul::opengl::ProgramObject::Build( + "Lens Flare Blend", + absPath(PassthroughVertexShaderPath), + absPath(BlendShaderPath) + ); + ghoul::opengl::updateUniformLocations(*_blendProgram, _blendUniformCache, blendUniformNames); + + _lensflareGradientTexture = ghoul::io::TextureReader::ref().loadTexture( absPath(LenscolorImagePath) ); + if (_lensflareGradientTexture) { + LDEBUG(fmt::format("Loaded texture from '{}'", absPath(LenscolorImagePath) )); + _lensflareGradientTexture->uploadTexture(); + } + _lensflareDustTexture = ghoul::io::TextureReader::ref().loadTexture( absPath(LensdirtImagePath) ); + if (_lensflareDustTexture) { + LDEBUG(fmt::format("Loaded texture from '{}'", absPath(LensdirtImagePath) )); + _lensflareDustTexture->uploadTexture(); + } + _lensflareStarTexture = ghoul::io::TextureReader::ref().loadTexture( absPath(LensstarImagePath) ); + if (_lensflareStarTexture) { + LDEBUG(fmt::format("Loaded texture from '{}'", absPath(LensstarImagePath) )); + _lensflareStarTexture->uploadTexture(); + } + +} + +void PostprocessingRenderer::deinitializeGL() { + LDEBUG("PostprocessingRenderer::deinitializeGL"); + glDeleteTextures(1, &_sceneTexture); + glDeleteFramebuffers(1, &_sceneFramebuffer); + + glDeleteTextures(_postTexturesNumber, _postTextures); + glDeleteFramebuffers(1, &_postFramebuffer); + + glDeleteBuffers(1, &_vertexPositionBuffer); + glDeleteVertexArrays(1, &_screenQuad); +} + +void PostprocessingRenderer::updateResolution(){ + _resolution = global::renderEngine.renderingResolution(); + _resolutionLow = glm::ivec2( static_cast(_resolution.x) / _downsampleP, static_cast(_resolution.y) / _downsampleP ); + _aspectRatio = static_cast(_resolution.x) / static_cast(_resolution.y); + + glBindTexture(GL_TEXTURE_2D, _sceneTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _resolution.x, _resolution.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + for (int i = 0; i < _postTexturesNumber; i++ ){ + glBindTexture(GL_TEXTURE_2D, _postTextures[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _resolutionLow.x, _resolutionLow.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } +} + +void PostprocessingRenderer::update() { + + bool resolutionIsDirty = _resolution != global::renderEngine.renderingResolution(); + if (resolutionIsDirty){ + updateResolution(); + } + + if (_enableBloomP){ + + if (_bloomProgram->isDirty()) { + _bloomProgram->rebuildFromFile(); + + ghoul::opengl::updateUniformLocations( + *_bloomProgram, + _bloomUniformCache, + bloomUniformNames + ); + } + + } + + if (_enableLensFlareP){ + + if (_lensflarePassProgram->isDirty()) { + _lensflarePassProgram->rebuildFromFile(); + + ghoul::opengl::updateUniformLocations( + *_lensflarePassProgram, + _lensflarePassUniformCache, + lensflarePassUniformNames + ); + } + + } + + if (_enableBloomP || _enableLensFlareP){ + + if (_blurProgram->isDirty()) { + _blurProgram->rebuildFromFile(); + + ghoul::opengl::updateUniformLocations( + *_blurProgram, + _blurUniformCache, + blurUniformNames + ); + } + + if (_blendProgram->isDirty()) { + _blendProgram->rebuildFromFile(); + + ghoul::opengl::updateUniformLocations( + *_blendProgram, + _blendUniformCache, + blendUniformNames + ); + } + + } + +} + +void PostprocessingRenderer::render(Camera* camera) { + + if (isEnabled()){ + + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + int bloomTex = 1; + int lensflareTex = 2; + int outputTex = 0; + + // if only rendering one or the other, skip blend step, so render to output texture + if (_enableBloomP && !_enableLensFlareP) bloomTex = outputTex; + if (_enableLensFlareP && !_enableBloomP) lensflareTex = outputTex; + + if (_enableBloomP){ + + // bloom + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + glViewport(0,0,_resolutionLow.x,_resolutionLow.y); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + bloomTex); + _bloomProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _sceneTexture); + _bloomProgram->setUniform(_bloomUniformCache.mainColorTexture, mainColorTextureUnit); + + _bloomProgram->setUniform(_bloomUniformCache.threshold, _bloomThresholdP ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _bloomProgram->deactivate(); + + } + + if (_enableLensFlareP){ + + // lens flare features + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + glViewport(0,0,_resolutionLow.x,_resolutionLow.y); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + lensflareTex); + _lensflareFeatureProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _sceneTexture); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.mainColorTexture, mainColorTextureUnit); + + ghoul::opengl::TextureUnit dustUnit; + dustUnit.activate(); + _lensflareDustTexture->bind(); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.dustTexture, dustUnit ); + + ghoul::opengl::TextureUnit gradientUnit; + gradientUnit.activate(); + _lensflareGradientTexture->bind(); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.gradientTexture, gradientUnit ); + + ghoul::opengl::TextureUnit starUnit; + starUnit.activate(); + _lensflareStarTexture->bind(); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.starTexture, starUnit ); + + glm::dvec3 cameraViewDirection = camera->viewDirectionWorldSpace(); + float starRotation = cameraViewDirection.x + cameraViewDirection.y + cameraViewDirection.z; + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.starRotation, starRotation ); + + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.aspectRatio, _aspectRatio ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.chromaticDistortion, _chromaticDistortionP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.colorGradientAlpha, _colorGradientAlphaP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.dustAlpha, _dustAlphaP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.ghostsAlpha, _ghostsAlphaP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.ghostsDispersal, _ghostsDispersalP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.ghostsNumber, _ghostsNumberP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.ghostsWeight, _ghostsWeightP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.haloAlpha, _haloAlphaP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.haloWidth, _haloWidthP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.haloWeight, _haloWeightP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.starAlpha, _starAlphaP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.thesholdBias, _thesholdBiasP ); + _lensflareFeatureProgram->setUniform(_lensflareFeatureUniformCache.thesholdScale, _thesholdScaleP ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _lensflareFeatureProgram->deactivate(); + + } + + if (_enableBloomP && _enableLensFlareP) { + + // blend effects with original texture + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + glViewport(0,0,_resolutionLow.x,_resolutionLow.y); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + outputTex); + _blendProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _postTextures[bloomTex]); + _blendProgram->setUniform(_blendUniformCache.mainColorTexture, mainColorTextureUnit); + + ghoul::opengl::TextureUnit effectsColorTextureUnit; + effectsColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _postTextures[lensflareTex]); + _blendProgram->setUniform(_blendUniformCache.effectsColorTexture, effectsColorTextureUnit); + + _blendProgram->setUniform(_blendUniformCache.exposure, 0.0f ); + _blendProgram->setUniform(_blendUniformCache.gamma, 1.0f ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _blendProgram->deactivate(); + + } + + for (int i = 0; i < _blurPassNumberP; i++){ + + { // blur horizontal + + int src = 0; + int dst = 1; + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + glViewport(0,0,_resolutionLow.x,_resolutionLow.y); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + dst); + _blurProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _postTextures[src]); + _blurProgram->setUniform(_blurUniformCache.mainColorTexture, mainColorTextureUnit); + _blurProgram->setUniform(_blurUniformCache.blurDirection, glm::vec2(1.0f,0.0f) ); + _blurProgram->setUniform(_blurUniformCache.blurMagnitude, _blurMagnitudeP ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _blurProgram->deactivate(); + + } + + { // blur vertical + + int src = 1; + int dst = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, _postFramebuffer); + glViewport(0,0,_resolutionLow.x,_resolutionLow.y); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + dst); + _blurProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _postTextures[src]); + _blurProgram->setUniform(_blurUniformCache.mainColorTexture, mainColorTextureUnit); + _blurProgram->setUniform(_blurUniformCache.blurDirection, glm::vec2(0.0f,1.0f) ); + _blurProgram->setUniform(_blurUniformCache.blurMagnitude, _blurMagnitudeP ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _blurProgram->deactivate(); + + } + + } + + { // blend effects with original texture + + int src = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + glViewport(0,0,_resolution.x,_resolution.y); + _blendProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _sceneTexture); + _blendProgram->setUniform(_blendUniformCache.mainColorTexture, mainColorTextureUnit); + + ghoul::opengl::TextureUnit effectsColorTextureUnit; + effectsColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _postTextures[src]); + _blendProgram->setUniform(_blendUniformCache.effectsColorTexture, effectsColorTextureUnit); + + _blendProgram->setUniform(_blendUniformCache.exposure, _exposureP ); + _blendProgram->setUniform(_blendUniformCache.gamma, _gammaP ); + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _blendProgram->deactivate(); + + } + + } + +} + +} // namespace openspace diff --git a/modules/postprocessing/rendering/postprocessingrenderer.h b/modules/postprocessing/rendering/postprocessingrenderer.h new file mode 100644 index 0000000000..351c61b3f4 --- /dev/null +++ b/modules/postprocessing/rendering/postprocessingrenderer.h @@ -0,0 +1,119 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_RENDERER___H__ +#define __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_RENDERER___H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace openspace { + +class PostprocessingRenderer : public properties::PropertyOwner { + +public: + PostprocessingRenderer(); + void initialize(const ghoul::Dictionary&); + void initializeGL(); + void deinitializeGL(); + void update(); + void updateResolution(); + void render(Camera* camera); + GLuint framebuffer(); + bool isEnabled(); + void bindFramebuffer(); + +private: + + glm::ivec2 _resolution = glm::ivec2(0); + glm::ivec2 _resolutionLow = glm::ivec2(0); + float _aspectRatio = 16.0f/9.0f; + + GLuint _screenQuad; + GLuint _vertexPositionBuffer; + + std::unique_ptr _lensflarePassProgram; + UniformCache(mainColorTexture) _lensflarePassUniformCache; + std::unique_ptr _lensflareFeatureProgram; + UniformCache( + mainColorTexture, aspectRatio, chromaticDistortion, colorGradientAlpha, dustAlpha, dustTexture, ghostsAlpha, + ghostsDispersal, ghostsNumber, ghostsWeight, gradientTexture, haloAlpha, haloWidth, haloWeight, starAlpha, + starRotation, starTexture, thesholdBias, thesholdScale + ) _lensflareFeatureUniformCache; + + std::unique_ptr _bloomProgram; + UniformCache(mainColorTexture, threshold) _bloomUniformCache; + + std::unique_ptr _blurProgram; + UniformCache(mainColorTexture, blurDirection, blurMagnitude) _blurUniformCache; + + std::unique_ptr _blendProgram; + UniformCache(mainColorTexture, effectsColorTexture, exposure, gamma) _blendUniformCache; + + GLuint _sceneFramebuffer; + GLuint _sceneTexture; + GLuint _postFramebuffer; + static const int _postTexturesNumber = 3; + GLuint _postTextures[_postTexturesNumber]; + + std::unique_ptr _lensflareGradientTexture; + std::unique_ptr _lensflareDustTexture; + std::unique_ptr _lensflareStarTexture; + + properties::BoolProperty _enableLensFlareP; + properties::FloatProperty _chromaticDistortionP; + properties::FloatProperty _colorGradientAlphaP; + properties::IntProperty _downsampleP; + properties::FloatProperty _dustAlphaP; + properties::FloatProperty _ghostsAlphaP; + properties::FloatProperty _ghostsDispersalP; + properties::IntProperty _ghostsNumberP; + properties::FloatProperty _ghostsWeightP; + properties::FloatProperty _haloAlphaP; + properties::FloatProperty _haloWidthP; + properties::FloatProperty _haloWeightP; + properties::FloatProperty _starAlphaP; + properties::FloatProperty _thesholdBiasP; + properties::FloatProperty _thesholdScaleP; + + properties::BoolProperty _enableBloomP; + properties::FloatProperty _bloomThresholdP; + + properties::IntProperty _blurPassNumberP; + properties::FloatProperty _blurMagnitudeP; + + properties::FloatProperty _exposureP; + properties::FloatProperty _gammaP; + +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_POSTPROCESSING___POSTPROCESSING_RENDERER___H__ diff --git a/modules/postprocessing/shaders/blend_fs.glsl b/modules/postprocessing/shaders/blend_fs.glsl new file mode 100644 index 0000000000..a81d6f2862 --- /dev/null +++ b/modules/postprocessing/shaders/blend_fs.glsl @@ -0,0 +1,51 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout (location = 0) out vec4 finalColor; + +in vec2 UV; + +uniform sampler2D mainColorTexture; +uniform sampler2D effectsColorTexture; +uniform float exposure; +uniform float gamma; + +void main() { + vec3 scene = texture(mainColorTexture, UV).rgb; + vec3 effects = texture(effectsColorTexture, UV).rgb; + + vec3 color = scene + effects; + + // tone mapping + if (exposure > 0.0){ + color = vec3(1.0) - exp(-color * exposure); + } + + // gamma correction + color = pow(color, vec3(1.0 / gamma)); + + finalColor = vec4(color, 1.0); +} diff --git a/modules/postprocessing/shaders/bloom_fs.glsl b/modules/postprocessing/shaders/bloom_fs.glsl new file mode 100644 index 0000000000..586ad67033 --- /dev/null +++ b/modules/postprocessing/shaders/bloom_fs.glsl @@ -0,0 +1,43 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout (location = 0) out vec4 finalColor; + +in vec2 UV; + +uniform sampler2D mainColorTexture; +uniform float threshold; + +void main() { + vec4 color = vec4(0.0); + color = texture(mainColorTexture, UV); + float brightness = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); + if (brightness > threshold){ + finalColor = vec4(color.rgb, 1.0); + }else{ + finalColor = vec4(0.0, 0.0, 0.0, 1.0); + } +} diff --git a/modules/postprocessing/shaders/blur_fs.glsl b/modules/postprocessing/shaders/blur_fs.glsl new file mode 100644 index 0000000000..bd5578006f --- /dev/null +++ b/modules/postprocessing/shaders/blur_fs.glsl @@ -0,0 +1,91 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout (location = 0) out vec4 finalColor; + +in vec2 UV; + +uniform sampler2D mainColorTexture; +uniform vec2 blurDirection; +uniform float blurMagnitude; + +// Linear sampling, 9-tap +// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ + +// 9-tap, sigma = 1.0 +// 0.382928, 0.241732, 0.060598, 0.005977, 0.000229 +// uniform int n = 3; +// uniform float offset[3] = float[]( 0, 1.200436609003407, 3.0368997744118595 ); +// uniform float weight[3] = float[]( 0.382928, 0.30233, 0.006206 ); + +// 9-tap, sigma = 1.75 +// 0.227204, 0.193829, 0.120338, 0.054364, 0.017867 +// uniform int n = 3; +// uniform float offset[3] = float[]( 0.227204, 1.383038320383745, 3.247359167116612 ); +// uniform float weight[3] = float[]( 0, 0.314167, 0.072231 ); + +// 9-tap, sigma = 15 +// 0.112759, 0.112509, 0.111762, 0.110527, 0.108822 +uniform int n = 3; +uniform float offset[3] = float[]( 0, 1.4983346041173402, 3.4961134994916776 ); +uniform float weight[3] = float[]( 0.112759, 0.224271, 0.21934900000000002 ); + +// 17-tap, sigma = 3.0 +// 0.13298, 0.125858, 0.106701, 0.081029, 0.055119, 0.033585, 0.018331, 0.008962, 0.003924 +// uniform int n = 5; +// uniform float offset[5] = float[]( 0.13298, 1.4588126023933712, 3.4048461967858508, 5.35308960628708, 7.304516529566972 ); +// uniform float weight[5] = float[]( 0, 0.23255900000000002, 0.136148, 0.051916, 0.012886 ); + +// 33-tap, sigma = 5.0 +// 0.079733, 0.078159, 0.073622, 0.066638, 0.05796, 0.048441, 0.038903, 0.030022, 0.022263, 0.015864, 0.010863, 0.007147, 0.004519, 0.002745, 0.001603, 0.000899, 0.000485 +// uniform int n = 9; +// uniform float offset[9] = float[]( 0, 1.48505412403397, 3.4651760060354095, 5.445399798497894, 7.425800898919384, 9.406442922886967, 11.387364992285274, 13.36867525298988, 15.35043352601156 ); +// uniform float weight[9] = float[]( 0.079733, 0.151781, 0.124598, 0.087344, 0.052285, 0.026727, 0.011666, 0.004348, 0.001384 ); + +// 33-tap, sigma = 15.0 +// 0.036493, 0.036412, 0.03617, 0.035771, 0.035219, 0.034522, 0.033688, 0.032729, 0.031657, 0.030483, 0.029224, 0.027892, 0.026502, 0.025071, 0.023611, 0.022138, 0.020665 +// uniform int n = 9; +// uniform float offset[9] = float[]( 0, 1.4983329200077153, 3.4961121284687984, 5.493886526902214, 7.491675208896344, 9.489456847605808, 11.487222855461999, 13.485004724538843, 15.482793262154521 ); +// uniform float weight[9] = float[]( 0.036493, 0.07258200000000001, 0.07099, 0.06820999999999999, 0.064386, 0.059706999999999996, 0.054394, 0.048682, 0.042803 ); + +void main() { + vec4 sum = vec4(0.0); + vec2 tc = UV; + float mag = blurMagnitude; + float hstep = blurDirection.x; + float vstep = blurDirection.y; + float h = mag*hstep; + float v = mag*vstep; + + sum = texture( mainColorTexture, tc ) * weight[0]; + for (int i=1; iw ) return 0.0; + x /= w; + return 1.0 - x*x*(3.0-2.0*x); +} + +// https://gist.github.com/ayamflow/c06bc0c8a64f985dd431bd0ac5b557cd +vec2 rotateUV(vec2 uv, float rotation) { + float mid = 0.5; + return vec2( + cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid, + cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid + ); +} + +vec3 textureDistorted(sampler2D tex, vec2 texcoord, vec2 direction, vec3 distortion) { + return vec3( + texture(tex, texcoord + direction * distortion.r).r, + texture(tex, texcoord + direction * distortion.g).g, + texture(tex, texcoord + direction * distortion.b).b + ); +} + +vec3 sampleScaledBiasedTexture(sampler2D tex, vec2 uv){ + return max(vec3(0.0), texture( mainColorTexture, uv ).xyz + thesholdBias) * thesholdScale; +} + +vec3 sampleScaledBiasedTexture(sampler2D tex, vec2 uv, vec2 direction, vec3 distortion){ + return max(vec3(0.0), textureDistorted( mainColorTexture, uv, direction, distortion ).xyz + thesholdBias) * thesholdScale; +} + +// http://john-chapman-graphics.blogspot.com/2013/02/pseudo-lens-flare.html +// https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html +void main(){ + + vec3 color = vec3(0.0); + + vec2 texelSize = 1.0 / vec2(textureSize(mainColorTexture, 0)); + + vec2 texcoord = -UV + vec2(1.0); // flip image + vec2 ghostVec = (vec2(0.5) - texcoord) * ghostsDispersal; + vec3 distortion = vec3(-texelSize.x * chromaticDistortion, 0.0, texelSize.x * chromaticDistortion); + vec2 direction = normalize(ghostVec); + vec2 circVec = vec2(ghostVec.x*aspectRatio, ghostVec.y); + float offset = 0.5 * (1.0 - aspectRatio); + float offsetY = 0.5 * (1.0 - 1.0/aspectRatio); + + // ghosts + for (int i = 0; i < ghostsNumber; ++i) { + vec2 offset = fract(texcoord + ghostVec * float(i)); + + // falloff from center + float weight = length(vec2(0.5) - offset) / length(vec2(0.5)); + weight = pow(1.0 - weight, ghostsWeight); + + color += ghostsAlpha * sampleScaledBiasedTexture(mainColorTexture, offset, direction, distortion) * weight; + } + + // halo + vec3 haloColor = vec3(0.0); + vec2 haloVec = vec2(0.5) - UV; + haloVec.x *= aspectRatio; + haloVec = normalize(haloVec); + haloVec.x /= aspectRatio; + haloVec *= haloWidth; + float d = distance( vec2(UV.x*aspectRatio+offset,UV.y), vec2(0.5) ); + float weight = cubicPulse( haloWidth, haloWeight, d ); + haloColor += 3.0 * haloAlpha * sampleScaledBiasedTexture(mainColorTexture, UV + haloVec, direction, distortion).xyz * weight; + + // star + vec2 starUV = vec2(UV.x , UV.y / aspectRatio + offsetY); + starUV = rotateUV(starUV, starRotation); + haloColor *= starAlpha * textureDistorted(starTexture, starUV, direction, distortion).xyz; + color += haloColor; + + // color gradient + vec2 circUV = vec2(UV.x , UV.y / aspectRatio + offsetY); + float xy = length(vec2(0.5) - circUV) / length(vec2(0.5)); + vec3 gradientColor = texture(gradientTexture, vec2(xy,0.0) ).xyz; + color *= mix( vec3(1.0), gradientColor, colorGradientAlpha ); + + // dust + color *= mix( vec3(1.0), texture(dustTexture, UV).xyz, dustAlpha ); + + finalColor = vec4(color.rgb,1.0); + + finalColor.r *= 0.75; + finalColor.g *= 0.95; + finalColor.b *= 1.00; + +} + diff --git a/modules/postprocessing/shaders/pass_fs.glsl b/modules/postprocessing/shaders/pass_fs.glsl new file mode 100644 index 0000000000..f7582b9aa7 --- /dev/null +++ b/modules/postprocessing/shaders/pass_fs.glsl @@ -0,0 +1,37 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout (location = 0) out vec4 finalColor; + +in vec2 UV; + +uniform sampler2D mainColorTexture; + +void main() { + vec4 color = vec4(0.0); + color = texture(mainColorTexture, UV); + finalColor = vec4(color.rgb, 1.0); +} diff --git a/modules/postprocessing/shaders/pass_vs.glsl b/modules/postprocessing/shaders/pass_vs.glsl new file mode 100644 index 0000000000..ae6a4cf3b6 --- /dev/null +++ b/modules/postprocessing/shaders/pass_vs.glsl @@ -0,0 +1,34 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +in vec4 position; + +out vec2 UV; + +void main() { + gl_Position = position; + UV = 0.5 + position.xy * 0.5; +} diff --git a/modules/postprocessing/textures/lenscolor.png b/modules/postprocessing/textures/lenscolor.png new file mode 100644 index 0000000000..34d9abd306 Binary files /dev/null and b/modules/postprocessing/textures/lenscolor.png differ diff --git a/modules/postprocessing/textures/lensdirt.png b/modules/postprocessing/textures/lensdirt.png new file mode 100644 index 0000000000..bcd7932a88 Binary files /dev/null and b/modules/postprocessing/textures/lensdirt.png differ diff --git a/modules/postprocessing/textures/lensstar.png b/modules/postprocessing/textures/lensstar.png new file mode 100644 index 0000000000..ddc48e60ec Binary files /dev/null and b/modules/postprocessing/textures/lensstar.png differ diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 7b5502cc3b..522c6599e2 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -48,6 +48,10 @@ #include #include +#ifdef OPENSPACE_MODULE_POSTPROCESSING_ENABLED +#include +#endif + namespace { constexpr const char* _loggerCat = "FramebufferRenderer"; @@ -294,6 +298,10 @@ void FramebufferRenderer::update() { if (_hdrBackGroundProgram && _hdrBackGroundProgram->isDirty()) { _hdrBackGroundProgram->rebuildFromFile(); } + + #ifdef OPENSPACE_MODULE_POSTPROCESSING_ENABLED + PostprocessingModule::renderer().update(); + #endif if (_resolveProgram->isDirty()) { _resolveProgram->rebuildFromFile(); @@ -977,9 +985,19 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac performRaycasterTasks(tasks.raycasterTasks); } - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - GLenum dBuffer[1] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, dBuffer); + #ifdef OPENSPACE_MODULE_POSTPROCESSING_ENABLED + if (PostprocessingModule::renderer().isEnabled()){ + PostprocessingModule::renderer().bindFramebuffer(); + }else{ + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + GLenum dBuffer[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, dBuffer); + } + #else + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + GLenum dBuffer[1] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, dBuffer); + #endif { std::unique_ptr perfInternal; @@ -1008,6 +1026,11 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac _resolveProgram->deactivate(); } + + #ifdef OPENSPACE_MODULE_POSTPROCESSING_ENABLED + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + PostprocessingModule::renderer().render(camera); + #endif } void FramebufferRenderer::performRaycasterTasks(const std::vector& tasks) {