From 0efee85bd835fb0fffe73cf9a519ace5ff595abb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 29 Jul 2016 00:36:43 +0200 Subject: [PATCH] Added tonemapping and sector based exposure control --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_renderbuffers.cpp | 41 ++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 4 ++ src/gl/renderer/gl_renderer.cpp | 8 ++- src/gl/renderer/gl_renderer.h | 5 ++ src/gl/scene/gl_scene.cpp | 79 +++++++++++++++++++++------ src/gl/shaders/gl_blurshader.cpp | 11 +--- src/gl/shaders/gl_tonemapshader.cpp | 65 ++++++++++++++++++++++ src/gl/shaders/gl_tonemapshader.h | 18 ++++++ src/gl/system/gl_wipe.cpp | 6 +- wadsrc/static/shaders/glsl/tonemap.fp | 65 ++++++++++++++++++++++ wadsrc/static/shaders/glsl/tonemap.vp | 11 ++++ 12 files changed, 284 insertions(+), 30 deletions(-) create mode 100644 src/gl/shaders/gl_tonemapshader.cpp create mode 100644 src/gl/shaders/gl_tonemapshader.h create mode 100644 wadsrc/static/shaders/glsl/tonemap.fp create mode 100644 wadsrc/static/shaders/glsl/tonemap.vp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e7ae8cbb..6009a2c37 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1108,6 +1108,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_presentshader.cpp gl/shaders/gl_bloomshader.cpp gl/shaders/gl_blurshader.cpp + gl/shaders/gl_tonemapshader.cpp gl/system/gl_interface.cpp gl/system/gl_framebuffer.cpp gl/system/gl_menu.cpp diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 52182c9da..590ea3935 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -97,10 +97,16 @@ void FGLRenderBuffers::Clear() glDeleteTextures(1, &mSceneTexture); if (mSceneDepthStencil != 0) glDeleteRenderbuffers(1, &mSceneDepthStencil); + if (mHudFB != 0) + glDeleteFramebuffers(1, &mHudFB); + if (mHudTexture != 0) + glDeleteTextures(1, &mHudTexture); mSceneFB = 0; mSceneTexture = 0; mSceneDepthStencil = 0; + mHudFB = 0; + mHudTexture = 0; mWidth = 0; mHeight = 0; } @@ -122,7 +128,9 @@ void FGLRenderBuffers::Setup(int width, int height) glActiveTexture(GL_TEXTURE0); glGenFramebuffers(1, &mSceneFB); + glGenFramebuffers(1, &mHudFB); glGenTextures(1, &mSceneTexture); + glGenTextures(1, &mHudTexture); glGenRenderbuffers(1, &mSceneDepthStencil); glBindTexture(GL_TEXTURE_2D, mSceneTexture); @@ -139,6 +147,16 @@ void FGLRenderBuffers::Setup(int width, int height) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mSceneTexture, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mSceneDepthStencil); + glBindTexture(GL_TEXTURE_2D, mHudTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, mHudFB); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mHudTexture, 0); + int bloomWidth = MAX(width / 2, 1); int bloomHeight = MAX(height / 2, 1); for (int i = 0; i < NumBloomLevels; i++) @@ -191,6 +209,17 @@ void FGLRenderBuffers::BindSceneFB() glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); } +//========================================================================== +// +// Makes the 2D/HUD frame buffer active +// +//========================================================================== + +void FGLRenderBuffers::BindHudFB() +{ + glBindFramebuffer(GL_FRAMEBUFFER, mHudFB); +} + //========================================================================== // // Makes the screen frame buffer active @@ -213,3 +242,15 @@ void FGLRenderBuffers::BindSceneTexture(int index) glActiveTexture(GL_TEXTURE0 + index); glBindTexture(GL_TEXTURE_2D, mSceneTexture); } + +//========================================================================== +// +// Binds the 2D/HUD frame buffer texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindHudTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + glBindTexture(GL_TEXTURE_2D, mHudTexture); +} diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 611d196d2..24d301d52 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -22,8 +22,10 @@ public: void Setup(int width, int height); void BindSceneFB(); + void BindHudFB(); void BindOutputFB(); void BindSceneTexture(int index); + void BindHudTexture(int index); static bool IsSupported() { return gl.version >= 3.3f; } @@ -39,6 +41,8 @@ private: GLuint mSceneTexture = 0; GLuint mSceneDepthStencil = 0; GLuint mSceneFB = 0; + GLuint mHudTexture = 0; + GLuint mHudFB = 0; GLuint mOutputFB = 0; }; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 2eed18bb9..264ff4c7f 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -64,6 +64,7 @@ #include "gl/shaders/gl_shader.h" #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" +#include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/textures/gl_texture.h" #include "gl/textures/gl_translate.h" @@ -115,6 +116,7 @@ void FGLRenderer::Initialize() mBloomExtractShader = new FBloomExtractShader(); mBloomCombineShader = new FBloomCombineShader(); mBlurShader = new FBlurShader(); + mTonemapShader = new FTonemapShader(); mPresentShader = new FPresentShader(); // Only needed for the core profile, because someone decided it was a good idea to remove the default VAO. @@ -168,6 +170,7 @@ FGLRenderer::~FGLRenderer() if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; if (mBlurShader) delete mBlurShader; + if (mTonemapShader) delete mTonemapShader; } //========================================================================== @@ -235,7 +238,10 @@ void FGLRenderer::Begin2D() if (FGLRenderBuffers::IsSupported()) { mBuffers->Setup(framebuffer->GetWidth(), framebuffer->GetHeight()); - mBuffers->BindSceneFB(); + if (mDrawingScene2D) + mBuffers->BindSceneFB(); + else + mBuffers->BindHudFB(); glViewport(0, 0, mOutputViewport.width, mOutputViewport.height); } else diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 6635c2353..39eddcbf0 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -22,6 +22,7 @@ class FGLRenderBuffers; class FBloomExtractShader; class FBloomCombineShader; class FBlurShader; +class FTonemapShader; class FPresentShader; inline float DEG2RAD(float deg) @@ -88,6 +89,7 @@ public: FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; FBlurShader *mBlurShader; + FTonemapShader *mTonemapShader; FPresentShader *mPresentShader; FTexture *gllight; @@ -106,6 +108,8 @@ public: GL_IRECT mOutputViewportLB; GL_IRECT mOutputViewport; + bool mDrawingScene2D = false; + float mCameraExposure = 1.0f; FGLRenderer(OpenGLFrameBuffer *fb); ~FGLRenderer() ; @@ -154,6 +158,7 @@ public: void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); void BloomScene(); + void TonemapScene(); void Flush(); void SetProjection(float fov, float ratio, float fovratio); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 0aa9f0444..2136e21a2 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -74,6 +74,7 @@ #include "gl/shaders/gl_shader.h" #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" +#include "gl/shaders/gl_tonemapshader.h" #include "gl/shaders/gl_presentshader.h" #include "gl/stereo3d/gl_stereo3d.h" #include "gl/stereo3d/scoped_view_shifter.h" @@ -219,11 +220,9 @@ void FGLRenderer::BloomScene() const float blurAmount = 4.0f; int sampleCount = 5; // Note: must be uneven number 3 to 15 - float exposure = 2.0f; + float exposure = mCameraExposure; - auto vbo = GLRenderer->mVBO; - - // TODO: Need a better way to share state with other parts of the pipeline + // TBD: Maybe need a better way to share state with other parts of the pipeline GLboolean blendEnabled, scissorEnabled; GLint currentProgram, blendEquationRgb, blendEquationAlpha, blendSrcRgb, blendSrcAlpha, blendDestRgb, blendDestAlpha; glGetBooleanv(GL_BLEND, &blendEnabled); @@ -251,12 +250,12 @@ void FGLRenderer::BloomScene() mBloomExtractShader->SceneTexture.Set(0); mBloomExtractShader->Exposure.Set(exposure); { - FFlatVertex *ptr = vbo->GetBuffer(); + FFlatVertex *ptr = mVBO->GetBuffer(); ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; - vbo->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -266,8 +265,8 @@ void FGLRenderer::BloomScene() { const auto &level = mBuffers->BloomLevels[i]; const auto &next = mBuffers->BloomLevels[i + 1]; - mBlurShader->BlurHorizontal(vbo, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(vbo, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height); + mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); + mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level.HTexture, next.VFramebuffer, next.Width, next.Height); } // Blur and upscale: @@ -276,8 +275,8 @@ void FGLRenderer::BloomScene() const auto &level = mBuffers->BloomLevels[i]; const auto &next = mBuffers->BloomLevels[i - 1]; - mBlurShader->BlurHorizontal(vbo, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); - mBlurShader->BlurVertical(vbo, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height); + mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level.VTexture, level.HFramebuffer, level.Width, level.Height); + mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level.HTexture, level.VFramebuffer, level.Width, level.Height); // Linear upscale: glBindFramebuffer(GL_FRAMEBUFFER, next.VFramebuffer); @@ -289,17 +288,17 @@ void FGLRenderer::BloomScene() mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); { - FFlatVertex *ptr = vbo->GetBuffer(); + FFlatVertex *ptr = mVBO->GetBuffer(); ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; - vbo->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } } - mBlurShader->BlurHorizontal(vbo, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); - mBlurShader->BlurVertical(vbo, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); + mBlurShader->BlurHorizontal(mVBO, blurAmount, sampleCount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height); + mBlurShader->BlurVertical(mVBO, blurAmount, sampleCount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height); // Add bloom back to scene texture: mBuffers->BindSceneFB(); @@ -314,12 +313,12 @@ void FGLRenderer::BloomScene() mBloomCombineShader->Bind(); mBloomCombineShader->BloomTexture.Set(0); { - FFlatVertex *ptr = vbo->GetBuffer(); + FFlatVertex *ptr = mVBO->GetBuffer(); ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; - vbo->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); } if (blendEnabled) @@ -332,7 +331,41 @@ void FGLRenderer::BloomScene() //----------------------------------------------------------------------------- // -// Run post processing steps and copy to frame buffer +// Tonemap scene texture and place the result in the HUD/2D texture +// +//----------------------------------------------------------------------------- + +void FGLRenderer::TonemapScene() +{ + GLboolean blendEnabled, scissorEnabled; + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); + + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + + mBuffers->BindHudFB(); + mBuffers->BindSceneTexture(0); + mTonemapShader->Bind(); + mTonemapShader->SceneTexture.Set(0); + mTonemapShader->Exposure.Set(mCameraExposure); + + FFlatVertex *ptr = mVBO->GetBuffer(); + ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; + ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; + ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; + ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; + mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP); + + if (blendEnabled) + glEnable(GL_BLEND); + if (scissorEnabled) + glEnable(GL_SCISSOR_TEST); +} + +//----------------------------------------------------------------------------- +// +// Gamma correct while copying to frame buffer // //----------------------------------------------------------------------------- @@ -406,7 +439,7 @@ void FGLRenderer::Flush() mPresentShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); mPresentShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); } - mBuffers->BindSceneTexture(0); + mBuffers->BindHudTexture(0); FFlatVertex *ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; @@ -938,6 +971,7 @@ void FGLRenderer::EndDrawScene(sector_t * viewsector) glDisable(GL_SCISSOR_TEST); BloomScene(); + TonemapScene(); } @@ -1042,6 +1076,13 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo mViewActor=camera; } + if (toscreen) + { + float light = viewsector->lightlevel / 255.0f; + float exposure = MAX(1.0f + (1.0f - light * light) * 1.5f, 0.5f); + mCameraExposure = mCameraExposure * 0.98f + exposure * 0.02f; + } + // 'viewsector' will not survive the rendering so it cannot be used anymore below. retval = viewsector; @@ -1056,6 +1097,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo // TODO: stereo specific viewport - needed when implementing side-by-side modes etc. SetOutputViewport(bounds); Set3DViewport(); + mDrawingScene2D = true; mCurrentFoV = fov; // Stereo mode specific perspective projection SetProjection( eye->GetProjection(fov, ratio, fovratio) ); @@ -1073,6 +1115,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo ProcessScene(toscreen); if (mainview) EndDrawScene(retval); // do not call this for camera textures. + mDrawingScene2D = false; eye->TearDown(); } stereo3dMode.TearDown(); diff --git a/src/gl/shaders/gl_blurshader.cpp b/src/gl/shaders/gl_blurshader.cpp index 6ed7573ee..aee8696d9 100644 --- a/src/gl/shaders/gl_blurshader.cpp +++ b/src/gl/shaders/gl_blurshader.cpp @@ -80,32 +80,29 @@ void FBlurShader::BlurHorizontal(FFlatVertexBuffer *vbo, float blurAmount, int s void FBlurShader::Blur(FFlatVertexBuffer *vbo, float blurAmount, int sampleCount, GLuint inputTexture, GLuint outputFrameBuffer, int width, int height, bool vertical) { - int error = glGetError(); BlurSetup *setup = GetSetup(blurAmount, sampleCount); - error = glGetError(); if (vertical) setup->VerticalShader->Bind(); else setup->HorizontalShader->Bind(); - error = glGetError(); + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, inputTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - error = glGetError(); + glBindFramebuffer(GL_FRAMEBUFFER, outputFrameBuffer); glViewport(0, 0, width, height); glDisable(GL_BLEND); - error = glGetError(); + FFlatVertex *ptr = vbo->GetBuffer(); ptr->Set(-1.0f, -1.0f, 0, 0.0f, 0.0f); ptr++; ptr->Set(-1.0f, 1.0f, 0, 0.0f, 1.0f); ptr++; ptr->Set(1.0f, -1.0f, 0, 1.0f, 0.0f); ptr++; ptr->Set(1.0f, 1.0f, 0, 1.0f, 1.0f); ptr++; vbo->RenderCurrent(ptr, GL_TRIANGLE_STRIP); - error = glGetError(); } //========================================================================== @@ -138,9 +135,7 @@ FBlurShader::BlurSetup *FBlurShader::GetSetup(float blurAmount, int sampleCount) blurSetup.VerticalShader->SetAttribLocation(0, "PositionInProjection"); blurSetup.VerticalShader->Link("vertical blur"); blurSetup.VerticalShader->Bind(); - int error = glGetError(); glUniform1i(glGetUniformLocation(*blurSetup.VerticalShader.get(), "SourceTexture"), 0); - error = glGetError(); blurSetup.HorizontalShader = std::make_shared(); blurSetup.HorizontalShader->Compile(FShaderProgram::Vertex, "horizontal blur vertex shader", vertexCode); diff --git a/src/gl/shaders/gl_tonemapshader.cpp b/src/gl/shaders/gl_tonemapshader.cpp new file mode 100644 index 000000000..44ea40012 --- /dev/null +++ b/src/gl/shaders/gl_tonemapshader.cpp @@ -0,0 +1,65 @@ +/* +** gl_tonemapshader.cpp +** Converts a HDR texture to 0-1 range by applying a tonemap operator +** +**--------------------------------------------------------------------------- +** Copyright 2016 Magnus Norddahl +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be +** covered by the terms of the GNU Lesser General Public License as published +** by the Free Software Foundation; either version 2.1 of the License, or (at +** your option) any later version. +** 5. Full disclosure of the entire project's source code, except for third +** party libraries is mandatory. (NOTE: This clause is non-negotiable!) +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "gl/system/gl_system.h" +#include "files.h" +#include "m_swap.h" +#include "v_video.h" +#include "gl/gl_functions.h" +#include "vectors.h" +#include "gl/system/gl_interface.h" +#include "gl/system/gl_framebuffer.h" +#include "gl/system/gl_cvars.h" +#include "gl/shaders/gl_tonemapshader.h" + +void FTonemapShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/tonemap.vp"); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/tonemap.fp"); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/tonemap"); + mShader.SetAttribLocation(0, "PositionInProjection"); + SceneTexture.Init(mShader, "InputTexture"); + Exposure.Init(mShader, "ExposureAdjustment"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_tonemapshader.h b/src/gl/shaders/gl_tonemapshader.h new file mode 100644 index 000000000..0380e31b8 --- /dev/null +++ b/src/gl/shaders/gl_tonemapshader.h @@ -0,0 +1,18 @@ +#ifndef __GL_TONEMAPSHADER_H +#define __GL_TONEMAPSHADER_H + +#include "gl_shaderprogram.h" + +class FTonemapShader +{ +public: + void Bind(); + + FBufferedUniform1i SceneTexture; + FBufferedUniform1f Exposure; + +private: + FShaderProgram mShader; +}; + +#endif \ No newline at end of file diff --git a/src/gl/system/gl_wipe.cpp b/src/gl/system/gl_wipe.cpp index 6b15e0b6d..1f1dedba3 100644 --- a/src/gl/system/gl_wipe.cpp +++ b/src/gl/system/gl_wipe.cpp @@ -158,7 +158,7 @@ bool OpenGLFrameBuffer::WipeStartScreen(int type) if (FGLRenderBuffers::IsSupported()) { - GLRenderer->mBuffers->BindSceneFB(); + GLRenderer->mBuffers->BindHudFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); } else @@ -193,7 +193,7 @@ void OpenGLFrameBuffer::WipeEndScreen() wipeendscreen->Bind(0, false, false); if (FGLRenderBuffers::IsSupported()) - GLRenderer->mBuffers->BindSceneFB(); + GLRenderer->mBuffers->BindHudFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -232,7 +232,7 @@ bool OpenGLFrameBuffer::WipeDo(int ticks) if (FGLRenderBuffers::IsSupported()) { - GLRenderer->mBuffers->BindSceneFB(); + GLRenderer->mBuffers->BindHudFB(); glViewport(0, 0, GLRenderer->mOutputViewport.width, GLRenderer->mOutputViewport.height); } diff --git a/wadsrc/static/shaders/glsl/tonemap.fp b/wadsrc/static/shaders/glsl/tonemap.fp new file mode 100644 index 000000000..e1e3d3497 --- /dev/null +++ b/wadsrc/static/shaders/glsl/tonemap.fp @@ -0,0 +1,65 @@ + +#version 330 + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D InputTexture; +uniform float ExposureAdjustment; + +vec3 Linear(vec3 c) +{ + //return pow(c, 2.2); + return c * c; // cheaper, but assuming gamma of 2.0 instead of 2.2 +} + +vec3 sRGB(vec3 c) +{ + //return pow(c, vec3(1.0 / 2.2)); + return sqrt(c); // cheaper, but assuming gamma of 2.0 instead of 2.2 +} + +vec3 TonemapLinear(vec3 color) +{ + return sRGB(color); +} + +vec3 TonemapReinhard(vec3 color) +{ + color = color / (1 + color); + return sRGB(color); +} + +vec3 TonemapHejlDawson(vec3 color) +{ + vec3 x = max(vec3(0), color - 0.004); + return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06); // no sRGB needed +} + +vec3 Uncharted2Tonemap(vec3 x) +{ + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; +} + +vec3 TonemapUncharted2(vec3 color) +{ + float W = 11.2; + float ExposureBias = 2.0; + vec3 curr = Uncharted2Tonemap(ExposureBias * color); + vec3 whiteScale = vec3(1) / Uncharted2Tonemap(vec3(W)); + return sRGB(curr * whiteScale); +} + +void main() +{ + vec3 color = texture(InputTexture, TexCoord).rgb; + color = color * ExposureAdjustment; + color = Linear(color); // needed because gzdoom's scene texture is not linear at the moment + FragColor = vec4(TonemapUncharted2(color), 1.0); +} diff --git a/wadsrc/static/shaders/glsl/tonemap.vp b/wadsrc/static/shaders/glsl/tonemap.vp new file mode 100644 index 000000000..b73fe7fc8 --- /dev/null +++ b/wadsrc/static/shaders/glsl/tonemap.vp @@ -0,0 +1,11 @@ + +#version 330 + +in vec4 PositionInProjection; +out vec2 TexCoord; + +void main() +{ + gl_Position = PositionInProjection; + TexCoord = PositionInProjection.xy * 0.5 + 0.5; +}