From 9076d462619a5c9a4020c28477365c2efa568ce1 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 29 Aug 2016 13:10:22 +0200 Subject: [PATCH 01/29] Added SSAO pass --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 107 ++++++++++- src/gl/renderer/gl_renderbuffers.cpp | 221 +++++++++++++++++----- src/gl/renderer/gl_renderbuffers.h | 24 ++- src/gl/renderer/gl_renderer.cpp | 5 + src/gl/renderer/gl_renderer.h | 9 + src/gl/scene/gl_scene.cpp | 9 +- src/gl/shaders/gl_ambientshader.cpp | 89 +++++++++ src/gl/shaders/gl_ambientshader.h | 39 ++++ src/gl/stereo3d/gl_stereo3d.cpp | 2 +- wadsrc/static/language.enu | 1 + wadsrc/static/menudef.zz | 1 + wadsrc/static/shaders/glsl/lineardepth.fp | 16 ++ wadsrc/static/shaders/glsl/ssao.fp | 117 ++++++++++++ 14 files changed, 580 insertions(+), 61 deletions(-) create mode 100644 src/gl/shaders/gl_ambientshader.cpp create mode 100644 src/gl/shaders/gl_ambientshader.h create mode 100644 wadsrc/static/shaders/glsl/lineardepth.fp create mode 100644 wadsrc/static/shaders/glsl/ssao.fp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73dba07c4e..039a03b52e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1125,6 +1125,7 @@ set( FASTMATH_SOURCES gl/shaders/gl_shaderprogram.cpp gl/shaders/gl_presentshader.cpp gl/shaders/gl_bloomshader.cpp + gl/shaders/gl_ambientshader.cpp gl/shaders/gl_blurshader.cpp gl/shaders/gl_colormapshader.cpp gl/shaders/gl_tonemapshader.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 7ce8be0adc..9df28ce5bd 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -55,6 +55,7 @@ #include "gl/renderer/gl_postprocessstate.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" +#include "gl/shaders/gl_ambientshader.h" #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" #include "gl/shaders/gl_tonemapshader.h" @@ -98,6 +99,20 @@ CVAR(Float, gl_lens_k, -0.12f, 0) CVAR(Float, gl_lens_kcube, 0.1f, 0) CVAR(Float, gl_lens_chromatic, 1.12f, 0) +CVAR(Bool, gl_ssao, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Bool, gl_ssao_debug, false, 0) +CVAR(Float, gl_ssao_bias, 0.5f, 0) +CVAR(Float, gl_ssao_radius, 100.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur_amount, 6.0f, 0) +{ + if (self < 0.1f) self = 0.1f; +} +CUSTOM_CVAR(Int, gl_ssao_blur_samples, 9, 0) +{ + if (self < 3 || self > 15 || self % 2 == 0) + self = 9; +} + EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -109,6 +124,96 @@ void FGLRenderer::RenderScreenQuad() GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); } +void FGLRenderer::PostProcessScene() +{ + if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture(); + AmbientOccludeScene(); + UpdateCameraExposure(); + BloomScene(); + TonemapScene(); + LensDistortScene(); +} + +//----------------------------------------------------------------------------- +// +// Adds ambient occlusion to the scene +// +//----------------------------------------------------------------------------- + +void FGLRenderer::AmbientOccludeScene() +{ + if (!gl_ssao || !FGLRenderBuffers::IsEnabled()) + return; + + FGLDebug::PushGroup("AmbientOccludeScene"); + + FGLPostProcessState savedState; + + float bias = gl_ssao_bias; + float aoRadius = gl_ssao_radius; + const float blurAmount = gl_ssao_blur_amount; + int blurSampleCount = gl_ssao_blur_samples; + + //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); + float tanHalfFovy = 1.0f / 1.33333302f; //gl_RenderState.mProjectionMatrix.get()[5]; + float invFocalLenX = tanHalfFovy * (mBuffers->AmbientWidth / (float)mBuffers->AmbientHeight); + float invFocalLenY = tanHalfFovy; + float nDotVBias = clamp(bias, 0.0f, 1.0f); + float r2 = aoRadius * aoRadius; + + // Calculate linear depth values + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); + mBuffers->BindSceneDepthTexture(0); + mLinearDepthShader->Bind(); + mLinearDepthShader->DepthTexture.Set(0); + mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); + mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); + mLinearDepthShader->InverseDepthRangeA.Set(1.0f); + mLinearDepthShader->InverseDepthRangeB.Set(0.0f); + RenderScreenQuad(); + + // Apply ambient occlusion + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mSSAOShader->Bind(); + mSSAOShader->DepthTexture.Set(0); + mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); + mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); + mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + mSSAOShader->NDotVBias.Set(nDotVBias); + mSSAOShader->NegInvR2.Set(-1.0f / r2); + mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight); + mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias)); + RenderScreenQuad(); + + // Blur SSAO texture + mBlurShader->BlurHorizontal(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture1, mBuffers->AmbientFB0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); + mBlurShader->BlurVertical(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture0, mBuffers->AmbientFB1, mBuffers->AmbientWidth, mBuffers->AmbientHeight); + + // Add SSAO back to scene texture: + mBuffers->BindCurrentFB(); + glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + if (gl_ssao_debug) + glBlendFunc(GL_ONE, GL_ZERO); + else + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + mBloomCombineShader->Bind(); + mBloomCombineShader->BloomTexture.Set(0); + RenderScreenQuad(); + glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + + FGLDebug::PopGroup(); +} + //----------------------------------------------------------------------------- // // Extracts light average from the scene and updates the camera exposure texture @@ -190,7 +295,7 @@ void FGLRenderer::UpdateCameraExposure() void FGLRenderer::BloomScene() { // Only bloom things if enabled and no special fixed light mode is active - if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT) + if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT || gl_ssao_debug) return; FGLDebug::PushGroup("BloomScene"); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index b2471e4b91..54d597c4da 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -40,6 +40,7 @@ #include "w_wad.h" #include "i_system.h" #include "doomerrors.h" +#include CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR(Bool, gl_renderbuffers, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) @@ -75,15 +76,16 @@ FGLRenderBuffers::~FGLRenderBuffers() ClearEyeBuffers(); ClearBloom(); ClearExposureLevels(); + ClearAmbientOcclusion(); } void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); - DeleteRenderBuffer(mSceneMultisample); - DeleteRenderBuffer(mSceneDepthStencil); - DeleteRenderBuffer(mSceneDepth); - DeleteRenderBuffer(mSceneStencil); + DeleteFrameBuffer(mSceneDataFB); + DeleteTexture(mSceneMultisample); + DeleteTexture(mSceneData); + DeleteTexture(mSceneDepthStencil); } void FGLRenderBuffers::ClearPipeline() @@ -132,6 +134,15 @@ void FGLRenderBuffers::ClearEyeBuffers() mEyeFBs.Clear(); } +void FGLRenderBuffers::ClearAmbientOcclusion() +{ + DeleteFrameBuffer(AmbientFB0); + DeleteFrameBuffer(AmbientFB1); + DeleteTexture(AmbientTexture0); + DeleteTexture(AmbientTexture1); + DeleteTexture(AmbientRandomTexture); +} + void FGLRenderBuffers::DeleteTexture(GLuint &handle) { if (handle != 0) @@ -203,6 +214,7 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei { CreateBloom(sceneWidth, sceneHeight); CreateExposureLevels(sceneWidth, sceneHeight); + CreateAmbientOcclusion(sceneWidth, sceneHeight); mSceneWidth = sceneWidth; mSceneHeight = sceneHeight; } @@ -240,10 +252,19 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples) ClearScene(); if (samples > 1) - mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, samples, width, height); + { + mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); + mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); + mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); + } + else + { + mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); + } - mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height); - mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1); + mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], 0, mSceneDepthStencil, samples > 1); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneData, mSceneDepthStencil, samples > 1); } //========================================================================== @@ -296,6 +317,47 @@ void FGLRenderBuffers::CreateBloom(int width, int height) } } +//========================================================================== +// +// Creates ambient occlusion working buffers +// +//========================================================================== + +void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) +{ + ClearAmbientOcclusion(); + + if (width <= 0 || height <= 0) + return; + + AmbientWidth = width / 2; + AmbientHeight = height / 2; + AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG32F, AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG32F, AmbientWidth, AmbientHeight); + AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); + AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); + + int16_t randomValues[16 * 4]; + std::mt19937 generator(1337); + std::uniform_real_distribution distribution(-1.0, 1.0); + for (int i = 0; i < 16; i++) + { + double num_directions = 8.0; // Must be same as the define in ssao.fp + double angle = 2.0 * M_PI * distribution(generator) / num_directions; + double x = cos(angle); + double y = sin(angle); + double z = distribution(generator); + double w = distribution(generator); + + randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0); + } + + AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); +} + //========================================================================== // // Creates camera exposure level buffers @@ -368,12 +430,28 @@ void FGLRenderBuffers::CreateEyeBuffers(int eye) GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data) { - GLuint type = (format == GL_RGBA16F || format == GL_R32F) ? GL_FLOAT : GL_UNSIGNED_BYTE; GLuint handle = 0; glGenTextures(1, &handle); glBindTexture(GL_TEXTURE_2D, handle); FGLDebug::LabelObject(GL_TEXTURE, handle, name); - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format != GL_R32F ? GL_RGBA : GL_RED, type, data); + + GLenum dataformat, datatype; + switch (format) + { + case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break; + case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break; + case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; + case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; + case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break; + case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break; + case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; + default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture"); + } + + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, data); 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); @@ -381,6 +459,17 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int return handle; } +GLuint FGLRenderBuffers::Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations) +{ + GLuint handle = 0; + glGenTextures(1, &handle); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, handle); + FGLDebug::LabelObject(GL_TEXTURE, handle, name); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, format, width, height, fixedSampleLocations); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + return handle; +} + //========================================================================== // // Creates a render buffer @@ -428,34 +517,26 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer) +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) { GLuint handle = 0; glGenFramebuffers(1, &handle); glBindFramebuffer(GL_FRAMEBUFFER, handle); FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); - if (colorIsARenderBuffer) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); + if (multisample) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0, 0); + if (colorbuffer1 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil, 0); + } else - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); - if (CheckFrameBufferCompleteness()) - ClearFrameBuffer(true, true); - return handle; -} - -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer) -{ - GLuint handle = 0; - glGenFramebuffers(1, &handle); - glBindFramebuffer(GL_FRAMEBUFFER, handle); - FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); - if (colorIsARenderBuffer) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); - else - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil); + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0, 0); + if (colorbuffer1 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0); + } if (CheckFrameBufferCompleteness()) ClearFrameBuffer(true, true); return handle; @@ -475,22 +556,23 @@ bool FGLRenderBuffers::CheckFrameBufferCompleteness() FailedCreate = true; -#if 0 - FString error = "glCheckFramebufferStatus failed: "; - switch (result) + if (gl_debug_level > 0) { - default: error.AppendFormat("error code %d", (int)result); break; - case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break; - case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break; - case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break; + FString error = "glCheckFramebufferStatus failed: "; + switch (result) + { + default: error.AppendFormat("error code %d", (int)result); break; + case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break; + case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break; + } + Printf("%s\n", error.GetChars()); } - I_FatalError(error); -#endif return false; } @@ -595,9 +677,54 @@ void FGLRenderBuffers::BindEyeFB(int eye, bool readBuffer) // //========================================================================== -void FGLRenderBuffers::BindSceneFB() +void FGLRenderBuffers::BindSceneFB(bool sceneData) { - glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); + glBindFramebuffer(GL_FRAMEBUFFER, sceneData ? mSceneDataFB : mSceneFB); +} + +//========================================================================== +// +// Binds the scene color texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneColorTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if (mSamples > 1) + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneMultisample); + else + glBindTexture(GL_TEXTURE_2D, mPipelineTexture[0]); +} + +//========================================================================== +// +// Binds the scene data texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneDataTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if (mSamples > 1) + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneData); + else + glBindTexture(GL_TEXTURE_2D, mSceneData); +} + +//========================================================================== +// +// Binds the depth texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneDepthTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if (mSamples > 1) + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneDepthStencil); + else + glBindTexture(GL_TEXTURE_2D, mSceneDepthStencil); } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 4477718f4b..351a0ed0c5 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -31,7 +31,10 @@ public: bool Setup(int width, int height, int sceneWidth, int sceneHeight); - void BindSceneFB(); + void BindSceneFB(bool sceneData); + void BindSceneColorTexture(int index); + void BindSceneDataTexture(int index); + void BindSceneDepthTexture(int index); void BlitSceneToTexture(); void BindCurrentTexture(int index); @@ -53,6 +56,15 @@ public: GLuint ExposureFB = 0; bool FirstExposureFrame = true; + // Ambient occlusion buffers + GLuint AmbientTexture0 = 0; + GLuint AmbientTexture1 = 0; + GLuint AmbientFB0 = 0; + GLuint AmbientFB1 = 0; + int AmbientWidth = 0; + int AmbientHeight = 0; + GLuint AmbientRandomTexture = 0; + static bool IsEnabled(); int GetWidth() const { return mWidth; } @@ -64,17 +76,19 @@ private: void ClearEyeBuffers(); void ClearBloom(); void ClearExposureLevels(); + void ClearAmbientOcclusion(); void CreateScene(int width, int height, int samples); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); void CreateExposureLevels(int width, int height); void CreateEyeBuffers(int eye); + void CreateAmbientOcclusion(int width, int height); GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr); + GLuint Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations); GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height); GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); - GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); - GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); void DeleteTexture(GLuint &handle); @@ -94,9 +108,9 @@ private: // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 0; - GLuint mSceneDepth = 0; - GLuint mSceneStencil = 0; + GLuint mSceneData = 0; GLuint mSceneFB = 0; + GLuint mSceneDataFB = 0; // Effect/HUD buffers GLuint mPipelineTexture[NumPipelineTextures]; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 42b4a8e1b8..829b2500bd 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -51,6 +51,7 @@ #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_drawinfo.h" #include "gl/shaders/gl_shader.h" +#include "gl/shaders/gl_ambientshader.h" #include "gl/shaders/gl_bloomshader.h" #include "gl/shaders/gl_blurshader.h" #include "gl/shaders/gl_tonemapshader.h" @@ -121,6 +122,8 @@ void gl_FlushModels(); void FGLRenderer::Initialize(int width, int height) { mBuffers = new FGLRenderBuffers(); + mLinearDepthShader = new FLinearDepthShader(); + mSSAOShader = new FSSAOShader(); mBloomExtractShader = new FBloomExtractShader(); mBloomCombineShader = new FBloomCombineShader(); mExposureExtractShader = new FExposureExtractShader(); @@ -184,6 +187,8 @@ FGLRenderer::~FGLRenderer() } if (mBuffers) delete mBuffers; if (mPresentShader) delete mPresentShader; + if (mLinearDepthShader) delete mLinearDepthShader; + if (mSSAOShader) delete mSSAOShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; if (mExposureExtractShader) delete mExposureExtractShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 71c52474a1..2ec35b4a82 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -19,6 +19,8 @@ class FLightBuffer; class FSamplerManager; class DPSprite; class FGLRenderBuffers; +class FLinearDepthShader; +class FSSAOShader; class FBloomExtractShader; class FBloomCombineShader; class FExposureExtractShader; @@ -93,6 +95,8 @@ public: int mOldFBID; FGLRenderBuffers *mBuffers; + FLinearDepthShader *mLinearDepthShader; + FSSAOShader *mSSAOShader; FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; FExposureExtractShader *mExposureExtractShader; @@ -172,6 +176,8 @@ public: void WriteSavePic (player_t *player, FileWriter *file, int width, int height); void EndDrawScene(sector_t * viewsector); void UpdateCameraExposure(); + void PostProcessScene(); + void AmbientOccludeScene(); void BloomScene(); void TonemapScene(); void ColormapScene(); @@ -198,6 +204,9 @@ public: DAngle rotation, FDynamicColormap *colormap, int lightlevel); int PTM_BestColor (const uint32 *pal_in, int r, int g, int b, int first, int num); + + static float GetZNear() { return 5.f; } + static float GetZFar() { return 65536.f; } }; // Global functions. Make them members of GLRenderer later? diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 0c76b4bb1b..27772a0ca2 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -209,7 +209,7 @@ void FGLRenderer::SetProjection(float fov, float ratio, float fovratio) { float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovratio)); - gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, 5.f, 65536.f); + gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, GetZNear(), GetZFar()); } // raw matrix input from stereo 3d modes @@ -826,12 +826,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo if (mainview && toscreen) EndDrawScene(lviewsector); // do not call this for camera textures. if (mainview && FGLRenderBuffers::IsEnabled()) { - mBuffers->BlitSceneToTexture(); - UpdateCameraExposure(); - BloomScene(); - TonemapScene(); - ColormapScene(); - LensDistortScene(); + PostProcessScene(); // This should be done after postprocessing, not before. mBuffers->BindCurrentFB(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp new file mode 100644 index 0000000000..d9d4a34257 --- /dev/null +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -0,0 +1,89 @@ +/* +** gl_bloomshader.cpp +** Shaders used for screen space ambient occlusion +** +**--------------------------------------------------------------------------- +** 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_ambientshader.h" + +void FLinearDepthShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/lineardepth"); + mShader.SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(mShader, "DepthTexture"); + LinearizeDepthA.Init(mShader, "LinearizeDepthA"); + LinearizeDepthB.Init(mShader, "LinearizeDepthB"); + InverseDepthRangeA.Init(mShader, "InverseDepthRangeA"); + InverseDepthRangeB.Init(mShader, "InverseDepthRangeB"); + } + mShader.Bind(); +} + +void FSSAOShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/ssao"); + mShader.SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(mShader, "DepthTexture"); + UVToViewA.Init(mShader, "UVToViewA"); + UVToViewB.Init(mShader, "UVToViewB"); + InvFullResolution.Init(mShader, "InvFullResolution"); + NDotVBias.Init(mShader, "NDotVBias"); + NegInvR2.Init(mShader, "NegInvR2"); + RadiusToScreen.Init(mShader, "RadiusToScreen"); + AOMultiplier.Init(mShader, "AOMultiplier"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h new file mode 100644 index 0000000000..44f9165964 --- /dev/null +++ b/src/gl/shaders/gl_ambientshader.h @@ -0,0 +1,39 @@ +#ifndef __GL_AMBIENTSHADER_H +#define __GL_AMBIENTSHADER_H + +#include "gl_shaderprogram.h" + +class FLinearDepthShader +{ +public: + void Bind(); + + FBufferedUniformSampler DepthTexture; + FBufferedUniform1f LinearizeDepthA; + FBufferedUniform1f LinearizeDepthB; + FBufferedUniform1f InverseDepthRangeA; + FBufferedUniform1f InverseDepthRangeB; + +private: + FShaderProgram mShader; +}; + +class FSSAOShader +{ +public: + void Bind(); + + FBufferedUniformSampler DepthTexture; + FBufferedUniform2f UVToViewA; + FBufferedUniform2f UVToViewB; + FBufferedUniform2f InvFullResolution; + FBufferedUniform1f NDotVBias; + FBufferedUniform1f NegInvR2; + FBufferedUniform1f RadiusToScreen; + FBufferedUniform1f AOMultiplier; + +private: + FShaderProgram mShader; +}; + +#endif \ No newline at end of file diff --git a/src/gl/stereo3d/gl_stereo3d.cpp b/src/gl/stereo3d/gl_stereo3d.cpp index 9403d47512..6b1623ba69 100644 --- a/src/gl/stereo3d/gl_stereo3d.cpp +++ b/src/gl/stereo3d/gl_stereo3d.cpp @@ -41,7 +41,7 @@ VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) co // Lifted from gl_scene.cpp FGLRenderer::SetProjection() float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); - result.perspective(fovy, aspectRatio, 5.f, 65536.f); + result.perspective(fovy, aspectRatio, FGLRenderer::GetZNear(), FGLRenderer::GetZFar()); return result; } diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 50526a75b5..197e262f55 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2633,6 +2633,7 @@ GLPREFMNU_MULTISAMPLE = "Multisample"; GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_LENS = "Lens distortion effect"; +GLPREFMNU_SSAO = "Ambient occlusion"; // Option Values OPTVAL_SMART = "Smart"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 1ab4f1a6d5..68523ea83f 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -226,4 +226,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_LENS", gl_lens, "OnOff" + Option "$GLPREFMNU_SSAO", gl_ssao, "OnOff" } diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp new file mode 100644 index 0000000000..f61bb39955 --- /dev/null +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -0,0 +1,16 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D DepthTexture; +uniform float LinearizeDepthA; +uniform float LinearizeDepthB; +uniform float InverseDepthRangeA; +uniform float InverseDepthRangeB; + +void main() +{ + float depth = texture(DepthTexture, TexCoord).x; + float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); + FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0); +} diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp new file mode 100644 index 0000000000..c9f8534d9f --- /dev/null +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -0,0 +1,117 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform vec2 UVToViewA; +uniform vec2 UVToViewB; +uniform vec2 InvFullResolution; + +uniform float NDotVBias; +uniform float NegInvR2; +uniform float RadiusToScreen; +uniform float AOMultiplier; + +uniform sampler2D DepthTexture; + +#if USE_RANDOM_TEXTURE +uniform sampler2D RandomTexture; +#endif + +#define NUM_DIRECTIONS 8.0 +#define NUM_STEPS 4.0 + +#define PI 3.14159265358979323846 + +// Calculate eye space position for the specified texture coordinate +vec3 FetchViewPos(vec2 uv) +{ + float z = texture(DepthTexture, uv).x; + return vec3((UVToViewA * uv + UVToViewB) * z, z); +} + +vec3 MinDiff(vec3 p, vec3 pr, vec3 pl) +{ + vec3 v1 = pr - p; + vec3 v2 = p - pl; + return (dot(v1, v1) < dot(v2, v2)) ? v1 : v2; +} + +// Reconstruct eye space normal from nearest neighbors +vec3 ReconstructNormal(vec3 p) +{ + vec3 pr = FetchViewPos(TexCoord + vec2(InvFullResolution.x, 0)); + vec3 pl = FetchViewPos(TexCoord + vec2(-InvFullResolution.x, 0)); + vec3 pt = FetchViewPos(TexCoord + vec2(0, InvFullResolution.y)); + vec3 pb = FetchViewPos(TexCoord + vec2(0, -InvFullResolution.y)); + return normalize(cross(MinDiff(p, pr, pl), MinDiff(p, pt, pb))); +} + +// Compute normalized 2D direction +vec2 RotateDirection(vec2 dir, vec2 cossin) +{ + return vec2(dir.x * cossin.x - dir.y * cossin.y, dir.x * cossin.y + dir.y * cossin.x); +} + +vec4 GetJitter() +{ +#if !USE_RANDOM_TEXTURE + return vec4(1,0,1,1); + //vec3 rand = noise3(TexCoord.x + TexCoord.y); + //float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS; + //return vec4(cos(angle), sin(angle), rand.y, rand.z); +#else + #define RANDOM_TEXTURE_WIDTH 4.0 + return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH); +#endif +} + +// Calculates the ambient occlusion of a sample +float ComputeSampleAO(vec3 kernelPos, vec3 normal, vec3 samplePos) +{ + vec3 v = samplePos - kernelPos; + float distanceSquare = dot(v, v); + float nDotV = dot(normal, v) * inversesqrt(distanceSquare); + return clamp(nDotV - NDotVBias, 0.0, 1.0) * clamp(distanceSquare * NegInvR2 + 1.0, 0.0, 1.0); +} + +// Calculates the total ambient occlusion for the entire fragment +float ComputeAO(vec3 viewPosition, vec3 viewNormal) +{ + vec4 rand = GetJitter(); + + float radiusPixels = RadiusToScreen / viewPosition.z; + float stepSizePixels = radiusPixels / (NUM_STEPS + 1.0); + + const float directionAngleStep = 2.0 * PI / NUM_DIRECTIONS; + float ao = 0.0; + + for (float directionIndex = 0.0; directionIndex < NUM_DIRECTIONS; ++directionIndex) + { + float angle = directionAngleStep * directionIndex; + + vec2 direction = RotateDirection(vec2(cos(angle), sin(angle)), rand.xy); + float rayPixels = (rand.z * stepSizePixels + 1.0); + + for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) + { + vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; + vec3 samplePos = FetchViewPos(sampleUV); + ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); + rayPixels += stepSizePixels; + } + } + + ao *= AOMultiplier / (NUM_DIRECTIONS * NUM_STEPS); + return clamp(1.0 - ao * 2.0, 0.0, 1.0); +} + +void main() +{ + vec3 viewPosition = FetchViewPos(TexCoord); + vec3 viewNormal = ReconstructNormal(viewPosition); + float occlusion = ComputeAO(viewPosition, viewNormal); + //FragColor = vec4(viewPosition.x * 0.001 + 0.5, viewPosition.y * 0.001 + 0.5, viewPosition.z * 0.001, 1.0); + //FragColor = vec4(viewNormal.x * 0.5 + 0.5, viewNormal.y * 0.5 + 0.5, viewNormal.z * 0.5 + 0.5, 1.0); + //FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); + FragColor = vec4(occlusion, occlusion, occlusion, 1.0); +} From 723eb746f660d8ee63b63fff7a515ad27fb4264f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 30 Aug 2016 01:09:21 +0200 Subject: [PATCH 02/29] Add ssao random texture --- src/gl/renderer/gl_postprocess.cpp | 10 ++++++++++ src/gl/shaders/gl_ambientshader.cpp | 11 ++++++++++- src/gl/shaders/gl_ambientshader.h | 2 ++ wadsrc/static/shaders/glsl/ssao.fp | 16 +++++++++------- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 9df28ce5bd..4fb83c642e 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -100,6 +100,7 @@ CVAR(Float, gl_lens_kcube, 0.1f, 0) CVAR(Float, gl_lens_chromatic, 1.12f, 0) CVAR(Bool, gl_ssao, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_ssao_debug, false, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) @@ -148,11 +149,13 @@ void FGLRenderer::AmbientOccludeScene() FGLDebug::PushGroup("AmbientOccludeScene"); FGLPostProcessState savedState; + savedState.SaveTextureBinding1(); float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; const float blurAmount = gl_ssao_blur_amount; int blurSampleCount = gl_ssao_blur_samples; + float aoStrength = gl_ssao_strength; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); float tanHalfFovy = 1.0f / 1.33333302f; //gl_RenderState.mProjectionMatrix.get()[5]; @@ -178,8 +181,14 @@ void FGLRenderer::AmbientOccludeScene() glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glActiveTexture(GL_TEXTURE0); mSSAOShader->Bind(); mSSAOShader->DepthTexture.Set(0); + mSSAOShader->RandomTexture.Set(1); mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); @@ -187,6 +196,7 @@ void FGLRenderer::AmbientOccludeScene() mSSAOShader->NegInvR2.Set(-1.0f / r2); mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight); mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias)); + mSSAOShader->AOStrength.Set(aoStrength); RenderScreenQuad(); // Blur SSAO texture diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index d9d4a34257..55682a91e0 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -71,12 +71,20 @@ void FSSAOShader::Bind() { if (!mShader) { + const char *defines = R"( + #define USE_RANDOM_TEXTURE + #define RANDOM_TEXTURE_WIDTH 4.0 + #define NUM_DIRECTIONS 8.0 + #define NUM_STEPS 4.0 + )"; + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", defines, 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/ssao"); mShader.SetAttribLocation(0, "PositionInProjection"); DepthTexture.Init(mShader, "DepthTexture"); + RandomTexture.Init(mShader, "RandomTexture"); UVToViewA.Init(mShader, "UVToViewA"); UVToViewB.Init(mShader, "UVToViewB"); InvFullResolution.Init(mShader, "InvFullResolution"); @@ -84,6 +92,7 @@ void FSSAOShader::Bind() NegInvR2.Init(mShader, "NegInvR2"); RadiusToScreen.Init(mShader, "RadiusToScreen"); AOMultiplier.Init(mShader, "AOMultiplier"); + AOStrength.Init(mShader, "AOStrength"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 44f9165964..fdff178ec2 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -24,6 +24,7 @@ public: void Bind(); FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler RandomTexture; FBufferedUniform2f UVToViewA; FBufferedUniform2f UVToViewB; FBufferedUniform2f InvFullResolution; @@ -31,6 +32,7 @@ public: FBufferedUniform1f NegInvR2; FBufferedUniform1f RadiusToScreen; FBufferedUniform1f AOMultiplier; + FBufferedUniform1f AOStrength; private: FShaderProgram mShader; diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index c9f8534d9f..f143e913f7 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -11,15 +11,14 @@ uniform float NegInvR2; uniform float RadiusToScreen; uniform float AOMultiplier; +uniform float AOStrength; + uniform sampler2D DepthTexture; -#if USE_RANDOM_TEXTURE +#if defined(USE_RANDOM_TEXTURE) uniform sampler2D RandomTexture; #endif -#define NUM_DIRECTIONS 8.0 -#define NUM_STEPS 4.0 - #define PI 3.14159265358979323846 // Calculate eye space position for the specified texture coordinate @@ -54,13 +53,12 @@ vec2 RotateDirection(vec2 dir, vec2 cossin) vec4 GetJitter() { -#if !USE_RANDOM_TEXTURE +#if !defined(USE_RANDOM_TEXTURE) return vec4(1,0,1,1); //vec3 rand = noise3(TexCoord.x + TexCoord.y); //float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS; //return vec4(cos(angle), sin(angle), rand.y, rand.z); #else - #define RANDOM_TEXTURE_WIDTH 4.0 return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH); #endif } @@ -109,7 +107,11 @@ void main() { vec3 viewPosition = FetchViewPos(TexCoord); vec3 viewNormal = ReconstructNormal(viewPosition); - float occlusion = ComputeAO(viewPosition, viewNormal); + float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); + + // GZDoom does not use linear buffers at the moment, apply some gamma to get it closer to correct + occlusion = occlusion * occlusion; + //FragColor = vec4(viewPosition.x * 0.001 + 0.5, viewPosition.y * 0.001 + 0.5, viewPosition.z * 0.001, 1.0); //FragColor = vec4(viewNormal.x * 0.5 + 0.5, viewNormal.y * 0.5 + 0.5, viewNormal.z * 0.5 + 0.5, 1.0); //FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); From a6fdaca6337cc2226dafb3a26e38273a2bb0e909 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 1 Sep 2016 07:15:40 +0200 Subject: [PATCH 03/29] Fix precision issue in SSAO shader --- src/gl/renderer/gl_postprocess.cpp | 8 ++++---- src/gl/renderer/gl_renderbuffers.h | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 4fb83c642e..2356eaee7d 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -104,11 +104,11 @@ CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_ssao_debug, false, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) -CUSTOM_CVAR(Float, gl_ssao_blur_amount, 6.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) { if (self < 0.1f) self = 0.1f; } -CUSTOM_CVAR(Int, gl_ssao_blur_samples, 9, 0) +CUSTOM_CVAR(Int, gl_ssao_blur_samples, 5, 0) { if (self < 3 || self > 15 || self % 2 == 0) self = 9; @@ -158,8 +158,8 @@ void FGLRenderer::AmbientOccludeScene() float aoStrength = gl_ssao_strength; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); - float tanHalfFovy = 1.0f / 1.33333302f; //gl_RenderState.mProjectionMatrix.get()[5]; - float invFocalLenX = tanHalfFovy * (mBuffers->AmbientWidth / (float)mBuffers->AmbientHeight); + float tanHalfFovy = 1.0f / 1.33333302f; // 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; + float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight()); float invFocalLenY = tanHalfFovy; float nDotVBias = clamp(bias, 0.0f, 1.0f); float r2 = aoRadius * aoRadius; diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 351a0ed0c5..080593881b 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -70,6 +70,9 @@ public: int GetWidth() const { return mWidth; } int GetHeight() const { return mHeight; } + int GetSceneWidth() const { return mSceneWidth; } + int GetSceneHeight() const { return mSceneHeight; } + private: void ClearScene(); void ClearPipeline(); From a246b586733613f318897d64a0f65df092c058c6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 2 Sep 2016 05:45:00 +0200 Subject: [PATCH 04/29] Change SSAO blur to be depth aware --- src/gl/renderer/gl_postprocess.cpp | 22 ++++-- src/gl/renderer/gl_renderer.cpp | 8 +++ src/gl/renderer/gl_renderer.h | 4 ++ src/gl/shaders/gl_ambientshader.cpp | 32 +++++++++ src/gl/shaders/gl_ambientshader.h | 25 +++++++ wadsrc/static/shaders/glsl/depthblur.fp | 81 +++++++++++++++++++++++ wadsrc/static/shaders/glsl/ssao.fp | 9 +-- wadsrc/static/shaders/glsl/ssaocombine.fp | 11 +++ 8 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 wadsrc/static/shaders/glsl/depthblur.fp create mode 100644 wadsrc/static/shaders/glsl/ssaocombine.fp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 2356eaee7d..97491cb580 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -200,8 +200,22 @@ void FGLRenderer::AmbientOccludeScene() RenderScreenQuad(); // Blur SSAO texture - mBlurShader->BlurHorizontal(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture1, mBuffers->AmbientFB0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); - mBlurShader->BlurVertical(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture0, mBuffers->AmbientFB1, mBuffers->AmbientWidth, mBuffers->AmbientHeight); + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mDepthBlurShader->Bind(false); + mDepthBlurShader->BlurSharpness[false].Set(blurAmount); + mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + RenderScreenQuad(); + + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + mDepthBlurShader->Bind(true); + mDepthBlurShader->BlurSharpness[true].Set(blurAmount); + mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + mDepthBlurShader->PowExponent[true].Set(1.8f); + RenderScreenQuad(); // Add SSAO back to scene texture: mBuffers->BindCurrentFB(); @@ -216,8 +230,8 @@ void FGLRenderer::AmbientOccludeScene() glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - mBloomCombineShader->Bind(); - mBloomCombineShader->BloomTexture.Set(0); + mSSAOCombineShader->Bind(); + mSSAOCombineShader->AODepthTexture.Set(0); RenderScreenQuad(); glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 829b2500bd..befa330e96 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -114,6 +114,10 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mColormapShader = nullptr; mLensShader = nullptr; + mLinearDepthShader = nullptr; + mDepthBlurShader = nullptr; + mSSAOShader = nullptr; + mSSAOCombineShader = nullptr; } void gl_LoadModels(); @@ -123,7 +127,9 @@ void FGLRenderer::Initialize(int width, int height) { mBuffers = new FGLRenderBuffers(); mLinearDepthShader = new FLinearDepthShader(); + mDepthBlurShader = new FDepthBlurShader(); mSSAOShader = new FSSAOShader(); + mSSAOCombineShader = new FSSAOCombineShader(); mBloomExtractShader = new FBloomExtractShader(); mBloomCombineShader = new FBloomCombineShader(); mExposureExtractShader = new FExposureExtractShader(); @@ -188,7 +194,9 @@ FGLRenderer::~FGLRenderer() if (mBuffers) delete mBuffers; if (mPresentShader) delete mPresentShader; if (mLinearDepthShader) delete mLinearDepthShader; + if (mDepthBlurShader) delete mDepthBlurShader; if (mSSAOShader) delete mSSAOShader; + if (mSSAOCombineShader) delete mSSAOCombineShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; if (mExposureExtractShader) delete mExposureExtractShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 2ec35b4a82..a285c9ef77 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -20,7 +20,9 @@ class FSamplerManager; class DPSprite; class FGLRenderBuffers; class FLinearDepthShader; +class FDepthBlurShader; class FSSAOShader; +class FSSAOCombineShader; class FBloomExtractShader; class FBloomCombineShader; class FExposureExtractShader; @@ -97,6 +99,8 @@ public: FGLRenderBuffers *mBuffers; FLinearDepthShader *mLinearDepthShader; FSSAOShader *mSSAOShader; + FDepthBlurShader *mDepthBlurShader; + FSSAOCombineShader *mSSAOCombineShader; FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; FExposureExtractShader *mExposureExtractShader; diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 55682a91e0..6b8c9cc485 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -96,3 +96,35 @@ void FSSAOShader::Bind() } mShader.Bind(); } + +void FDepthBlurShader::Bind(bool vertical) +{ + auto &shader = mShader[vertical]; + if (!shader) + { + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/depthblur.fp", vertical ? "#define BLUR_VERTICAL\n" : "#define BLUR_HORIZONTAL\n", 330); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/depthblur"); + shader.SetAttribLocation(0, "PositionInProjection"); + AODepthTexture[vertical].Init(shader, "AODepthTexture"); + BlurSharpness[vertical].Init(shader, "BlurSharpness"); + InvFullResolution[vertical].Init(shader, "InvFullResolution"); + PowExponent[vertical].Init(shader, "PowExponent"); + } + shader.Bind(); +} + +void FSSAOCombineShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/ssaocombine"); + mShader.SetAttribLocation(0, "PositionInProjection"); + AODepthTexture.Init(mShader, "AODepthTexture"); + } + mShader.Bind(); +} diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index fdff178ec2..419ca939e2 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -38,4 +38,29 @@ private: FShaderProgram mShader; }; +class FDepthBlurShader +{ +public: + void Bind(bool vertical); + + FBufferedUniformSampler AODepthTexture[2]; + FBufferedUniform1f BlurSharpness[2]; + FBufferedUniform2f InvFullResolution[2]; + FBufferedUniform1f PowExponent[2]; + +private: + FShaderProgram mShader[2]; +}; + +class FSSAOCombineShader +{ +public: + void Bind(); + + FBufferedUniformSampler AODepthTexture; + +private: + FShaderProgram mShader; +}; + #endif \ No newline at end of file diff --git a/wadsrc/static/shaders/glsl/depthblur.fp b/wadsrc/static/shaders/glsl/depthblur.fp new file mode 100644 index 0000000000..bd464d03da --- /dev/null +++ b/wadsrc/static/shaders/glsl/depthblur.fp @@ -0,0 +1,81 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D AODepthTexture; +uniform float BlurSharpness; +uniform vec2 InvFullResolution; +uniform float PowExponent; + +#define KERNEL_RADIUS 3.0 + +struct CenterPixelData +{ + vec2 UV; + float Depth; + float Sharpness; +}; + +float CrossBilateralWeight(float r, float sampleDepth, CenterPixelData center) +{ + const float blurSigma = KERNEL_RADIUS * 0.5; + const float blurFalloff = 1.0 / (2.0 * blurSigma * blurSigma); + + float deltaZ = (sampleDepth - center.Depth) * center.Sharpness; + + return exp2(-r * r * blurFalloff - deltaZ * deltaZ); +} + +void ProcessSample(float ao, float z, float r, CenterPixelData center, inout float totalAO, inout float totalW) +{ + float w = CrossBilateralWeight(r, z, center); + totalAO += w * ao; + totalW += w; +} + +void ProcessRadius(vec2 deltaUV, CenterPixelData center, inout float totalAO, inout float totalW) +{ + for (float r = 1; r <= KERNEL_RADIUS; r += 1.0) + { + vec2 uv = r * deltaUV + center.UV; + vec2 aoZ = texture(AODepthTexture, uv).xy; + ProcessSample(aoZ.x, aoZ.y, r, center, totalAO, totalW); + } +} + +vec2 ComputeBlur(vec2 deltaUV) +{ + vec2 aoZ = texture(AODepthTexture, TexCoord).xy; + + CenterPixelData center; + center.UV = TexCoord; + center.Depth = aoZ.y; + center.Sharpness = BlurSharpness; + + float totalAO = aoZ.x; + float totalW = 1.0; + + ProcessRadius(deltaUV, center, totalAO, totalW); + ProcessRadius(-deltaUV, center, totalAO, totalW); + + return vec2(totalAO / totalW, aoZ.y); +} + +vec2 BlurX() +{ + return ComputeBlur(vec2(InvFullResolution.x, 0.0)); +} + +float BlurY() +{ + return pow(clamp(ComputeBlur(vec2(0.0, InvFullResolution.y)).x, 0.0, 1.0), PowExponent); +} + +void main() +{ +#if defined(BLUR_HORIZONTAL) + FragColor = vec4(BlurX(), 0.0, 1.0); +#else + FragColor = vec4(BlurY(), 0.0, 0.0, 1.0); +#endif +} diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index f143e913f7..e0d972c579 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -108,12 +108,5 @@ void main() vec3 viewPosition = FetchViewPos(TexCoord); vec3 viewNormal = ReconstructNormal(viewPosition); float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); - - // GZDoom does not use linear buffers at the moment, apply some gamma to get it closer to correct - occlusion = occlusion * occlusion; - - //FragColor = vec4(viewPosition.x * 0.001 + 0.5, viewPosition.y * 0.001 + 0.5, viewPosition.z * 0.001, 1.0); - //FragColor = vec4(viewNormal.x * 0.5 + 0.5, viewNormal.y * 0.5 + 0.5, viewNormal.z * 0.5 + 0.5, 1.0); - //FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); - FragColor = vec4(occlusion, occlusion, occlusion, 1.0); + FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp new file mode 100644 index 0000000000..21fdff1024 --- /dev/null +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -0,0 +1,11 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D AODepthTexture; + +void main() +{ + float attenutation = texture(AODepthTexture, TexCoord).x; + FragColor = vec4(attenutation, attenutation, attenutation, 0.0); +} From 09bec67821f6ac1a78aab3bfbd037b1397721b2a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Sep 2016 04:12:00 +0200 Subject: [PATCH 05/29] Resolve multisampling depth in shader --- src/gl/renderer/gl_postprocess.cpp | 21 +++++++++-------- src/gl/shaders/gl_ambientshader.cpp | 28 ++++++++++++----------- src/gl/shaders/gl_ambientshader.h | 15 ++++++------ wadsrc/static/shaders/glsl/lineardepth.fp | 19 +++++++++++++++ 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 97491cb580..8282bc3871 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -127,8 +127,7 @@ void FGLRenderer::RenderScreenQuad() void FGLRenderer::PostProcessScene() { - if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture(); - AmbientOccludeScene(); + mBuffers->BlitSceneToTexture(); UpdateCameraExposure(); BloomScene(); TonemapScene(); @@ -156,6 +155,7 @@ void FGLRenderer::AmbientOccludeScene() const float blurAmount = gl_ssao_blur_amount; int blurSampleCount = gl_ssao_blur_samples; float aoStrength = gl_ssao_strength; + bool multisample = gl_multisample > 1; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); float tanHalfFovy = 1.0f / 1.33333302f; // 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; @@ -168,12 +168,15 @@ void FGLRenderer::AmbientOccludeScene() glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); mBuffers->BindSceneDepthTexture(0); - mLinearDepthShader->Bind(); - mLinearDepthShader->DepthTexture.Set(0); - mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); - mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); - mLinearDepthShader->InverseDepthRangeA.Set(1.0f); - mLinearDepthShader->InverseDepthRangeB.Set(0.0f); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mLinearDepthShader->Bind(multisample); + mLinearDepthShader->DepthTexture[multisample].Set(0); + if (multisample) mLinearDepthShader->SampleCount[multisample].Set(gl_multisample); + mLinearDepthShader->LinearizeDepthA[multisample].Set(1.0f / GetZFar() - 1.0f / GetZNear()); + mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); + mLinearDepthShader->InverseDepthRangeA[multisample].Set(1.0f); + mLinearDepthShader->InverseDepthRangeB[multisample].Set(0.0f); RenderScreenQuad(); // Apply ambient occlusion @@ -218,7 +221,7 @@ void FGLRenderer::AmbientOccludeScene() RenderScreenQuad(); // Add SSAO back to scene texture: - mBuffers->BindCurrentFB(); + mBuffers->BindSceneFB(); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 6b8c9cc485..f3b6eced67 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -49,22 +49,24 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_ambientshader.h" -void FLinearDepthShader::Bind() +void FLinearDepthShader::Bind(bool multisample) { - if (!mShader) + auto &shader = mShader[multisample]; + if (!shader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", "", 330); - mShader.SetFragDataLocation(0, "FragColor"); - mShader.Link("shaders/glsl/lineardepth"); - mShader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture.Init(mShader, "DepthTexture"); - LinearizeDepthA.Init(mShader, "LinearizeDepthA"); - LinearizeDepthB.Init(mShader, "LinearizeDepthB"); - InverseDepthRangeA.Init(mShader, "InverseDepthRangeA"); - InverseDepthRangeB.Init(mShader, "InverseDepthRangeB"); + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/lineardepth"); + shader.SetAttribLocation(0, "PositionInProjection"); + DepthTexture[multisample].Init(shader, "DepthTexture"); + SampleCount[multisample].Init(shader, "SampleCount"); + LinearizeDepthA[multisample].Init(shader, "LinearizeDepthA"); + LinearizeDepthB[multisample].Init(shader, "LinearizeDepthB"); + InverseDepthRangeA[multisample].Init(shader, "InverseDepthRangeA"); + InverseDepthRangeB[multisample].Init(shader, "InverseDepthRangeB"); } - mShader.Bind(); + shader.Bind(); } void FSSAOShader::Bind() diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 419ca939e2..5f9ef630b5 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -6,16 +6,17 @@ class FLinearDepthShader { public: - void Bind(); + void Bind(bool multisample); - FBufferedUniformSampler DepthTexture; - FBufferedUniform1f LinearizeDepthA; - FBufferedUniform1f LinearizeDepthB; - FBufferedUniform1f InverseDepthRangeA; - FBufferedUniform1f InverseDepthRangeB; + FBufferedUniformSampler DepthTexture[2]; + FBufferedUniform1i SampleCount[2]; + FBufferedUniform1f LinearizeDepthA[2]; + FBufferedUniform1f LinearizeDepthB[2]; + FBufferedUniform1f InverseDepthRangeA[2]; + FBufferedUniform1f InverseDepthRangeB[2]; private: - FShaderProgram mShader; + FShaderProgram mShader[2]; }; class FSSAOShader diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index f61bb39955..31df9dc321 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -2,7 +2,12 @@ in vec2 TexCoord; out vec4 FragColor; +#if defined(MULTISAMPLE) +uniform sampler2DMS DepthTexture; +uniform int SampleCount; +#else uniform sampler2D DepthTexture; +#endif uniform float LinearizeDepthA; uniform float LinearizeDepthB; uniform float InverseDepthRangeA; @@ -10,7 +15,21 @@ uniform float InverseDepthRangeB; void main() { +#if defined(MULTISAMPLE) + ivec2 texSize = textureSize(DepthTexture); + ivec2 ipos = ivec2(TexCoord * vec2(texSize)); + float depth = 0.0; + for (int i = 0; i < SampleCount; i++) + depth += texelFetch(DepthTexture, ipos, i).x; + depth /= float(SampleCount); +#else + /*ivec2 texSize = textureSize(DepthTexture, 0); + ivec2 ipos = ivec2(TexCoord * vec2(texSize)); + if (ipos.x < 0) ipos.x += texSize.x; + if (ipos.y < 0) ipos.y += texSize.y; + float depth = texelFetch(DepthTexture, ipos, 0).x;*/ float depth = texture(DepthTexture, TexCoord).x; +#endif float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0); } From c7c0ffadb55421a1d7723db9bb1dac46ebd1d005 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Sep 2016 04:29:50 +0200 Subject: [PATCH 06/29] Move SSAO pass to be before translucent rendering Fix depth sampling location when not using fullscreen scene --- src/gl/renderer/gl_postprocess.cpp | 3 ++- src/gl/scene/gl_scene.cpp | 2 ++ src/gl/shaders/gl_ambientshader.cpp | 2 ++ src/gl/shaders/gl_ambientshader.h | 2 ++ wadsrc/static/shaders/glsl/lineardepth.fp | 12 +++++++++--- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 8282bc3871..3031d80baf 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -177,6 +177,8 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA[multisample].Set(1.0f); mLinearDepthShader->InverseDepthRangeB[multisample].Set(0.0f); + mLinearDepthShader->Scale[multisample].Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height); + mLinearDepthShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); // Apply ambient occlusion @@ -236,7 +238,6 @@ void FGLRenderer::AmbientOccludeScene() mSSAOCombineShader->Bind(); mSSAOCombineShader->AODepthTexture.Set(0); RenderScreenQuad(); - glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); FGLDebug::PopGroup(); } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 27772a0ca2..a50fe87f8b 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -491,6 +491,8 @@ void FGLRenderer::DrawScene(int drawmode) RenderScene(recursion); + AmbientOccludeScene(); + // Handle all portals after rendering the opaque objects but before // doing all translucent stuff recursion++; diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index f3b6eced67..54a651281c 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -65,6 +65,8 @@ void FLinearDepthShader::Bind(bool multisample) LinearizeDepthB[multisample].Init(shader, "LinearizeDepthB"); InverseDepthRangeA[multisample].Init(shader, "InverseDepthRangeA"); InverseDepthRangeB[multisample].Init(shader, "InverseDepthRangeB"); + Scale[multisample].Init(shader, "Scale"); + Offset[multisample].Init(shader, "Offset"); } shader.Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 5f9ef630b5..5b18ea85fd 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -14,6 +14,8 @@ public: FBufferedUniform1f LinearizeDepthB[2]; FBufferedUniform1f InverseDepthRangeA[2]; FBufferedUniform1f InverseDepthRangeB[2]; + FBufferedUniform2f Scale[2]; + FBufferedUniform2f Offset[2]; private: FShaderProgram mShader[2]; diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index 31df9dc321..7e4eee745b 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -8,28 +8,34 @@ uniform int SampleCount; #else uniform sampler2D DepthTexture; #endif + uniform float LinearizeDepthA; uniform float LinearizeDepthB; uniform float InverseDepthRangeA; uniform float InverseDepthRangeB; +uniform vec2 Scale; +uniform vec2 Offset; void main() { + vec2 uv = Offset + TexCoord * Scale; + #if defined(MULTISAMPLE) ivec2 texSize = textureSize(DepthTexture); - ivec2 ipos = ivec2(TexCoord * vec2(texSize)); + ivec2 ipos = ivec2(uv * vec2(texSize)); float depth = 0.0; for (int i = 0; i < SampleCount; i++) depth += texelFetch(DepthTexture, ipos, i).x; depth /= float(SampleCount); #else /*ivec2 texSize = textureSize(DepthTexture, 0); - ivec2 ipos = ivec2(TexCoord * vec2(texSize)); + ivec2 ipos = ivec2(uv * vec2(texSize)); if (ipos.x < 0) ipos.x += texSize.x; if (ipos.y < 0) ipos.y += texSize.y; float depth = texelFetch(DepthTexture, ipos, 0).x;*/ - float depth = texture(DepthTexture, TexCoord).x; + float depth = texture(DepthTexture, uv).x; #endif + float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0); } From e025f6e54bbf140c584030928706e95dee2bb8a5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 4 Sep 2016 08:15:29 +0200 Subject: [PATCH 07/29] Mark portals in scene alpha channel for the SSAO pass --- src/gl/renderer/gl_postprocess.cpp | 5 +++++ src/gl/scene/gl_portal.cpp | 8 +++++--- src/gl/shaders/gl_ambientshader.cpp | 1 + src/gl/shaders/gl_ambientshader.h | 1 + wadsrc/static/shaders/glsl/lineardepth.fp | 8 +++++--- wadsrc/static/shaders/glsl/stencil.fp | 2 +- 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 3031d80baf..d2b1b14c19 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -170,8 +170,13 @@ void FGLRenderer::AmbientOccludeScene() mBuffers->BindSceneDepthTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mBuffers->BindSceneColorTexture(1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glActiveTexture(GL_TEXTURE0); mLinearDepthShader->Bind(multisample); mLinearDepthShader->DepthTexture[multisample].Set(0); + mLinearDepthShader->ColorTexture[multisample].Set(1); if (multisample) mLinearDepthShader->SampleCount[multisample].Set(gl_multisample); mLinearDepthShader->LinearizeDepthA[multisample].Set(1.0f / GetZFar() - 1.0f / GetZNear()); mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index f34b5e23f5..575ef968d5 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -423,14 +423,16 @@ void GLPortal::End(bool usestencil) glDepthFunc(GL_LEQUAL); glDepthRange(0, 1); { - ScopedColorMask colorMask(0, 0, 0, 0); - // glColorMask(0,0,0,0); // no graphics + ScopedColorMask colorMask(0, 0, 0, 1); // mark portal in alpha channel but don't touch color gl_RenderState.SetEffect(EFF_STENCIL); gl_RenderState.EnableTexture(false); + gl_RenderState.BlendFunc(GL_ONE, GL_ZERO); + gl_RenderState.BlendEquation(GL_FUNC_ADD); + gl_RenderState.Apply(); DrawPortalStencil(); gl_RenderState.SetEffect(EFF_NONE); gl_RenderState.EnableTexture(true); - } // glColorMask(1, 1, 1, 1); + } glDepthFunc(GL_LESS); } PortalAll.Unclock(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 54a651281c..3fbd034348 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -60,6 +60,7 @@ void FLinearDepthShader::Bind(bool multisample) shader.Link("shaders/glsl/lineardepth"); shader.SetAttribLocation(0, "PositionInProjection"); DepthTexture[multisample].Init(shader, "DepthTexture"); + ColorTexture[multisample].Init(shader, "ColorTexture"); SampleCount[multisample].Init(shader, "SampleCount"); LinearizeDepthA[multisample].Init(shader, "LinearizeDepthA"); LinearizeDepthB[multisample].Init(shader, "LinearizeDepthB"); diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 5b18ea85fd..9c97791ba8 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -9,6 +9,7 @@ public: void Bind(bool multisample); FBufferedUniformSampler DepthTexture[2]; + FBufferedUniformSampler ColorTexture[2]; FBufferedUniform1i SampleCount[2]; FBufferedUniform1f LinearizeDepthA[2]; FBufferedUniform1f LinearizeDepthB[2]; diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index 7e4eee745b..61e5e81261 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -4,9 +4,11 @@ out vec4 FragColor; #if defined(MULTISAMPLE) uniform sampler2DMS DepthTexture; +uniform sampler2DMS ColorTexture; uniform int SampleCount; #else uniform sampler2D DepthTexture; +uniform sampler2D ColorTexture; #endif uniform float LinearizeDepthA; @@ -25,15 +27,15 @@ void main() ivec2 ipos = ivec2(uv * vec2(texSize)); float depth = 0.0; for (int i = 0; i < SampleCount; i++) - depth += texelFetch(DepthTexture, ipos, i).x; + depth += texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; depth /= float(SampleCount); #else /*ivec2 texSize = textureSize(DepthTexture, 0); ivec2 ipos = ivec2(uv * vec2(texSize)); if (ipos.x < 0) ipos.x += texSize.x; if (ipos.y < 0) ipos.y += texSize.y; - float depth = texelFetch(DepthTexture, ipos, 0).x;*/ - float depth = texture(DepthTexture, uv).x; + float depth = texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0;*/ + float depth = texture(ColorTexture, uv).a != 0.0 ? texture(DepthTexture, uv).x : 1.0; #endif float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); diff --git a/wadsrc/static/shaders/glsl/stencil.fp b/wadsrc/static/shaders/glsl/stencil.fp index d1b8745f6e..65f12b4055 100644 --- a/wadsrc/static/shaders/glsl/stencil.fp +++ b/wadsrc/static/shaders/glsl/stencil.fp @@ -3,6 +3,6 @@ out vec4 FragColor; void main() { - FragColor = vec4(1.0); + FragColor = vec4(1.0, 1.0, 1.0, 0.0); } From 11725c435e623470633fc4589dc9134abd59824e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Sep 2016 09:47:46 +0200 Subject: [PATCH 08/29] Grab tanHalfFovy from the projection matrix --- src/gl/renderer/gl_postprocess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index d2b1b14c19..232ad91baf 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -158,7 +158,7 @@ void FGLRenderer::AmbientOccludeScene() bool multisample = gl_multisample > 1; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); - float tanHalfFovy = 1.0f / 1.33333302f; // 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; + float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; float invFocalLenX = tanHalfFovy * (mBuffers->GetSceneWidth() / (float)mBuffers->GetSceneHeight()); float invFocalLenY = tanHalfFovy; float nDotVBias = clamp(bias, 0.0f, 1.0f); From 24ab13f1ce6cf2ed4455f74a0d6cdc9afac9631a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Sep 2016 18:19:00 +0200 Subject: [PATCH 09/29] Fix stripes in the reconstructed normals due to down scaling --- src/gl/renderer/gl_postprocess.cpp | 2 +- wadsrc/static/shaders/glsl/lineardepth.fp | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 232ad91baf..da56dc2cf5 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -182,7 +182,7 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA[multisample].Set(1.0f); mLinearDepthShader->InverseDepthRangeB[multisample].Set(0.0f); - mLinearDepthShader->Scale[multisample].Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height); + mLinearDepthShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); mLinearDepthShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index 61e5e81261..558738bd9f 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -24,18 +24,21 @@ void main() #if defined(MULTISAMPLE) ivec2 texSize = textureSize(DepthTexture); - ivec2 ipos = ivec2(uv * vec2(texSize)); +#else + ivec2 texSize = textureSize(DepthTexture, 0); +#endif + + // Use floor here because as we downscale the sampling error has to remain uniform to prevent + // noise in the depth values. + ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + +#if defined(MULTISAMPLE) float depth = 0.0; for (int i = 0; i < SampleCount; i++) depth += texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; depth /= float(SampleCount); #else - /*ivec2 texSize = textureSize(DepthTexture, 0); - ivec2 ipos = ivec2(uv * vec2(texSize)); - if (ipos.x < 0) ipos.x += texSize.x; - if (ipos.y < 0) ipos.y += texSize.y; - float depth = texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0;*/ - float depth = texture(ColorTexture, uv).a != 0.0 ? texture(DepthTexture, uv).x : 1.0; + float depth = texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0; #endif float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); From 0a8cc1b74c8176deff39f931da68b3f698d030bd Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 10 Sep 2016 22:39:09 +0200 Subject: [PATCH 10/29] Fix depth blur --- src/gl/renderer/gl_postprocess.cpp | 12 ++++------ wadsrc/static/shaders/glsl/depthblur.fp | 32 ++++++++----------------- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index da56dc2cf5..c58f6ea3a9 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -108,11 +108,6 @@ CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) { if (self < 0.1f) self = 0.1f; } -CUSTOM_CVAR(Int, gl_ssao_blur_samples, 5, 0) -{ - if (self < 3 || self > 15 || self % 2 == 0) - self = 9; -} EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) @@ -153,7 +148,6 @@ void FGLRenderer::AmbientOccludeScene() float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; const float blurAmount = gl_ssao_blur_amount; - int blurSampleCount = gl_ssao_blur_samples; float aoStrength = gl_ssao_strength; bool multisample = gl_multisample > 1; @@ -164,6 +158,8 @@ void FGLRenderer::AmbientOccludeScene() float nDotVBias = clamp(bias, 0.0f, 1.0f); float r2 = aoRadius * aoRadius; + float blurSharpness = 1.0f / blurAmount; + // Calculate linear depth values glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); @@ -215,14 +211,14 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); mDepthBlurShader->Bind(false); - mDepthBlurShader->BlurSharpness[false].Set(blurAmount); + mDepthBlurShader->BlurSharpness[false].Set(blurSharpness); mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); RenderScreenQuad(); glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); mDepthBlurShader->Bind(true); - mDepthBlurShader->BlurSharpness[true].Set(blurAmount); + mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); mDepthBlurShader->PowExponent[true].Set(1.8f); RenderScreenQuad(); diff --git a/wadsrc/static/shaders/glsl/depthblur.fp b/wadsrc/static/shaders/glsl/depthblur.fp index bd464d03da..c4f4438d30 100644 --- a/wadsrc/static/shaders/glsl/depthblur.fp +++ b/wadsrc/static/shaders/glsl/depthblur.fp @@ -7,39 +7,32 @@ uniform float BlurSharpness; uniform vec2 InvFullResolution; uniform float PowExponent; -#define KERNEL_RADIUS 3.0 +#define KERNEL_RADIUS 7.0 -struct CenterPixelData -{ - vec2 UV; - float Depth; - float Sharpness; -}; - -float CrossBilateralWeight(float r, float sampleDepth, CenterPixelData center) +float CrossBilateralWeight(float r, float sampleDepth, float centerDepth) { const float blurSigma = KERNEL_RADIUS * 0.5; const float blurFalloff = 1.0 / (2.0 * blurSigma * blurSigma); - float deltaZ = (sampleDepth - center.Depth) * center.Sharpness; + float deltaZ = (sampleDepth - centerDepth) * BlurSharpness; return exp2(-r * r * blurFalloff - deltaZ * deltaZ); } -void ProcessSample(float ao, float z, float r, CenterPixelData center, inout float totalAO, inout float totalW) +void ProcessSample(float ao, float z, float r, float centerDepth, inout float totalAO, inout float totalW) { - float w = CrossBilateralWeight(r, z, center); + float w = CrossBilateralWeight(r, z, centerDepth); totalAO += w * ao; totalW += w; } -void ProcessRadius(vec2 deltaUV, CenterPixelData center, inout float totalAO, inout float totalW) +void ProcessRadius(vec2 deltaUV, float centerDepth, inout float totalAO, inout float totalW) { for (float r = 1; r <= KERNEL_RADIUS; r += 1.0) { - vec2 uv = r * deltaUV + center.UV; + vec2 uv = r * deltaUV + TexCoord; vec2 aoZ = texture(AODepthTexture, uv).xy; - ProcessSample(aoZ.x, aoZ.y, r, center, totalAO, totalW); + ProcessSample(aoZ.x, aoZ.y, r, centerDepth, totalAO, totalW); } } @@ -47,16 +40,11 @@ vec2 ComputeBlur(vec2 deltaUV) { vec2 aoZ = texture(AODepthTexture, TexCoord).xy; - CenterPixelData center; - center.UV = TexCoord; - center.Depth = aoZ.y; - center.Sharpness = BlurSharpness; - float totalAO = aoZ.x; float totalW = 1.0; - ProcessRadius(deltaUV, center, totalAO, totalW); - ProcessRadius(-deltaUV, center, totalAO, totalW); + ProcessRadius(deltaUV, aoZ.y, totalAO, totalW); + ProcessRadius(-deltaUV, aoZ.y, totalAO, totalW); return vec2(totalAO / totalW, aoZ.y); } From 37e3172c945298a95709e81752c783bc70b2f8c4 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 11 Sep 2016 11:09:40 +0200 Subject: [PATCH 11/29] Fix random texture sampling bug --- src/gl/renderer/gl_postprocess.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index c58f6ea3a9..f89776d63a 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -191,6 +191,8 @@ void FGLRenderer::AmbientOccludeScene() glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture); 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_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glActiveTexture(GL_TEXTURE0); mSSAOShader->Bind(); mSSAOShader->DepthTexture.Set(0); From 9af34bac69147d22774ac9c999dc3ef751efa86a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 20 Sep 2016 02:57:57 +0200 Subject: [PATCH 12/29] Add gbuffer pass support to FShaderManager and FRenderState --- src/gl/renderer/gl_renderstate.cpp | 7 +- src/gl/renderer/gl_renderstate.h | 19 +++ src/gl/shaders/gl_shader.cpp | 179 ++++++++++++++++++----------- src/gl/shaders/gl_shader.h | 46 +++++--- wadsrc/static/shaders/glsl/main.fp | 6 + 5 files changed, 170 insertions(+), 87 deletions(-) diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 967296cb89..17f19455e7 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -105,6 +105,7 @@ void FRenderState::Reset() mViewMatrix.loadIdentity(); mModelMatrix.loadIdentity(); mTextureMatrix.loadIdentity(); + mPassType = NORMAL_PASS; } //========================================================================== @@ -118,11 +119,11 @@ bool FRenderState::ApplyShader() static const float nulvec[] = { 0.f, 0.f, 0.f, 0.f }; if (mSpecialEffect > EFF_NONE) { - activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect); + activeShader = GLRenderer->mShaderManager->BindEffect(mSpecialEffect, mPassType); } else { - activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f); + activeShader = GLRenderer->mShaderManager->Get(mTextureEnabled ? mEffectState : 4, mAlphaThreshold >= 0.f, mPassType); activeShader->Bind(); } @@ -342,7 +343,7 @@ void FRenderState::ApplyMatrices() { if (GLRenderer->mShaderManager != NULL) { - GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix); + GLRenderer->mShaderManager->ApplyMatrices(&mProjectionMatrix, &mViewMatrix, mPassType); } } diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 1c0a20348a..7bec51be04 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -63,6 +63,13 @@ enum EEffect MAX_EFFECTS }; +enum EPassType +{ + NORMAL_PASS, + GBUFFER_PASS, + MAX_PASS_TYPES +}; + class FRenderState { bool mTextureEnabled; @@ -111,6 +118,8 @@ class FRenderState FShader *activeShader; + EPassType mPassType = NORMAL_PASS; + bool ApplyShader(); public: @@ -459,6 +468,16 @@ public: return mInterpolationFactor; } + void SetPassType(EPassType passType) + { + mPassType = passType; + } + + EPassType GetPassType() + { + return mPassType; + } + // Backwards compatibility crap follows void ApplyFixedFunction(); void DrawColormapOverlay(); diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index d4e05dfa8e..59b941e862 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -180,6 +180,9 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * glBindAttribLocation(hShader, VATTR_COLOR, "aColor"); glBindAttribLocation(hShader, VATTR_VERTEX2, "aVertex2"); + glBindFragDataLocation(hShader, 0, "FragColor"); + glBindFragDataLocation(hShader, 1, "FragData"); + glLinkProgram(hShader); glGetShaderInfoLog(hVertProg, 10000, NULL, buffer); @@ -297,12 +300,13 @@ bool FShader::Bind() // //========================================================================== -FShader *FShaderManager::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard) +FShader *FShaderCollection::Compile (const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType) { FString defines; // this can't be in the shader code due to ATI strangeness. if (gl.MaxLights() == 128) defines += "#define MAXLIGHTS128\n"; if (!usediscard) defines += "#define NO_ALPHATEST\n"; + if (passType == GBUFFER_PASS) defines += "#define GBUFFER_PASS\n"; FShader *shader = NULL; try @@ -385,27 +389,75 @@ static const FEffectShader effectshaders[]= { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", NULL, "#define SIMPLE\n#define NO_ALPHATEST\n" }, }; - -//========================================================================== -// -// -// -//========================================================================== - FShaderManager::FShaderManager() { - if (!gl.legacyMode) CompileShaders(); + if (!gl.legacyMode) + { + for (int passType = 0; passType < MAX_PASS_TYPES; passType++) + mPassShaders.Push(new FShaderCollection((EPassType)passType)); + } } -//========================================================================== -// -// -// -//========================================================================== - FShaderManager::~FShaderManager() { - if (!gl.legacyMode) Clean(); + if (!gl.legacyMode) + { + glUseProgram(0); + mActiveShader = NULL; + + for (auto collection : mPassShaders) + delete collection; + } +} + +void FShaderManager::SetActiveShader(FShader *sh) +{ + if (mActiveShader != sh) + { + glUseProgram(sh!= NULL? sh->GetHandle() : 0); + mActiveShader = sh; + } +} + +FShader *FShaderManager::BindEffect(int effect, EPassType passType) +{ + if (passType < mPassShaders.Size()) + return mPassShaders[passType]->BindEffect(effect); + else + return nullptr; +} + +FShader *FShaderManager::Get(unsigned int eff, bool alphateston, EPassType passType) +{ + if (passType < mPassShaders.Size()) + return mPassShaders[passType]->Get(eff, alphateston); + else + return nullptr; +} + +void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType) +{ + if (gl.legacyMode) + { + glMatrixMode(GL_PROJECTION); + glLoadMatrixf(proj->get()); + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(view->get()); + } + else + { + if (passType < mPassShaders.Size()) + mPassShaders[passType]->ApplyMatrices(proj, view); + + if (mActiveShader) + mActiveShader->Bind(); + } +} + +void FShaderManager::ResetFixedColormap() +{ + for (auto &collection : mPassShaders) + collection->ResetFixedColormap(); } //========================================================================== @@ -414,10 +466,30 @@ FShaderManager::~FShaderManager() // //========================================================================== -void FShaderManager::CompileShaders() +FShaderCollection::FShaderCollection(EPassType passType) { - mActiveShader = NULL; + CompileShaders(passType); +} +//========================================================================== +// +// +// +//========================================================================== + +FShaderCollection::~FShaderCollection() +{ + Clean(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FShaderCollection::CompileShaders(EPassType passType) +{ mTextureEffects.Clear(); mTextureEffectsNAT.Clear(); for (int i = 0; i < MAX_EFFECTS; i++) @@ -427,11 +499,11 @@ void FShaderManager::CompileShaders() for(int i=0;defaultshaders[i].ShaderName != NULL;i++) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, true, passType); mTextureEffects.Push(shc); if (i <= 3) { - FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false); + FShader *shc = Compile(defaultshaders[i].ShaderName, defaultshaders[i].gettexelfunc, false, passType); mTextureEffectsNAT.Push(shc); } } @@ -441,7 +513,7 @@ void FShaderManager::CompileShaders() FString name = ExtractFileBase(usershaders[i]); FName sfn = name; - FShader *shc = Compile(sfn, usershaders[i], true); + FShader *shc = Compile(sfn, usershaders[i], true, passType); mTextureEffects.Push(shc); } @@ -463,11 +535,8 @@ void FShaderManager::CompileShaders() // //========================================================================== -void FShaderManager::Clean() +void FShaderCollection::Clean() { - glUseProgram(0); - mActiveShader = NULL; - for (unsigned int i = 0; i < mTextureEffectsNAT.Size(); i++) { if (mTextureEffectsNAT[i] != NULL) delete mTextureEffectsNAT[i]; @@ -491,7 +560,7 @@ void FShaderManager::Clean() // //========================================================================== -int FShaderManager::Find(const char * shn) +int FShaderCollection::Find(const char * shn) { FName sfn = shn; @@ -505,21 +574,6 @@ int FShaderManager::Find(const char * shn) return -1; } -//========================================================================== -// -// -// -//========================================================================== - -void FShaderManager::SetActiveShader(FShader *sh) -{ - if (mActiveShader != sh) - { - glUseProgram(sh!= NULL? sh->GetHandle() : 0); - mActiveShader = sh; - } -} - //========================================================================== // @@ -527,7 +581,7 @@ void FShaderManager::SetActiveShader(FShader *sh) // //========================================================================== -FShader *FShaderManager::BindEffect(int effect) +FShader *FShaderCollection::BindEffect(int effect) { if (effect >= 0 && effect < MAX_EFFECTS && mEffectShaders[effect] != NULL) { @@ -545,36 +599,25 @@ FShader *FShaderManager::BindEffect(int effect) //========================================================================== EXTERN_CVAR(Int, gl_fuzztype) -void FShaderManager::ApplyMatrices(VSMatrix *proj, VSMatrix *view) +void FShaderCollection::ApplyMatrices(VSMatrix *proj, VSMatrix *view) { - if (gl.legacyMode) + for (int i = 0; i < 4; i++) { - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(proj->get()); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(view->get()); + mTextureEffects[i]->ApplyMatrices(proj, view); + mTextureEffectsNAT[i]->ApplyMatrices(proj, view); } - else + mTextureEffects[4]->ApplyMatrices(proj, view); + if (gl_fuzztype != 0) { - for (int i = 0; i < 4; i++) - { - mTextureEffects[i]->ApplyMatrices(proj, view); - mTextureEffectsNAT[i]->ApplyMatrices(proj, view); - } - mTextureEffects[4]->ApplyMatrices(proj, view); - if (gl_fuzztype != 0) - { - mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view); - } - for (unsigned i = 12; i < mTextureEffects.Size(); i++) - { - mTextureEffects[i]->ApplyMatrices(proj, view); - } - for (int i = 0; i < MAX_EFFECTS; i++) - { - mEffectShaders[i]->ApplyMatrices(proj, view); - } - if (mActiveShader != NULL) mActiveShader->Bind(); + mTextureEffects[4 + gl_fuzztype]->ApplyMatrices(proj, view); + } + for (unsigned i = 12; i < mTextureEffects.Size(); i++) + { + mTextureEffects[i]->ApplyMatrices(proj, view); + } + for (int i = 0; i < MAX_EFFECTS; i++) + { + mEffectShaders[i]->ApplyMatrices(proj, view); } } diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 3439423213..ce285c3ee7 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -37,6 +37,7 @@ enum VATTR_NORMAL = 4 }; +class FShaderCollection; //========================================================================== // @@ -248,7 +249,7 @@ public: class FShader { - friend class FShaderManager; + friend class FShaderCollection; friend class FRenderState; unsigned int hShader; @@ -322,7 +323,6 @@ public: }; - //========================================================================== // // The global shader manager @@ -330,26 +330,40 @@ public: //========================================================================== class FShaderManager { - TArray mTextureEffects; - TArray mTextureEffectsNAT; - FShader *mActiveShader; - FShader *mEffectShaders[MAX_EFFECTS]; - - void Clean(); - void CompileShaders(); - public: FShaderManager(); ~FShaderManager(); - FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard); + + void SetActiveShader(FShader *sh); + FShader *GetActiveShader() const { return mActiveShader; } + + FShader *BindEffect(int effect, EPassType passType); + FShader *Get(unsigned int eff, bool alphateston, EPassType passType); + void ApplyMatrices(VSMatrix *proj, VSMatrix *view, EPassType passType); + + void ResetFixedColormap(); + +private: + FShader *mActiveShader = nullptr; + TArray mPassShaders; +}; + +class FShaderCollection +{ + TArray mTextureEffects; + TArray mTextureEffectsNAT; + FShader *mEffectShaders[MAX_EFFECTS]; + + void Clean(); + void CompileShaders(EPassType passType); + +public: + FShaderCollection(EPassType passType); + ~FShaderCollection(); + FShader *Compile(const char *ShaderName, const char *ShaderPath, bool usediscard, EPassType passType); int Find(const char *mame); FShader *BindEffect(int effect); - void SetActiveShader(FShader *sh); void ApplyMatrices(VSMatrix *proj, VSMatrix *view); - FShader *GetActiveShader() const - { - return mActiveShader; - } void ResetFixedColormap() { diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 95ac874b77..4d3531f010 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -5,6 +5,9 @@ in vec4 vTexCoord; in vec4 vColor; out vec4 FragColor; +#ifdef GBUFFER_PASS +out vec4 FragData; +#endif #ifdef SHADER_STORAGE_LIGHTS layout(std430, binding = 1) buffer LightBufferSSO @@ -345,5 +348,8 @@ void main() } } FragColor = frag; +#ifdef GBUFFER_PASS + FragData = vec4(uFogColor.rgb, 1.0); +#endif } From d7741362823fbe3bca3821b20fe75d0802575379 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 21 Sep 2016 02:04:56 +0200 Subject: [PATCH 13/29] Added SceneData texture as the second colorbuffer when rendering a scene and placed fog data into it --- src/gl/renderer/gl_postprocess.cpp | 18 ++++++++------ src/gl/renderer/gl_renderer.cpp | 2 +- src/gl/scene/gl_scene.cpp | 23 ++++++++++++++++-- src/gl/shaders/gl_ambientshader.cpp | 23 +++++++++++------- src/gl/shaders/gl_ambientshader.h | 10 +++++--- src/gl/system/gl_cvars.h | 6 +++++ wadsrc/static/shaders/glsl/main.fp | 28 +++++++++++++++++++++- wadsrc/static/shaders/glsl/ssaocombine.fp | 29 ++++++++++++++++++++++- 8 files changed, 115 insertions(+), 24 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index f89776d63a..3b94fd8cc1 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -137,9 +137,6 @@ void FGLRenderer::PostProcessScene() void FGLRenderer::AmbientOccludeScene() { - if (!gl_ssao || !FGLRenderBuffers::IsEnabled()) - return; - FGLDebug::PushGroup("AmbientOccludeScene"); FGLPostProcessState savedState; @@ -226,20 +223,27 @@ void FGLRenderer::AmbientOccludeScene() RenderScreenQuad(); // Add SSAO back to scene texture: - mBuffers->BindSceneFB(); + mBuffers->BindSceneFB(false); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, buffers); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); if (gl_ssao_debug) glBlendFunc(GL_ONE, GL_ZERO); else - glBlendFunc(GL_ZERO, GL_SRC_COLOR); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - mSSAOCombineShader->Bind(); - mSSAOCombineShader->AODepthTexture.Set(0); + mBuffers->BindSceneDataTexture(1); + mSSAOCombineShader->Bind(multisample); + mSSAOCombineShader->AODepthTexture[multisample].Set(0); + mSSAOCombineShader->SceneDataTexture[multisample].Set(1); + if (multisample) mSSAOCombineShader->SampleCount[multisample].Set(gl_multisample); + mSSAOCombineShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); + mSSAOCombineShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); FGLDebug::PopGroup(); diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index befa330e96..368db63d2e 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -323,7 +323,7 @@ void FGLRenderer::Begin2D() if (mBuffers->Setup(mScreenViewport.width, mScreenViewport.height, mSceneViewport.width, mSceneViewport.height)) { if (mDrawingScene2D) - mBuffers->BindSceneFB(); + mBuffers->BindSceneFB(false); else mBuffers->BindCurrentFB(); } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index a50fe87f8b..6a8c9a11a1 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -158,7 +158,11 @@ void FGLRenderer::Set3DViewport(bool mainview) { if (mainview && mBuffers->Setup(mScreenViewport.width, mScreenViewport.height, mSceneViewport.width, mSceneViewport.height)) { - mBuffers->BindSceneFB(); + mBuffers->BindSceneFB(gl_ssao); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(gl_ssao ? 2 : 1, buffers); + gl_RenderState.SetPassType(gl_ssao ? GBUFFER_PASS : NORMAL_PASS); + gl_RenderState.Apply(); } // Always clear all buffers with scissor test disabled. @@ -491,7 +495,13 @@ void FGLRenderer::DrawScene(int drawmode) RenderScene(recursion); - AmbientOccludeScene(); + bool applySSAO = gl_ssao && FGLRenderBuffers::IsEnabled() && drawmode != DM_PORTAL; + if (applySSAO) + { + AmbientOccludeScene(); + gl_RenderState.SetPassType(GBUFFER_PASS); + gl_RenderState.Apply(); + } // Handle all portals after rendering the opaque objects but before // doing all translucent stuff @@ -499,6 +509,15 @@ void FGLRenderer::DrawScene(int drawmode) GLPortal::EndFrame(); recursion--; RenderTranslucent(); + + if (applySSAO) + { + mBuffers->BindSceneFB(true); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(2, buffers); + gl_RenderState.SetPassType(NORMAL_PASS); + gl_RenderState.Apply(); + } } diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 3fbd034348..4fa5b0e019 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -120,16 +120,21 @@ void FDepthBlurShader::Bind(bool vertical) shader.Bind(); } -void FSSAOCombineShader::Bind() +void FSSAOCombineShader::Bind(bool multisample) { - if (!mShader) + auto &shader = mShader[multisample]; + if (!shader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", "", 330); - mShader.SetFragDataLocation(0, "FragColor"); - mShader.Link("shaders/glsl/ssaocombine"); - mShader.SetAttribLocation(0, "PositionInProjection"); - AODepthTexture.Init(mShader, "AODepthTexture"); + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/ssaocombine"); + shader.SetAttribLocation(0, "PositionInProjection"); + AODepthTexture[multisample].Init(shader, "AODepthTexture"); + SceneDataTexture[multisample].Init(shader, "SceneDataTexture"); + SampleCount[multisample].Init(shader, "SampleCount"); + Scale[multisample].Init(shader, "Scale"); + Offset[multisample].Init(shader, "Offset"); } - mShader.Bind(); + shader.Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 9c97791ba8..f36b10625e 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -59,12 +59,16 @@ private: class FSSAOCombineShader { public: - void Bind(); + void Bind(bool multisample); - FBufferedUniformSampler AODepthTexture; + FBufferedUniformSampler AODepthTexture[2]; + FBufferedUniformSampler SceneDataTexture[2]; + FBufferedUniform1i SampleCount[2]; + FBufferedUniform2f Scale[2]; + FBufferedUniform2f Offset[2]; private: - FShaderProgram mShader; + FShaderProgram mShader[2]; }; #endif \ No newline at end of file diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 4cda3657de..97bd0b46c6 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -50,6 +50,12 @@ EXTERN_CVAR(Bool, gl_lens) EXTERN_CVAR(Float, gl_lens_k) EXTERN_CVAR(Float, gl_lens_kcube) EXTERN_CVAR(Float, gl_lens_chromatic) +EXTERN_CVAR(Bool, gl_ssao) +EXTERN_CVAR(Float, gl_ssao_strength) +EXTERN_CVAR(Bool, gl_ssao_debug) +EXTERN_CVAR(Float, gl_ssao_bias) +EXTERN_CVAR(Float, gl_ssao_radius) +EXTERN_CVAR(Float, gl_ssao_blur_amount) EXTERN_CVAR(Int, gl_debug_level) EXTERN_CVAR(Bool, gl_debug_breakpoint) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 4d3531f010..0d2b419c15 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -233,6 +233,32 @@ vec4 applyFog(vec4 frag, float fogfactor) return vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a); } +//=========================================================================== +// +// The color of the fragment if it is fully occluded by ambient lighting +// +//=========================================================================== + +vec3 AmbientOcclusionColor() +{ + float fogdist; + float fogfactor; + + // + // calculate fog factor + // + if (uFogEnabled == -1) + { + fogdist = pixelpos.w; + } + else + { + fogdist = max(16.0, length(pixelpos.xyz)); + } + fogfactor = exp2 (uFogDensity * fogdist); + + return mix(uFogColor.rgb, vec3(0.0), fogfactor); +} //=========================================================================== // @@ -349,7 +375,7 @@ void main() } FragColor = frag; #ifdef GBUFFER_PASS - FragData = vec4(uFogColor.rgb, 1.0); + FragData = vec4(AmbientOcclusionColor(), 1.0); #endif } diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp index 21fdff1024..7cd0962763 100644 --- a/wadsrc/static/shaders/glsl/ssaocombine.fp +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -4,8 +4,35 @@ out vec4 FragColor; uniform sampler2D AODepthTexture; +#if defined(MULTISAMPLE) +uniform sampler2DMS SceneDataTexture; +uniform int SampleCount; +#else +uniform sampler2D SceneDataTexture; +#endif + +uniform vec2 Scale; +uniform vec2 Offset; + void main() { + vec2 uv = Offset + TexCoord * Scale; +#if defined(MULTISAMPLE) + ivec2 texSize = textureSize(SceneDataTexture); +#else + ivec2 texSize = textureSize(SceneDataTexture, 0); +#endif + ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + +#if defined(MULTISAMPLE) + vec3 fogColor = vec3(0.0); + for (int i = 0; i < SampleCount; i++) + fogColor += texelFetch(SceneDataTexture, ipos, i).rgb; + fogColor /= float(SampleCount); +#else + vec3 fogColor = texelFetch(SceneDataTexture, ipos, 0).rgb; +#endif + float attenutation = texture(AODepthTexture, TexCoord).x; - FragColor = vec4(attenutation, attenutation, attenutation, 0.0); + FragColor = vec4(fogColor, 1.0 - attenutation); } From 0397fe185f68d923fec0cee03faee4bc946e0126 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 22 Sep 2016 03:49:19 +0200 Subject: [PATCH 14/29] Don't do ambient occlusion when rendering to texture --- src/gl/scene/gl_scene.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 6a8c9a11a1..59d6e09871 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -493,14 +493,29 @@ void FGLRenderer::DrawScene(int drawmode) } GLRenderer->mClipPortal = NULL; // this must be reset before any portal recursion takes place. - RenderScene(recursion); - - bool applySSAO = gl_ssao && FGLRenderBuffers::IsEnabled() && drawmode != DM_PORTAL; + // If SSAO is active, switch to gbuffer shaders and use the gbuffer framebuffer + bool applySSAO = gl_ssao && FGLRenderBuffers::IsEnabled() && drawmode == DM_MAINVIEW; if (applySSAO) { - AmbientOccludeScene(); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(2, buffers); gl_RenderState.SetPassType(GBUFFER_PASS); gl_RenderState.Apply(); + gl_RenderState.ApplyMatrices(); + } + + RenderScene(recursion); + + // Apply ambient occlusion and switch back to shaders without gbuffer output + if (applySSAO) + { + GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, buffers); + AmbientOccludeScene(); + mBuffers->BindSceneFB(true); + gl_RenderState.SetPassType(NORMAL_PASS); + gl_RenderState.Apply(); + gl_RenderState.ApplyMatrices(); } // Handle all portals after rendering the opaque objects but before @@ -509,15 +524,6 @@ void FGLRenderer::DrawScene(int drawmode) GLPortal::EndFrame(); recursion--; RenderTranslucent(); - - if (applySSAO) - { - mBuffers->BindSceneFB(true); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(2, buffers); - gl_RenderState.SetPassType(NORMAL_PASS); - gl_RenderState.Apply(); - } } From 3f11c0562c446ce2c007c8a10ec99f3898ccc7fe Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Sep 2016 19:26:25 +0200 Subject: [PATCH 15/29] Add ssao quality setting --- src/gl/renderer/gl_postprocess.cpp | 7 +++- src/gl/scene/gl_scene.cpp | 9 +++-- src/gl/shaders/gl_ambientshader.cpp | 63 ++++++++++++++++++----------- src/gl/shaders/gl_ambientshader.h | 13 +++++- src/gl/system/gl_cvars.h | 2 +- wadsrc/static/language.enu | 5 ++- wadsrc/static/menudef.zz | 10 ++++- 7 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 3b94fd8cc1..2fcfe245ac 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -99,7 +99,12 @@ CVAR(Float, gl_lens_k, -0.12f, 0) CVAR(Float, gl_lens_kcube, 0.1f, 0) CVAR(Float, gl_lens_chromatic, 1.12f, 0) -CVAR(Bool, gl_ssao, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_ssao, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self > 3) + self = 0; +} + CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_ssao_debug, false, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 59d6e09871..3efd22155f 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -158,10 +158,11 @@ void FGLRenderer::Set3DViewport(bool mainview) { if (mainview && mBuffers->Setup(mScreenViewport.width, mScreenViewport.height, mSceneViewport.width, mSceneViewport.height)) { - mBuffers->BindSceneFB(gl_ssao); + bool useSSAO = (gl_ssao != 0); + mBuffers->BindSceneFB(useSSAO); GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(gl_ssao ? 2 : 1, buffers); - gl_RenderState.SetPassType(gl_ssao ? GBUFFER_PASS : NORMAL_PASS); + glDrawBuffers(useSSAO ? 2 : 1, buffers); + gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); gl_RenderState.Apply(); } @@ -494,7 +495,7 @@ void FGLRenderer::DrawScene(int drawmode) GLRenderer->mClipPortal = NULL; // this must be reset before any portal recursion takes place. // If SSAO is active, switch to gbuffer shaders and use the gbuffer framebuffer - bool applySSAO = gl_ssao && FGLRenderBuffers::IsEnabled() && drawmode == DM_MAINVIEW; + bool applySSAO = gl_ssao != 0 && FGLRenderBuffers::IsEnabled() && drawmode == DM_MAINVIEW; if (applySSAO) { GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 4fa5b0e019..7d0e26a6a7 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -74,32 +74,47 @@ void FLinearDepthShader::Bind(bool multisample) void FSSAOShader::Bind() { - if (!mShader) + auto &shader = mShader[gl_ssao]; + if (!shader) { - const char *defines = R"( - #define USE_RANDOM_TEXTURE - #define RANDOM_TEXTURE_WIDTH 4.0 - #define NUM_DIRECTIONS 8.0 - #define NUM_STEPS 4.0 - )"; - - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", defines, 330); - mShader.SetFragDataLocation(0, "FragColor"); - mShader.Link("shaders/glsl/ssao"); - mShader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture.Init(mShader, "DepthTexture"); - RandomTexture.Init(mShader, "RandomTexture"); - UVToViewA.Init(mShader, "UVToViewA"); - UVToViewB.Init(mShader, "UVToViewB"); - InvFullResolution.Init(mShader, "InvFullResolution"); - NDotVBias.Init(mShader, "NDotVBias"); - NegInvR2.Init(mShader, "NegInvR2"); - RadiusToScreen.Init(mShader, "RadiusToScreen"); - AOMultiplier.Init(mShader, "AOMultiplier"); - AOStrength.Init(mShader, "AOStrength"); + shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao), 330); + shader.SetFragDataLocation(0, "FragColor"); + shader.Link("shaders/glsl/ssao"); + shader.SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(shader, "DepthTexture"); + RandomTexture.Init(shader, "RandomTexture"); + UVToViewA.Init(shader, "UVToViewA"); + UVToViewB.Init(shader, "UVToViewB"); + InvFullResolution.Init(shader, "InvFullResolution"); + NDotVBias.Init(shader, "NDotVBias"); + NegInvR2.Init(shader, "NegInvR2"); + RadiusToScreen.Init(shader, "RadiusToScreen"); + AOMultiplier.Init(shader, "AOMultiplier"); + AOStrength.Init(shader, "AOStrength"); } - mShader.Bind(); + shader.Bind(); +} + +FString FSSAOShader::GetDefines(int mode) +{ + int numDirections, numSteps; + switch (gl_ssao) + { + default: + case LowQuality: numDirections = 2; numSteps = 4; break; + case MediumQuality: numDirections = 4; numSteps = 4; break; + case HighQuality: numDirections = 8; numSteps = 4; break; + } + + FString defines; + defines.Format(R"( + #define USE_RANDOM_TEXTURE + #define RANDOM_TEXTURE_WIDTH 4.0 + #define NUM_DIRECTIONS %d.0 + #define NUM_STEPS %d.0 + )", numDirections, numSteps); + return defines; } void FDepthBlurShader::Bind(bool vertical) diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index f36b10625e..704729b246 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -39,7 +39,18 @@ public: FBufferedUniform1f AOStrength; private: - FShaderProgram mShader; + enum Quality + { + Off, + LowQuality, + MediumQuality, + HighQuality, + NumQualityModes + }; + + FString GetDefines(int mode); + + FShaderProgram mShader[NumQualityModes]; }; class FDepthBlurShader diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 97bd0b46c6..845f0dd22f 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -50,7 +50,7 @@ EXTERN_CVAR(Bool, gl_lens) EXTERN_CVAR(Float, gl_lens_k) EXTERN_CVAR(Float, gl_lens_kcube) EXTERN_CVAR(Float, gl_lens_chromatic) -EXTERN_CVAR(Bool, gl_ssao) +EXTERN_CVAR(Int, gl_ssao) EXTERN_CVAR(Float, gl_ssao_strength) EXTERN_CVAR(Bool, gl_ssao_debug) EXTERN_CVAR(Float, gl_ssao_bias) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 197e262f55..fae6d871b5 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2167,6 +2167,9 @@ NETMNU_TICBALANCE = "Latency balancing"; // Option Values OPTVAL_OFF = "Off"; OPTVAL_ON = "On"; +OPTVAL_LOW = "Low"; +OPTVAL_MEDIUM = "Medium"; +OPTVAL_HIGH = "High"; OPTVAL_MALE = "Male"; OPTVAL_FEMALE = "Female"; OPTVAL_OTHER = "Other"; @@ -2633,7 +2636,7 @@ GLPREFMNU_MULTISAMPLE = "Multisample"; GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_LENS = "Lens distortion effect"; -GLPREFMNU_SSAO = "Ambient occlusion"; +GLPREFMNU_SSAO = "Ambient occlusion quality"; // Option Values OPTVAL_SMART = "Smart"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 68523ea83f..8b742ceff5 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -42,6 +42,14 @@ OptionValue "TonemapModes" 5, "$OPTVAL_PALETTE" } +OptionValue "SSAOModes" +{ + 0, "$OPTVAL_OFF" + 1, "$OPTVAL_LOW" + 2, "$OPTVAL_MEDIUM" + 3, "$OPTVAL_HIGH" +} + OptionValue "TextureFormats" { 0, "$OPTVAL_RGBA8" @@ -226,5 +234,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_LENS", gl_lens, "OnOff" - Option "$GLPREFMNU_SSAO", gl_ssao, "OnOff" + Option "$GLPREFMNU_SSAO", gl_ssao, "SSAOModes" } From 979e70ca8f9514b1f976d604e7a0a63907149238 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Sep 2016 20:09:40 +0200 Subject: [PATCH 16/29] Add gl_ssao_portals for controlling how many portals gets SSAO --- src/gl/renderer/gl_postprocess.cpp | 6 ++++++ src/gl/scene/gl_scene.cpp | 13 +++++++++++-- src/gl/system/gl_cvars.h | 1 + wadsrc/static/language.enu | 1 + wadsrc/static/menudef.zz | 1 + 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 2fcfe245ac..23fdda2ebe 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -105,6 +105,12 @@ CUSTOM_CVAR(Int, gl_ssao, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) self = 0; } +CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0) + self = 0; +} + CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, gl_ssao_debug, false, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 3efd22155f..b6120f9400 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -477,6 +477,7 @@ void FGLRenderer::RenderTranslucent() void FGLRenderer::DrawScene(int drawmode) { static int recursion=0; + static int ssao_portals_available = 0; if (camera != nullptr) { @@ -494,8 +495,16 @@ void FGLRenderer::DrawScene(int drawmode) } GLRenderer->mClipPortal = NULL; // this must be reset before any portal recursion takes place. - // If SSAO is active, switch to gbuffer shaders and use the gbuffer framebuffer - bool applySSAO = gl_ssao != 0 && FGLRenderBuffers::IsEnabled() && drawmode == DM_MAINVIEW; + // Decide if we need to do ssao for this scene + bool applySSAO = gl_ssao != 0 && FGLRenderBuffers::IsEnabled(); + switch (drawmode) + { + case DM_MAINVIEW: ssao_portals_available = gl_ssao_portals; break; + case DM_OFFSCREEN: ssao_portals_available = 0; applySSAO = false; break; + case DM_PORTAL: applySSAO = applySSAO && (ssao_portals_available > 0); ssao_portals_available--; break; + } + + // If SSAO is active, switch to gbuffer shaders and use the framebuffer with gbuffers if (applySSAO) { GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 845f0dd22f..836787117d 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -51,6 +51,7 @@ EXTERN_CVAR(Float, gl_lens_k) EXTERN_CVAR(Float, gl_lens_kcube) EXTERN_CVAR(Float, gl_lens_chromatic) EXTERN_CVAR(Int, gl_ssao) +EXTERN_CVAR(Int, gl_ssao_portals) EXTERN_CVAR(Float, gl_ssao_strength) EXTERN_CVAR(Bool, gl_ssao_debug) EXTERN_CVAR(Float, gl_ssao_bias) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index fae6d871b5..cb3af51aaf 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2637,6 +2637,7 @@ GLPREFMNU_TONEMAP = "Tonemap Mode"; GLPREFMNU_BLOOM = "Bloom effect"; GLPREFMNU_LENS = "Lens distortion effect"; GLPREFMNU_SSAO = "Ambient occlusion quality"; +GLPREFMNU_SSAO_PORTALS = "Portals with AO"; // Option Values OPTVAL_SMART = "Smart"; diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index 8b742ceff5..4784baa937 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -235,4 +235,5 @@ OptionMenu "GLPrefOptions" Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff" Option "$GLPREFMNU_LENS", gl_lens, "OnOff" Option "$GLPREFMNU_SSAO", gl_ssao, "SSAOModes" + Slider "$GLPREFMNU_SSAO_PORTALS", gl_ssao_portals, 0.0, 4.0, 1.0, 0 } From 6cb9f875dd3acc102cf46be46d0a8cb38d4860c6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 25 Sep 2016 00:31:43 +0200 Subject: [PATCH 17/29] Fix missing call from merge --- src/gl/renderer/gl_postprocess.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 23fdda2ebe..6c18edd1e6 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -137,6 +137,7 @@ void FGLRenderer::PostProcessScene() UpdateCameraExposure(); BloomScene(); TonemapScene(); + ColormapScene(); LensDistortScene(); } From 287acea6b46669d4192b132e84d889b4e0730c95 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 25 Sep 2016 00:31:57 +0200 Subject: [PATCH 18/29] Update copyright --- src/gl/shaders/gl_ambientshader.cpp | 60 ++++++++++------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 7d0e26a6a7..43adb5c0eb 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -1,42 +1,24 @@ -/* -** gl_bloomshader.cpp -** Shaders used for screen space ambient occlusion -** -**--------------------------------------------------------------------------- -** 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. -**--------------------------------------------------------------------------- -** -*/ +// +//--------------------------------------------------------------------------- +// +// Copyright(C) 2016 Magnus Norddahl +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// #include "gl/system/gl_system.h" #include "files.h" From 7c4780638201122f6ad8024c5edcce26b6759767 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 3 Oct 2016 09:18:47 +0200 Subject: [PATCH 19/29] Fix aspect ratio bug in LensDistortScene --- src/gl/renderer/gl_postprocess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 6c18edd1e6..ff65fee6d0 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -569,7 +569,7 @@ void FGLRenderer::LensDistortScene() 0.0f }; - float aspect = mSceneViewport.width / mSceneViewport.height; + float aspect = mSceneViewport.width / (float)mSceneViewport.height; // Scale factor to keep sampling within the input texture float r2 = aspect * aspect * 0.25 + 0.25f; From 490dd612b3d662b4f190f34dc37e4367fddedc61 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 5 Oct 2016 03:56:58 +0200 Subject: [PATCH 20/29] Keep using render buffers when ssao is off, for better performance --- src/gl/renderer/gl_renderbuffers.cpp | 91 ++++++++++++++++++++-------- src/gl/renderer/gl_renderbuffers.h | 4 +- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 54d597c4da..9915b024c8 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -83,9 +83,18 @@ void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); DeleteFrameBuffer(mSceneDataFB); - DeleteTexture(mSceneMultisample); - DeleteTexture(mSceneData); - DeleteTexture(mSceneDepthStencil); + if (mSceneUsesTextures) + { + DeleteTexture(mSceneMultisample); + DeleteTexture(mSceneData); + DeleteTexture(mSceneDepthStencil); + } + else + { + DeleteRenderBuffer(mSceneMultisample); + DeleteRenderBuffer(mSceneData); + DeleteRenderBuffer(mSceneDepthStencil); + } } void FGLRenderBuffers::ClearPipeline() @@ -188,6 +197,7 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei I_FatalError("Requested invalid render buffer sizes: screen = %dx%d", width, height); int samples = clamp((int)gl_multisample, 0, mMaxSamples); + bool needsSceneTextures = (gl_ssao != 0); GLint activeTex; GLint textureBinding; @@ -195,19 +205,16 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei glActiveTexture(GL_TEXTURE0); glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); - if (width == mWidth && height == mHeight && mSamples != samples) - { - CreateScene(mWidth, mHeight, samples); - mSamples = samples; - } - else if (width != mWidth || height != mHeight) - { + if (width != mWidth || height != mHeight) CreatePipeline(width, height); - CreateScene(width, height, samples); - mWidth = width; - mHeight = height; - mSamples = samples; - } + + if (width != mWidth || height != mHeight || mSamples != samples || mSceneUsesTextures != needsSceneTextures) + CreateScene(width, height, samples, needsSceneTextures); + + mWidth = width; + mHeight = height; + mSamples = samples; + mSceneUsesTextures = needsSceneTextures; // Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight) @@ -247,24 +254,44 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei // //========================================================================== -void FGLRenderBuffers::CreateScene(int width, int height, int samples) +void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool needsSceneTextures) { ClearScene(); if (samples > 1) { - mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); - mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); - mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); + if (needsSceneTextures) + { + mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); + mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); + mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneData, mSceneDepthStencil, true); + } + else + { + mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples); + mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneDepthStencil, true); + } } else { - mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); - mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); + if (needsSceneTextures) + { + mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneData, mSceneDepthStencil, false); + } + else + { + mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + } } - - mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], 0, mSceneDepthStencil, samples > 1); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneData, mSceneDepthStencil, samples > 1); } //========================================================================== @@ -517,6 +544,22 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer) +{ + GLuint handle = 0; + glGenFramebuffers(1, &handle); + glBindFramebuffer(GL_FRAMEBUFFER, handle); + FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); + if (colorIsARenderBuffer) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); + else + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); + if (CheckFrameBufferCompleteness()) + ClearFrameBuffer(true, true); + return handle; +} + GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) { GLuint handle = 0; diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 2ca58149f5..3fcc2c07ba 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -81,7 +81,7 @@ private: void ClearBloom(); void ClearExposureLevels(); void ClearAmbientOcclusion(); - void CreateScene(int width, int height, int samples); + void CreateScene(int width, int height, int samples, bool needsSceneTextures); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); void CreateExposureLevels(int width, int height); @@ -92,6 +92,7 @@ private: GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height); GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); @@ -115,6 +116,7 @@ private: GLuint mSceneData = 0; GLuint mSceneFB = 0; GLuint mSceneDataFB = 0; + bool mSceneUsesTextures = false; // Effect/HUD buffers GLuint mPipelineTexture[NumPipelineTextures]; From 00e72028efd9145eb54704fa974c57d2034b7cec Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 5 Oct 2016 07:57:27 +0200 Subject: [PATCH 21/29] Add another gbuffer with normal data and make ssao pass use it --- src/gl/renderer/gl_postprocess.cpp | 58 ++++++----- src/gl/renderer/gl_postprocessstate.cpp | 55 +++++----- src/gl/renderer/gl_postprocessstate.h | 7 +- src/gl/renderer/gl_renderbuffers.cpp | 54 +++++++--- src/gl/renderer/gl_renderbuffers.h | 8 +- src/gl/scene/gl_scene.cpp | 8 +- src/gl/shaders/gl_ambientshader.cpp | 121 +++++++++++++--------- src/gl/shaders/gl_ambientshader.h | 45 ++++---- src/gl/shaders/gl_shader.cpp | 3 +- src/gl/system/gl_cvars.h | 2 +- wadsrc/static/shaders/glsl/main.fp | 6 +- wadsrc/static/shaders/glsl/ssao.fp | 23 +++- wadsrc/static/shaders/glsl/ssaocombine.fp | 12 +-- 13 files changed, 241 insertions(+), 161 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index fde8da3533..ac5a6336d3 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -121,7 +121,7 @@ CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) } CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -CVAR(Bool, gl_ssao_debug, false, 0) +CVAR(Int, gl_ssao_debug, 0, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) @@ -162,13 +162,12 @@ void FGLRenderer::AmbientOccludeScene() FGLDebug::PushGroup("AmbientOccludeScene"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(3); float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; const float blurAmount = gl_ssao_blur_amount; float aoStrength = gl_ssao_strength; - bool multisample = gl_multisample > 1; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); float tanHalfFovy = 1.0f / gl_RenderState.mProjectionMatrix.get()[5]; @@ -189,16 +188,16 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); - mLinearDepthShader->Bind(multisample); - mLinearDepthShader->DepthTexture[multisample].Set(0); - mLinearDepthShader->ColorTexture[multisample].Set(1); - if (multisample) mLinearDepthShader->SampleCount[multisample].Set(gl_multisample); - mLinearDepthShader->LinearizeDepthA[multisample].Set(1.0f / GetZFar() - 1.0f / GetZNear()); - mLinearDepthShader->LinearizeDepthB[multisample].Set(MAX(1.0f / GetZNear(), 1.e-8f)); - mLinearDepthShader->InverseDepthRangeA[multisample].Set(1.0f); - mLinearDepthShader->InverseDepthRangeB[multisample].Set(0.0f); - mLinearDepthShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mLinearDepthShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mLinearDepthShader->Bind(); + mLinearDepthShader->DepthTexture.Set(0); + mLinearDepthShader->ColorTexture.Set(1); + if (gl_multisample > 1) mLinearDepthShader->SampleCount.Set(gl_multisample); + mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); + mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); + mLinearDepthShader->InverseDepthRangeA.Set(1.0f); + mLinearDepthShader->InverseDepthRangeB.Set(0.0f); + mLinearDepthShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); + mLinearDepthShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); // Apply ambient occlusion @@ -212,10 +211,14 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + mBuffers->BindSceneNormalTexture(2); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); mSSAOShader->Bind(); mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); + mSSAOShader->NormalTexture.Set(2); mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); @@ -246,26 +249,29 @@ void FGLRenderer::AmbientOccludeScene() // Add SSAO back to scene texture: mBuffers->BindSceneFB(false); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, buffers); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - if (gl_ssao_debug) + if (gl_ssao_debug > 1) glBlendFunc(GL_ONE, GL_ZERO); else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (gl_ssao_debug == 1) + { + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - mBuffers->BindSceneDataTexture(1); - mSSAOCombineShader->Bind(multisample); - mSSAOCombineShader->AODepthTexture[multisample].Set(0); - mSSAOCombineShader->SceneDataTexture[multisample].Set(1); - if (multisample) mSSAOCombineShader->SampleCount[multisample].Set(gl_multisample); - mSSAOCombineShader->Scale[multisample].Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mSSAOCombineShader->Offset[multisample].Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mBuffers->BindSceneFogTexture(1); + mSSAOCombineShader->Bind(); + mSSAOCombineShader->AODepthTexture.Set(0); + mSSAOCombineShader->SceneFogTexture.Set(1); + if (gl_multisample > 1) mSSAOCombineShader->SampleCount.Set(gl_multisample); + mSSAOCombineShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); + mSSAOCombineShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); FGLDebug::PopGroup(); @@ -285,7 +291,7 @@ void FGLRenderer::UpdateCameraExposure() FGLDebug::PushGroup("UpdateCameraExposure"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); // Extract light level from scene texture: const auto &level0 = mBuffers->ExposureLevels[0]; @@ -358,7 +364,7 @@ void FGLRenderer::BloomScene() FGLDebug::PushGroup("BloomScene"); FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); const float blurAmount = gl_bloom_amount; int sampleCount = gl_bloom_kernel_size; @@ -461,7 +467,7 @@ void FGLRenderer::TonemapScene() } else { - savedState.SaveTextureBinding1(); + savedState.SaveTextureBindings(2); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture); glActiveTexture(GL_TEXTURE0); diff --git a/src/gl/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp index 57b7862f5d..fead1435aa 100644 --- a/src/gl/renderer/gl_postprocessstate.cpp +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -45,17 +45,7 @@ FGLPostProcessState::FGLPostProcessState() { glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[0]); - glBindTexture(GL_TEXTURE_2D, 0); - if (gl.flags & RFL_SAMPLER_OBJECTS) - { - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[0]); - glBindSampler(0, 0); - glActiveTexture(GL_TEXTURE0 + 1); - glGetIntegerv(GL_SAMPLER_BINDING, &samplerBinding[1]); - glBindSampler(1, 0); - glActiveTexture(GL_TEXTURE0); - } + SaveTextureBindings(1); glGetBooleanv(GL_BLEND, &blendEnabled); glGetBooleanv(GL_SCISSOR_TEST, &scissorEnabled); @@ -75,12 +65,26 @@ FGLPostProcessState::FGLPostProcessState() glDisable(GL_BLEND); } -void FGLPostProcessState::SaveTextureBinding1() +void FGLPostProcessState::SaveTextureBindings(unsigned int numUnits) { - glActiveTexture(GL_TEXTURE1); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[1]); - glBindTexture(GL_TEXTURE_2D, 0); - textureBinding1Saved = true; + while (textureBinding.Size() < numUnits) + { + unsigned int i = textureBinding.Size(); + + GLint texture; + glActiveTexture(GL_TEXTURE0 + i); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); + glBindTexture(GL_TEXTURE_2D, 0); + textureBinding.Push(texture); + + if (gl.flags & RFL_SAMPLER_OBJECTS) + { + GLint sampler; + glGetIntegerv(GL_SAMPLER_BINDING, &sampler); + glBindSampler(i, 0); + samplerBinding.Push(sampler); + } + } glActiveTexture(GL_TEXTURE0); } @@ -117,25 +121,22 @@ FGLPostProcessState::~FGLPostProcessState() glUseProgram(currentProgram); - if (textureBinding1Saved) + // Fully unbind to avoid incomplete texture warnings from Nvidia's driver when gl_debug_level 4 is active + for (unsigned int i = 0; i < textureBinding.Size(); i++) { - glActiveTexture(GL_TEXTURE1); + glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - if (gl.flags & RFL_SAMPLER_OBJECTS) + for (unsigned int i = 0; i < samplerBinding.Size(); i++) { - glBindSampler(0, samplerBinding[0]); - glBindSampler(1, samplerBinding[1]); + glBindSampler(i, samplerBinding[i]); } - glBindTexture(GL_TEXTURE_2D, textureBinding[0]); - if (textureBinding1Saved) + for (unsigned int i = 0; i < textureBinding.Size(); i++) { - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, textureBinding[1]); + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_2D, textureBinding[i]); } glActiveTexture(activeTex); diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h index bf53aa7de9..795a7d4ba9 100644 --- a/src/gl/renderer/gl_postprocessstate.h +++ b/src/gl/renderer/gl_postprocessstate.h @@ -14,15 +14,15 @@ public: FGLPostProcessState(); ~FGLPostProcessState(); - void SaveTextureBinding1(); + void SaveTextureBindings(unsigned int numUnits); private: FGLPostProcessState(const FGLPostProcessState &) = delete; FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; GLint activeTex; - GLint textureBinding[2]; - GLint samplerBinding[2]; + TArray textureBinding; + TArray samplerBinding; GLboolean blendEnabled; GLboolean scissorEnabled; GLboolean depthEnabled; @@ -34,7 +34,6 @@ private: GLint blendSrcAlpha; GLint blendDestRgb; GLint blendDestAlpha; - bool textureBinding1Saved = false; }; #endif diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 9915b024c8..1a1509d7a6 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -86,13 +86,15 @@ void FGLRenderBuffers::ClearScene() if (mSceneUsesTextures) { DeleteTexture(mSceneMultisample); - DeleteTexture(mSceneData); + DeleteTexture(mSceneFog); + DeleteTexture(mSceneNormal); DeleteTexture(mSceneDepthStencil); } else { DeleteRenderBuffer(mSceneMultisample); - DeleteRenderBuffer(mSceneData); + DeleteRenderBuffer(mSceneFog); + DeleteRenderBuffer(mSceneNormal); DeleteRenderBuffer(mSceneDepthStencil); } } @@ -264,16 +266,17 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool need { mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false); mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false); - mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false); - mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, mSceneDepthStencil, true); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneData, mSceneDepthStencil, true); + mSceneFog = Create2DMultisampleTexture("SceneFog", GL_RGBA8, width, height, samples, false); + mSceneNormal = Create2DMultisampleTexture("SceneNormal", GL_RGB10_A2, width, height, samples, false); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, 0, 0, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneFog, mSceneNormal, mSceneDepthStencil, true); } else { mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, width, height, samples); mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples); mSceneFB = CreateFrameBuffer("SceneFB", mSceneMultisample, mSceneDepthStencil, true); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mSceneMultisample, mSceneDepthStencil, true); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mSceneMultisample, mSceneDepthStencil, true); } } else @@ -281,15 +284,16 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples, bool need if (needsSceneTextures) { mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); - mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height); - mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, mSceneDepthStencil, false); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneData, mSceneDepthStencil, false); + mSceneFog = Create2DTexture("SceneFog", GL_RGBA8, width, height); + mSceneNormal = Create2DTexture("SceneNormal", GL_RGB10_A2, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], 0, 0, mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneFog, mSceneNormal, mSceneDepthStencil, false); } else { mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mSceneDepthStencil, false); - mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", mPipelineTexture[0], mSceneDepthStencil, false); + mSceneDataFB = CreateFrameBuffer("SceneGBufferFB", mPipelineTexture[0], mSceneDepthStencil, false); } } } @@ -471,6 +475,7 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break; case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break; case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break; @@ -560,7 +565,7 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample) { GLuint handle = 0; glGenFramebuffers(1, &handle); @@ -571,6 +576,8 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0, 0); if (colorbuffer1 != 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1, 0); + if (colorbuffer2 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer2, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil, 0); } else @@ -578,6 +585,8 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0, 0); if (colorbuffer1 != 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1, 0); + if (colorbuffer2 != 0) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorbuffer2, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0); } if (CheckFrameBufferCompleteness()) @@ -742,17 +751,32 @@ void FGLRenderBuffers::BindSceneColorTexture(int index) //========================================================================== // -// Binds the scene data texture to the specified texture unit +// Binds the scene fog data texture to the specified texture unit // //========================================================================== -void FGLRenderBuffers::BindSceneDataTexture(int index) +void FGLRenderBuffers::BindSceneFogTexture(int index) { glActiveTexture(GL_TEXTURE0 + index); if (mSamples > 1) - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneData); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneFog); else - glBindTexture(GL_TEXTURE_2D, mSceneData); + glBindTexture(GL_TEXTURE_2D, mSceneFog); +} + +//========================================================================== +// +// Binds the scene normal data texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneNormalTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if (mSamples > 1) + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneNormal); + else + glBindTexture(GL_TEXTURE_2D, mSceneNormal); } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 3fcc2c07ba..9508f7009d 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -34,7 +34,8 @@ public: void BindSceneFB(bool sceneData); void BindSceneColorTexture(int index); - void BindSceneDataTexture(int index); + void BindSceneFogTexture(int index); + void BindSceneNormalTexture(int index); void BindSceneDepthTexture(int index); void BlitSceneToTexture(); @@ -93,7 +94,7 @@ private: GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); - GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); void DeleteTexture(GLuint &handle); @@ -113,7 +114,8 @@ private: // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 0; - GLuint mSceneData = 0; + GLuint mSceneFog = 0; + GLuint mSceneNormal = 0; GLuint mSceneFB = 0; GLuint mSceneDataFB = 0; bool mSceneUsesTextures = false; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b6120f9400..13b210d91c 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -160,8 +160,8 @@ void FGLRenderer::Set3DViewport(bool mainview) { bool useSSAO = (gl_ssao != 0); mBuffers->BindSceneFB(useSSAO); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(useSSAO ? 2 : 1, buffers); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(useSSAO ? 3 : 1, buffers); gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); gl_RenderState.Apply(); } @@ -507,8 +507,8 @@ void FGLRenderer::DrawScene(int drawmode) // If SSAO is active, switch to gbuffer shaders and use the framebuffer with gbuffers if (applySSAO) { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(2, buffers); + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(3, buffers); gl_RenderState.SetPassType(GBUFFER_PASS); gl_RenderState.Apply(); gl_RenderState.ApplyMatrices(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 43adb5c0eb..6348d24cd3 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -31,54 +31,65 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_ambientshader.h" -void FLinearDepthShader::Bind(bool multisample) +void FLinearDepthShader::Bind() { - auto &shader = mShader[multisample]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/lineardepth"); - shader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture[multisample].Init(shader, "DepthTexture"); - ColorTexture[multisample].Init(shader, "ColorTexture"); - SampleCount[multisample].Init(shader, "SampleCount"); - LinearizeDepthA[multisample].Init(shader, "LinearizeDepthA"); - LinearizeDepthB[multisample].Init(shader, "LinearizeDepthB"); - InverseDepthRangeA[multisample].Init(shader, "InverseDepthRangeA"); - InverseDepthRangeB[multisample].Init(shader, "InverseDepthRangeB"); - Scale[multisample].Init(shader, "Scale"); - Offset[multisample].Init(shader, "Offset"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/lineardepth"); + mShader->SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(*mShader, "DepthTexture"); + ColorTexture.Init(*mShader, "ColorTexture"); + SampleCount.Init(*mShader, "SampleCount"); + LinearizeDepthA.Init(*mShader, "LinearizeDepthA"); + LinearizeDepthB.Init(*mShader, "LinearizeDepthB"); + InverseDepthRangeA.Init(*mShader, "InverseDepthRangeA"); + InverseDepthRangeB.Init(*mShader, "InverseDepthRangeB"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } void FSSAOShader::Bind() { - auto &shader = mShader[gl_ssao]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mCurrentQuality != gl_ssao || mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao), 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/ssao"); - shader.SetAttribLocation(0, "PositionInProjection"); - DepthTexture.Init(shader, "DepthTexture"); - RandomTexture.Init(shader, "RandomTexture"); - UVToViewA.Init(shader, "UVToViewA"); - UVToViewB.Init(shader, "UVToViewB"); - InvFullResolution.Init(shader, "InvFullResolution"); - NDotVBias.Init(shader, "NDotVBias"); - NegInvR2.Init(shader, "NegInvR2"); - RadiusToScreen.Init(shader, "RadiusToScreen"); - AOMultiplier.Init(shader, "AOMultiplier"); - AOStrength.Init(shader, "AOStrength"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", GetDefines(gl_ssao, multisample), 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/ssao"); + mShader->SetAttribLocation(0, "PositionInProjection"); + DepthTexture.Init(*mShader, "DepthTexture"); + NormalTexture.Init(*mShader, "NormalTexture"); + RandomTexture.Init(*mShader, "RandomTexture"); + UVToViewA.Init(*mShader, "UVToViewA"); + UVToViewB.Init(*mShader, "UVToViewB"); + InvFullResolution.Init(*mShader, "InvFullResolution"); + NDotVBias.Init(*mShader, "NDotVBias"); + NegInvR2.Init(*mShader, "NegInvR2"); + RadiusToScreen.Init(*mShader, "RadiusToScreen"); + AOMultiplier.Init(*mShader, "AOMultiplier"); + AOStrength.Init(*mShader, "AOStrength"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } -FString FSSAOShader::GetDefines(int mode) +FString FSSAOShader::GetDefines(int mode, bool multisample) { int numDirections, numSteps; switch (gl_ssao) @@ -96,6 +107,9 @@ FString FSSAOShader::GetDefines(int mode) #define NUM_DIRECTIONS %d.0 #define NUM_STEPS %d.0 )", numDirections, numSteps); + + if (multisample) + defines += "\n#define MULTISAMPLE\n"; return defines; } @@ -117,21 +131,26 @@ void FDepthBlurShader::Bind(bool vertical) shader.Bind(); } -void FSSAOCombineShader::Bind(bool multisample) +void FSSAOCombineShader::Bind() { - auto &shader = mShader[multisample]; - if (!shader) + bool multisample = (gl_multisample > 1); + if (mMultisample != multisample) + mShader.reset(); + + if (!mShader) { - shader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - shader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); - shader.SetFragDataLocation(0, "FragColor"); - shader.Link("shaders/glsl/ssaocombine"); - shader.SetAttribLocation(0, "PositionInProjection"); - AODepthTexture[multisample].Init(shader, "AODepthTexture"); - SceneDataTexture[multisample].Init(shader, "SceneDataTexture"); - SampleCount[multisample].Init(shader, "SampleCount"); - Scale[multisample].Init(shader, "Scale"); - Offset[multisample].Init(shader, "Offset"); + mShader = std::make_unique(); + mShader->Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader->Compile(FShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", multisample ? "#define MULTISAMPLE\n" : "", 330); + mShader->SetFragDataLocation(0, "FragColor"); + mShader->Link("shaders/glsl/ssaocombine"); + mShader->SetAttribLocation(0, "PositionInProjection"); + AODepthTexture.Init(*mShader, "AODepthTexture"); + SceneFogTexture.Init(*mShader, "SceneFogTexture"); + SampleCount.Init(*mShader, "SampleCount"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); + mMultisample = multisample; } - shader.Bind(); + mShader->Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 704729b246..5c68892c3d 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -6,20 +6,21 @@ class FLinearDepthShader { public: - void Bind(bool multisample); + void Bind(); - FBufferedUniformSampler DepthTexture[2]; - FBufferedUniformSampler ColorTexture[2]; - FBufferedUniform1i SampleCount[2]; - FBufferedUniform1f LinearizeDepthA[2]; - FBufferedUniform1f LinearizeDepthB[2]; - FBufferedUniform1f InverseDepthRangeA[2]; - FBufferedUniform1f InverseDepthRangeB[2]; - FBufferedUniform2f Scale[2]; - FBufferedUniform2f Offset[2]; + FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler ColorTexture; + FBufferedUniform1i SampleCount; + FBufferedUniform1f LinearizeDepthA; + FBufferedUniform1f LinearizeDepthB; + FBufferedUniform1f InverseDepthRangeA; + FBufferedUniform1f InverseDepthRangeB; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: - FShaderProgram mShader[2]; + std::unique_ptr mShader; + bool mMultisample = false; }; class FSSAOShader @@ -28,6 +29,7 @@ public: void Bind(); FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler NormalTexture; FBufferedUniformSampler RandomTexture; FBufferedUniform2f UVToViewA; FBufferedUniform2f UVToViewB; @@ -48,9 +50,11 @@ private: NumQualityModes }; - FString GetDefines(int mode); + FString GetDefines(int mode, bool multisample); - FShaderProgram mShader[NumQualityModes]; + std::unique_ptr mShader; + Quality mCurrentQuality = Off; + bool mMultisample = false; }; class FDepthBlurShader @@ -70,16 +74,17 @@ private: class FSSAOCombineShader { public: - void Bind(bool multisample); + void Bind(); - FBufferedUniformSampler AODepthTexture[2]; - FBufferedUniformSampler SceneDataTexture[2]; - FBufferedUniform1i SampleCount[2]; - FBufferedUniform2f Scale[2]; - FBufferedUniform2f Offset[2]; + FBufferedUniformSampler AODepthTexture; + FBufferedUniformSampler SceneFogTexture; + FBufferedUniform1i SampleCount; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: - FShaderProgram mShader[2]; + std::unique_ptr mShader; + bool mMultisample = false; }; #endif \ No newline at end of file diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 9cbd69ce22..b7d8335f82 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -182,7 +182,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * glBindAttribLocation(hShader, VATTR_NORMAL, "aNormal"); glBindFragDataLocation(hShader, 0, "FragColor"); - glBindFragDataLocation(hShader, 1, "FragData"); + glBindFragDataLocation(hShader, 1, "FragFog"); + glBindFragDataLocation(hShader, 2, "FragNormal"); glLinkProgram(hShader); diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 836787117d..3b425d2613 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -53,7 +53,7 @@ EXTERN_CVAR(Float, gl_lens_chromatic) EXTERN_CVAR(Int, gl_ssao) EXTERN_CVAR(Int, gl_ssao_portals) EXTERN_CVAR(Float, gl_ssao_strength) -EXTERN_CVAR(Bool, gl_ssao_debug) +EXTERN_CVAR(Int, gl_ssao_debug) EXTERN_CVAR(Float, gl_ssao_bias) EXTERN_CVAR(Float, gl_ssao_radius) EXTERN_CVAR(Float, gl_ssao_blur_amount) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 1f270728df..e26b2fd4a3 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -8,7 +8,8 @@ in vec4 vColor; out vec4 FragColor; #ifdef GBUFFER_PASS -out vec4 FragData; +out vec4 FragFog; +out vec4 FragNormal; #endif #ifdef SHADER_STORAGE_LIGHTS @@ -408,7 +409,8 @@ void main() } FragColor = frag; #ifdef GBUFFER_PASS - FragData = vec4(AmbientOcclusionColor(), 1.0); + FragFog = vec4(AmbientOcclusionColor(), 1.0); + FragNormal = vec4(vEyeNormal.xyz * 0.5 + 0.5, 1.0); #endif } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index e0d972c579..758f7dbaa1 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -15,6 +15,12 @@ uniform float AOStrength; uniform sampler2D DepthTexture; +#if defined(MULTISAMPLE) +uniform sampler2DMS NormalTexture; +#else +uniform sampler2D NormalTexture; +#endif + #if defined(USE_RANDOM_TEXTURE) uniform sampler2D RandomTexture; #endif @@ -28,6 +34,20 @@ vec3 FetchViewPos(vec2 uv) return vec3((UVToViewA * uv + UVToViewB) * z, z); } +#if defined(MULTISAMPLE) +vec3 FetchNormal(vec2 uv) +{ + ivec2 texSize = textureSize(NormalTexture); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return normalize(texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0); +} +#else +vec3 FetchNormal(vec2 uv) +{ + return normalize(texture(NormalTexture, uv).xyz * 2.0 - 1.0); +} +#endif + vec3 MinDiff(vec3 p, vec3 pr, vec3 pl) { vec3 v1 = pr - p; @@ -106,7 +126,8 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { vec3 viewPosition = FetchViewPos(TexCoord); - vec3 viewNormal = ReconstructNormal(viewPosition); + //vec3 viewNormal = ReconstructNormal(viewPosition); + vec3 viewNormal = FetchNormal(TexCoord); float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp index 7cd0962763..377516587b 100644 --- a/wadsrc/static/shaders/glsl/ssaocombine.fp +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -5,10 +5,10 @@ out vec4 FragColor; uniform sampler2D AODepthTexture; #if defined(MULTISAMPLE) -uniform sampler2DMS SceneDataTexture; +uniform sampler2DMS SceneFogTexture; uniform int SampleCount; #else -uniform sampler2D SceneDataTexture; +uniform sampler2D SceneFogTexture; #endif uniform vec2 Scale; @@ -18,19 +18,19 @@ void main() { vec2 uv = Offset + TexCoord * Scale; #if defined(MULTISAMPLE) - ivec2 texSize = textureSize(SceneDataTexture); + ivec2 texSize = textureSize(SceneFogTexture); #else - ivec2 texSize = textureSize(SceneDataTexture, 0); + ivec2 texSize = textureSize(SceneFogTexture, 0); #endif ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); #if defined(MULTISAMPLE) vec3 fogColor = vec3(0.0); for (int i = 0; i < SampleCount; i++) - fogColor += texelFetch(SceneDataTexture, ipos, i).rgb; + fogColor += texelFetch(SceneFogTexture, ipos, i).rgb; fogColor /= float(SampleCount); #else - vec3 fogColor = texelFetch(SceneDataTexture, ipos, 0).rgb; + vec3 fogColor = texelFetch(SceneFogTexture, ipos, 0).rgb; #endif float attenutation = texture(AODepthTexture, TexCoord).x; From bb79dcb6349c694e441a875b5ff015de127da065 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 6 Oct 2016 07:36:49 +0200 Subject: [PATCH 22/29] SSAO math bug fixes --- src/gl/renderer/gl_postprocess.cpp | 65 +++++++++++++---------- src/gl/renderer/gl_renderbuffers.cpp | 44 +++++++++------ src/gl/renderer/gl_renderbuffers.h | 3 +- src/gl/shaders/gl_ambientshader.cpp | 3 ++ src/gl/shaders/gl_ambientshader.h | 2 + wadsrc/static/shaders/glsl/depthblur.fp | 2 +- wadsrc/static/shaders/glsl/lineardepth.fp | 33 ++++++++---- wadsrc/static/shaders/glsl/ssao.fp | 56 ++++++++++--------- 8 files changed, 125 insertions(+), 83 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index ac5a6336d3..97e2c3be9c 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -124,7 +124,7 @@ CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_ssao_debug, 0, 0) CVAR(Float, gl_ssao_bias, 0.5f, 0) CVAR(Float, gl_ssao_radius, 100.0f, 0) -CUSTOM_CVAR(Float, gl_ssao_blur_amount, 4.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur_amount, 16.0f, 0) { if (self < 0.1f) self = 0.1f; } @@ -178,6 +178,13 @@ void FGLRenderer::AmbientOccludeScene() float blurSharpness = 1.0f / blurAmount; + float sceneScaleX = mSceneViewport.width / (float)mScreenViewport.width; + float sceneScaleY = mSceneViewport.height / (float)mScreenViewport.height; + float sceneOffsetX = mSceneViewport.left / (float)mScreenViewport.width; + float sceneOffsetY = mSceneViewport.top / (float)mScreenViewport.height; + + int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1); + // Calculate linear depth values glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); @@ -196,8 +203,8 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA.Set(1.0f); mLinearDepthShader->InverseDepthRangeB.Set(0.0f); - mLinearDepthShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mLinearDepthShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mLinearDepthShader->Scale.Set(sceneScaleX, sceneScaleY); + mLinearDepthShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); // Apply ambient occlusion @@ -206,7 +213,7 @@ void FGLRenderer::AmbientOccludeScene() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientRandomTexture[randomTexture]); 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_REPEAT); @@ -219,44 +226,46 @@ void FGLRenderer::AmbientOccludeScene() mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); mSSAOShader->NormalTexture.Set(2); - mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY); - mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY); + mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, 2.0f * invFocalLenY); + mSSAOShader->UVToViewB.Set(-invFocalLenX, -invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); mSSAOShader->NDotVBias.Set(nDotVBias); mSSAOShader->NegInvR2.Set(-1.0f / r2); mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight); mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias)); mSSAOShader->AOStrength.Set(aoStrength); + mSSAOShader->Scale.Set(sceneScaleX, sceneScaleY); + mSSAOShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); // Blur SSAO texture - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - mDepthBlurShader->Bind(false); - mDepthBlurShader->BlurSharpness[false].Set(blurSharpness); - mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - RenderScreenQuad(); + if (gl_ssao_debug < 2) + { + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + mDepthBlurShader->Bind(false); + mDepthBlurShader->BlurSharpness[false].Set(blurSharpness); + mDepthBlurShader->InvFullResolution[false].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + RenderScreenQuad(); - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); - mDepthBlurShader->Bind(true); - mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); - mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - mDepthBlurShader->PowExponent[true].Set(1.8f); - RenderScreenQuad(); + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); + glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + mDepthBlurShader->Bind(true); + mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); + mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); + mDepthBlurShader->PowExponent[true].Set(1.8f); + RenderScreenQuad(); + } // Add SSAO back to scene texture: mBuffers->BindSceneFB(false); glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - if (gl_ssao_debug > 1) - glBlendFunc(GL_ONE, GL_ZERO); - else - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (gl_ssao_debug == 1) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (gl_ssao_debug != 0) { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -270,8 +279,8 @@ void FGLRenderer::AmbientOccludeScene() mSSAOCombineShader->AODepthTexture.Set(0); mSSAOCombineShader->SceneFogTexture.Set(1); if (gl_multisample > 1) mSSAOCombineShader->SampleCount.Set(gl_multisample); - mSSAOCombineShader->Scale.Set(mBuffers->AmbientWidth * 2.0f / (float)mScreenViewport.width, mBuffers->AmbientHeight * 2.0f / (float)mScreenViewport.height); - mSSAOCombineShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + mSSAOCombineShader->Scale.Set(sceneScaleX, sceneScaleY); + mSSAOCombineShader->Offset.Set(sceneOffsetX, sceneOffsetY); RenderScreenQuad(); FGLDebug::PopGroup(); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 1a1509d7a6..a24596562e 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -59,6 +59,11 @@ FGLRenderBuffers::FGLRenderBuffers() mPipelineFB[i] = 0; } + for (int i = 0; i < NumAmbientRandomTextures; i++) + { + AmbientRandomTexture[i] = 0; + } + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&mOutputFB); glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); } @@ -151,7 +156,8 @@ void FGLRenderBuffers::ClearAmbientOcclusion() DeleteFrameBuffer(AmbientFB1); DeleteTexture(AmbientTexture0); DeleteTexture(AmbientTexture1); - DeleteTexture(AmbientRandomTexture); + for (int i = 0; i < NumAmbientRandomTextures; i++) + DeleteTexture(AmbientRandomTexture[i]); } void FGLRenderBuffers::DeleteTexture(GLuint &handle) @@ -368,25 +374,31 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); - int16_t randomValues[16 * 4]; + // Must match quality enum in FSSAOShader::GetDefines + double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 }; + std::mt19937 generator(1337); - std::uniform_real_distribution distribution(-1.0, 1.0); - for (int i = 0; i < 16; i++) + std::uniform_real_distribution distribution(0.0, 1.0); + for (int quality = 0; quality < NumAmbientRandomTextures; quality++) { - double num_directions = 8.0; // Must be same as the define in ssao.fp - double angle = 2.0 * M_PI * distribution(generator) / num_directions; - double x = cos(angle); - double y = sin(angle); - double z = distribution(generator); - double w = distribution(generator); + int16_t randomValues[16 * 4]; - randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0); - randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0); + for (int i = 0; i < 16; i++) + { + double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality]; + double x = cos(angle); + double y = sin(angle); + double z = distribution(generator); + double w = distribution(generator); + + randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0); + randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0); + } + + AmbientRandomTexture[quality] = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); } - - AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 9508f7009d..d593b02486 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -65,7 +65,8 @@ public: GLuint AmbientFB1 = 0; int AmbientWidth = 0; int AmbientHeight = 0; - GLuint AmbientRandomTexture = 0; + enum { NumAmbientRandomTextures = 3 }; + GLuint AmbientRandomTexture[NumAmbientRandomTextures]; static bool IsEnabled(); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 6348d24cd3..0d08e12587 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -84,6 +84,8 @@ void FSSAOShader::Bind() RadiusToScreen.Init(*mShader, "RadiusToScreen"); AOMultiplier.Init(*mShader, "AOMultiplier"); AOStrength.Init(*mShader, "AOStrength"); + Scale.Init(*mShader, "Scale"); + Offset.Init(*mShader, "Offset"); mMultisample = multisample; } mShader->Bind(); @@ -91,6 +93,7 @@ void FSSAOShader::Bind() FString FSSAOShader::GetDefines(int mode, bool multisample) { + // Must match quality values in FGLRenderBuffers::CreateAmbientOcclusion int numDirections, numSteps; switch (gl_ssao) { diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 5c68892c3d..95dfd6bace 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -39,6 +39,8 @@ public: FBufferedUniform1f RadiusToScreen; FBufferedUniform1f AOMultiplier; FBufferedUniform1f AOStrength; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; private: enum Quality diff --git a/wadsrc/static/shaders/glsl/depthblur.fp b/wadsrc/static/shaders/glsl/depthblur.fp index c4f4438d30..7e3dad0742 100644 --- a/wadsrc/static/shaders/glsl/depthblur.fp +++ b/wadsrc/static/shaders/glsl/depthblur.fp @@ -7,7 +7,7 @@ uniform float BlurSharpness; uniform vec2 InvFullResolution; uniform float PowExponent; -#define KERNEL_RADIUS 7.0 +#define KERNEL_RADIUS 3.0 float CrossBilateralWeight(float r, float sampleDepth, float centerDepth) { diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index 558738bd9f..fa71c9de0a 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -18,6 +18,12 @@ uniform float InverseDepthRangeB; uniform vec2 Scale; uniform vec2 Offset; +float normalizeDepth(float depth) +{ + float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); + return 1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB); +} + void main() { vec2 uv = Offset + TexCoord * Scale; @@ -28,19 +34,24 @@ void main() ivec2 texSize = textureSize(DepthTexture, 0); #endif - // Use floor here because as we downscale the sampling error has to remain uniform to prevent - // noise in the depth values. - ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0))); #if defined(MULTISAMPLE) - float depth = 0.0; - for (int i = 0; i < SampleCount; i++) - depth += texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; - depth /= float(SampleCount); + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); + float sampleIndex = 0.0; + for (int i = 1; i < SampleCount; i++) + { + float hardwareDepth = texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; + float sampleDepth = normalizeDepth(hardwareDepth); + if (sampleDepth < depth) + { + depth = sampleDepth; + sampleIndex = float(i); + } + } + FragColor = vec4(depth, sampleIndex, 0.0, 1.0); #else - float depth = texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0; + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); + FragColor = vec4(depth, 0.0, 0.0, 1.0); #endif - - float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0); - FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index 758f7dbaa1..f895ddc255 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -13,6 +13,9 @@ uniform float AOMultiplier; uniform float AOStrength; +uniform vec2 Scale; +uniform vec2 Offset; + uniform sampler2D DepthTexture; #if defined(MULTISAMPLE) @@ -27,42 +30,42 @@ uniform sampler2D RandomTexture; #define PI 3.14159265358979323846 -// Calculate eye space position for the specified texture coordinate -vec3 FetchViewPos(vec2 uv) +// Calculate eye space position for the specified texture coordinate and depth +vec3 FetchViewPos(vec2 uv, float z) { - float z = texture(DepthTexture, uv).x; return vec3((UVToViewA * uv + UVToViewB) * z, z); } #if defined(MULTISAMPLE) -vec3 FetchNormal(vec2 uv) +vec3 SampleNormal(vec2 uv, float samplerIndex) { ivec2 texSize = textureSize(NormalTexture); ivec2 ipos = ivec2(uv * vec2(texSize)); - return normalize(texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0); + return texelFetch(NormalTexture, ipos, int(samplerIndex)).xyz * 2.0 - 1.0; } #else -vec3 FetchNormal(vec2 uv) +vec3 SampleNormal(vec2 uv, float samplerIndex) { - return normalize(texture(NormalTexture, uv).xyz * 2.0 - 1.0); + ivec2 texSize = textureSize(NormalTexture, 0); + ivec2 ipos = ivec2(uv * vec2(texSize)); + return texelFetch(NormalTexture, ipos, 0).xyz * 2.0 - 1.0; } #endif -vec3 MinDiff(vec3 p, vec3 pr, vec3 pl) +// Look up the eye space normal for the specified texture coordinate +vec3 FetchNormal(vec2 uv, float samplerIndex) { - vec3 v1 = pr - p; - vec3 v2 = p - pl; - return (dot(v1, v1) < dot(v2, v2)) ? v1 : v2; -} - -// Reconstruct eye space normal from nearest neighbors -vec3 ReconstructNormal(vec3 p) -{ - vec3 pr = FetchViewPos(TexCoord + vec2(InvFullResolution.x, 0)); - vec3 pl = FetchViewPos(TexCoord + vec2(-InvFullResolution.x, 0)); - vec3 pt = FetchViewPos(TexCoord + vec2(0, InvFullResolution.y)); - vec3 pb = FetchViewPos(TexCoord + vec2(0, -InvFullResolution.y)); - return normalize(cross(MinDiff(p, pr, pl), MinDiff(p, pt, pb))); + vec3 normal = SampleNormal(Offset + uv * Scale, samplerIndex); + if (length(normal) > 0.1) + { + normal = normalize(normal); + normal.z = -normal.z; + return normal; + } + else + { + return vec3(0.0); + } } // Compute normalized 2D direction @@ -113,7 +116,7 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) { vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; - vec3 samplePos = FetchViewPos(sampleUV); + vec3 samplePos = FetchViewPos(sampleUV, texture(DepthTexture, sampleUV).x); ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); rayPixels += stepSizePixels; } @@ -125,9 +128,10 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { - vec3 viewPosition = FetchViewPos(TexCoord); - //vec3 viewNormal = ReconstructNormal(viewPosition); - vec3 viewNormal = FetchNormal(TexCoord); - float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); + vec2 depthData = texture(DepthTexture, TexCoord).xy; + vec3 viewPosition = FetchViewPos(TexCoord, depthData.x); + vec3 viewNormal = FetchNormal(TexCoord, depthData.y); + float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0; + FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); } From 1b7c42f45f9c9bf524d065505a758c023560a172 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 9 Oct 2016 06:17:48 +0200 Subject: [PATCH 23/29] Multisampling ssao bug fixes and split linear depth to its own buffer --- src/gl/renderer/gl_postprocess.cpp | 22 ++++++++++++------- src/gl/renderer/gl_renderbuffers.cpp | 26 ++++++++++++++--------- src/gl/renderer/gl_renderbuffers.h | 4 +++- src/gl/shaders/gl_ambientshader.cpp | 3 ++- src/gl/shaders/gl_ambientshader.h | 3 ++- wadsrc/static/shaders/glsl/lineardepth.fp | 19 ++++------------- wadsrc/static/shaders/glsl/ssao.fp | 23 ++++++++++---------- wadsrc/static/shaders/glsl/ssaocombine.fp | 3 ++- 8 files changed, 55 insertions(+), 48 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 97e2c3be9c..dd8bccc8b9 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -122,9 +122,14 @@ CUSTOM_CVAR(Int, gl_ssao_portals, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Float, gl_ssao_strength, 0.7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_ssao_debug, 0, 0) -CVAR(Float, gl_ssao_bias, 0.5f, 0) -CVAR(Float, gl_ssao_radius, 100.0f, 0) -CUSTOM_CVAR(Float, gl_ssao_blur_amount, 16.0f, 0) +CVAR(Float, gl_ssao_bias, 0.2f, 0) +CVAR(Float, gl_ssao_radius, 80.0f, 0) +CUSTOM_CVAR(Float, gl_ssao_blur, 16.0f, 0) +{ + if (self < 0.1f) self = 0.1f; +} + +CUSTOM_CVAR(Float, gl_ssao_exponent, 1.8f, 0) { if (self < 0.1f) self = 0.1f; } @@ -166,7 +171,7 @@ void FGLRenderer::AmbientOccludeScene() float bias = gl_ssao_bias; float aoRadius = gl_ssao_radius; - const float blurAmount = gl_ssao_blur_amount; + const float blurAmount = gl_ssao_blur; float aoStrength = gl_ssao_strength; //float tanHalfFovy = tan(fovy * (M_PI / 360.0f)); @@ -186,7 +191,7 @@ void FGLRenderer::AmbientOccludeScene() int randomTexture = clamp(gl_ssao - 1, 0, FGLRenderBuffers::NumAmbientRandomTextures - 1); // Calculate linear depth values - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0); + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->LinearDepthFB); glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight); mBuffers->BindSceneDepthTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -198,7 +203,7 @@ void FGLRenderer::AmbientOccludeScene() mLinearDepthShader->Bind(); mLinearDepthShader->DepthTexture.Set(0); mLinearDepthShader->ColorTexture.Set(1); - if (gl_multisample > 1) mLinearDepthShader->SampleCount.Set(gl_multisample); + if (gl_multisample > 1) mLinearDepthShader->SampleIndex.Set(0); mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear()); mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f)); mLinearDepthShader->InverseDepthRangeA.Set(1.0f); @@ -209,7 +214,7 @@ void FGLRenderer::AmbientOccludeScene() // Apply ambient occlusion glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1); - glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0); + glBindTexture(GL_TEXTURE_2D, mBuffers->LinearDepthTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE1); @@ -226,6 +231,7 @@ void FGLRenderer::AmbientOccludeScene() mSSAOShader->DepthTexture.Set(0); mSSAOShader->RandomTexture.Set(1); mSSAOShader->NormalTexture.Set(2); + if (gl_multisample > 1) mSSAOShader->SampleIndex.Set(0); mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, 2.0f * invFocalLenY); mSSAOShader->UVToViewB.Set(-invFocalLenX, -invFocalLenY); mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); @@ -255,7 +261,7 @@ void FGLRenderer::AmbientOccludeScene() mDepthBlurShader->Bind(true); mDepthBlurShader->BlurSharpness[true].Set(blurSharpness); mDepthBlurShader->InvFullResolution[true].Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight); - mDepthBlurShader->PowExponent[true].Set(1.8f); + mDepthBlurShader->PowExponent[true].Set(gl_ssao_exponent); RenderScreenQuad(); } diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index a24596562e..b14ee98525 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -152,8 +152,10 @@ void FGLRenderBuffers::ClearEyeBuffers() void FGLRenderBuffers::ClearAmbientOcclusion() { + DeleteFrameBuffer(LinearDepthFB); DeleteFrameBuffer(AmbientFB0); DeleteFrameBuffer(AmbientFB1); + DeleteTexture(LinearDepthTexture); DeleteTexture(AmbientTexture0); DeleteTexture(AmbientTexture1); for (int i = 0; i < NumAmbientRandomTextures; i++) @@ -336,13 +338,13 @@ void FGLRenderBuffers::CreateBloom(int width, int height) if (width <= 0 || height <= 0) return; - int bloomWidth = MAX(width / 2, 1); - int bloomHeight = MAX(height / 2, 1); + int bloomWidth = (width + 1) / 2; + int bloomHeight = (height + 1) / 2; for (int i = 0; i < NumBloomLevels; i++) { auto &level = BloomLevels[i]; - level.Width = MAX(bloomWidth / 2, 1); - level.Height = MAX(bloomHeight / 2, 1); + level.Width = (bloomWidth + 1) / 2; + level.Height = (bloomHeight + 1) / 2; level.VTexture = Create2DTexture("Bloom.VTexture", GL_RGBA16F, level.Width, level.Height); level.HTexture = Create2DTexture("Bloom.HTexture", GL_RGBA16F, level.Width, level.Height); @@ -367,10 +369,12 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) if (width <= 0 || height <= 0) return; - AmbientWidth = width / 2; - AmbientHeight = height / 2; - AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG32F, AmbientWidth, AmbientHeight); - AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG32F, AmbientWidth, AmbientHeight); + AmbientWidth = (width + 1) / 2; + AmbientHeight = (height + 1) / 2; + LinearDepthTexture = Create2DTexture("LinearDepthTexture", GL_R32F, AmbientWidth, AmbientHeight); + AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG16F, AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG16F, AmbientWidth, AmbientHeight); + LinearDepthFB = CreateFrameBuffer("LinearDepthFB", LinearDepthTexture); AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); @@ -485,13 +489,15 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break; case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; case GL_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break; + case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break; + case GL_R16F: dataformat = GL_RED; datatype = GL_FLOAT; break; case GL_RG32F: dataformat = GL_RG; datatype = GL_FLOAT; break; + case GL_RG16F: dataformat = GL_RG; datatype = GL_FLOAT; break; case GL_RGB10_A2: dataformat = GL_RGBA; datatype = GL_UNSIGNED_INT_10_10_10_2; break; case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break; case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break; case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break; - case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break; default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture"); } @@ -530,7 +536,7 @@ GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, return handle; } -GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height) +GLuint FGLRenderBuffers::CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples) { if (samples <= 1) return CreateRenderBuffer(name, format, width, height); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index d593b02486..efa61f3e21 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -59,6 +59,8 @@ public: bool FirstExposureFrame = true; // Ambient occlusion buffers + GLuint LinearDepthTexture = 0; + GLuint LinearDepthFB = 0; GLuint AmbientTexture0 = 0; GLuint AmbientTexture1 = 0; GLuint AmbientFB0 = 0; @@ -92,7 +94,7 @@ private: GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr); GLuint Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations); GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height); - GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height); + GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height, int samples); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer); GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint colorbuffer2, GLuint depthstencil, bool multisample); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 0d08e12587..effde24964 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -47,7 +47,7 @@ void FLinearDepthShader::Bind() mShader->SetAttribLocation(0, "PositionInProjection"); DepthTexture.Init(*mShader, "DepthTexture"); ColorTexture.Init(*mShader, "ColorTexture"); - SampleCount.Init(*mShader, "SampleCount"); + SampleIndex.Init(*mShader, "SampleIndex"); LinearizeDepthA.Init(*mShader, "LinearizeDepthA"); LinearizeDepthB.Init(*mShader, "LinearizeDepthB"); InverseDepthRangeA.Init(*mShader, "InverseDepthRangeA"); @@ -86,6 +86,7 @@ void FSSAOShader::Bind() AOStrength.Init(*mShader, "AOStrength"); Scale.Init(*mShader, "Scale"); Offset.Init(*mShader, "Offset"); + SampleIndex.Init(*mShader, "SampleIndex"); mMultisample = multisample; } mShader->Bind(); diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 95dfd6bace..d3310c3d64 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -10,7 +10,7 @@ public: FBufferedUniformSampler DepthTexture; FBufferedUniformSampler ColorTexture; - FBufferedUniform1i SampleCount; + FBufferedUniform1i SampleIndex; FBufferedUniform1f LinearizeDepthA; FBufferedUniform1f LinearizeDepthB; FBufferedUniform1f InverseDepthRangeA; @@ -41,6 +41,7 @@ public: FBufferedUniform1f AOStrength; FBufferedUniform2f Scale; FBufferedUniform2f Offset; + FBufferedUniform1i SampleIndex; private: enum Quality diff --git a/wadsrc/static/shaders/glsl/lineardepth.fp b/wadsrc/static/shaders/glsl/lineardepth.fp index fa71c9de0a..3e2b3eb95b 100644 --- a/wadsrc/static/shaders/glsl/lineardepth.fp +++ b/wadsrc/static/shaders/glsl/lineardepth.fp @@ -5,7 +5,7 @@ out vec4 FragColor; #if defined(MULTISAMPLE) uniform sampler2DMS DepthTexture; uniform sampler2DMS ColorTexture; -uniform int SampleCount; +uniform int SampleIndex; #else uniform sampler2D DepthTexture; uniform sampler2D ColorTexture; @@ -37,21 +37,10 @@ void main() ivec2 ipos = ivec2(max(uv * vec2(texSize), vec2(0.0))); #if defined(MULTISAMPLE) - float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); - float sampleIndex = 0.0; - for (int i = 1; i < SampleCount; i++) - { - float hardwareDepth = texelFetch(ColorTexture, ipos, i).a != 0.0 ? texelFetch(DepthTexture, ipos, i).x : 1.0; - float sampleDepth = normalizeDepth(hardwareDepth); - if (sampleDepth < depth) - { - depth = sampleDepth; - sampleIndex = float(i); - } - } - FragColor = vec4(depth, sampleIndex, 0.0, 1.0); + float depth = normalizeDepth(texelFetch(ColorTexture, ipos, SampleIndex).a != 0.0 ? texelFetch(DepthTexture, ipos, SampleIndex).x : 1.0); #else float depth = normalizeDepth(texelFetch(ColorTexture, ipos, 0).a != 0.0 ? texelFetch(DepthTexture, ipos, 0).x : 1.0); - FragColor = vec4(depth, 0.0, 0.0, 1.0); #endif + + FragColor = vec4(depth, 0.0, 0.0, 1.0); } diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index f895ddc255..3b2db60059 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -20,6 +20,7 @@ uniform sampler2D DepthTexture; #if defined(MULTISAMPLE) uniform sampler2DMS NormalTexture; +uniform int SampleIndex; #else uniform sampler2D NormalTexture; #endif @@ -30,21 +31,22 @@ uniform sampler2D RandomTexture; #define PI 3.14159265358979323846 -// Calculate eye space position for the specified texture coordinate and depth -vec3 FetchViewPos(vec2 uv, float z) +// Calculate eye space position for the specified texture coordinate +vec3 FetchViewPos(vec2 uv) { + float z = texture(DepthTexture, uv).x; return vec3((UVToViewA * uv + UVToViewB) * z, z); } #if defined(MULTISAMPLE) -vec3 SampleNormal(vec2 uv, float samplerIndex) +vec3 SampleNormal(vec2 uv) { ivec2 texSize = textureSize(NormalTexture); ivec2 ipos = ivec2(uv * vec2(texSize)); - return texelFetch(NormalTexture, ipos, int(samplerIndex)).xyz * 2.0 - 1.0; + return texelFetch(NormalTexture, ipos, SampleIndex).xyz * 2.0 - 1.0; } #else -vec3 SampleNormal(vec2 uv, float samplerIndex) +vec3 SampleNormal(vec2 uv) { ivec2 texSize = textureSize(NormalTexture, 0); ivec2 ipos = ivec2(uv * vec2(texSize)); @@ -53,9 +55,9 @@ vec3 SampleNormal(vec2 uv, float samplerIndex) #endif // Look up the eye space normal for the specified texture coordinate -vec3 FetchNormal(vec2 uv, float samplerIndex) +vec3 FetchNormal(vec2 uv) { - vec3 normal = SampleNormal(Offset + uv * Scale, samplerIndex); + vec3 normal = SampleNormal(Offset + uv * Scale); if (length(normal) > 0.1) { normal = normalize(normal); @@ -116,7 +118,7 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex) { vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord; - vec3 samplePos = FetchViewPos(sampleUV, texture(DepthTexture, sampleUV).x); + vec3 samplePos = FetchViewPos(sampleUV); ao += ComputeSampleAO(viewPosition, viewNormal, samplePos); rayPixels += stepSizePixels; } @@ -128,9 +130,8 @@ float ComputeAO(vec3 viewPosition, vec3 viewNormal) void main() { - vec2 depthData = texture(DepthTexture, TexCoord).xy; - vec3 viewPosition = FetchViewPos(TexCoord, depthData.x); - vec3 viewNormal = FetchNormal(TexCoord, depthData.y); + vec3 viewPosition = FetchViewPos(TexCoord); + vec3 viewNormal = FetchNormal(TexCoord); float occlusion = viewNormal != vec3(0.0) ? ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength) : 1.0; FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0); diff --git a/wadsrc/static/shaders/glsl/ssaocombine.fp b/wadsrc/static/shaders/glsl/ssaocombine.fp index 377516587b..4ca64421ba 100644 --- a/wadsrc/static/shaders/glsl/ssaocombine.fp +++ b/wadsrc/static/shaders/glsl/ssaocombine.fp @@ -17,12 +17,13 @@ uniform vec2 Offset; void main() { vec2 uv = Offset + TexCoord * Scale; + #if defined(MULTISAMPLE) ivec2 texSize = textureSize(SceneFogTexture); #else ivec2 texSize = textureSize(SceneFogTexture, 0); #endif - ivec2 ipos = ivec2(max(floor(uv * vec2(texSize) - 0.75), vec2(0.0))); + ivec2 ipos = ivec2(uv * vec2(texSize)); #if defined(MULTISAMPLE) vec3 fogColor = vec3(0.0); From 660a45a0e07882f28b7261b563b593f50f2bd024 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 13 Oct 2016 18:04:00 +0200 Subject: [PATCH 24/29] Add normals to decals --- src/gl/scene/gl_decal.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gl/scene/gl_decal.cpp b/src/gl/scene/gl_decal.cpp index 651cb7aa9d..7fb680f8e0 100644 --- a/src/gl/scene/gl_decal.cpp +++ b/src/gl/scene/gl_decal.cpp @@ -316,6 +316,8 @@ void GLWall::DrawDecal(DBaseDecal *decal) gl_RenderState.SetFog(0,-1); } + gl_RenderState.SetNormal(glseg.Normal()); + FQuadDrawer qd; for (i = 0; i < 4; i++) { From 14c1a77f8a0278f5a25d50d61de8f0728145294f Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 13 Oct 2016 18:08:04 +0200 Subject: [PATCH 25/29] Fix AmbientOcclusionColor bug where pixelpos was assumed to be in eye space coordinates --- wadsrc/static/shaders/glsl/main.fp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index e26b2fd4a3..5ab9f11188 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -287,7 +287,7 @@ vec3 AmbientOcclusionColor() } else { - fogdist = max(16.0, length(pixelpos.xyz)); + fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); From e891911a991672c6fff8008b013928648fef793c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 22 Oct 2016 00:09:06 +0200 Subject: [PATCH 26/29] Fix broken SSAO portal rendering and let FRenderState do the glDrawBuffers calls --- src/gl/renderer/gl_renderstate.h | 17 ++++++++++++++ src/gl/scene/gl_scene.cpp | 35 ++++++++--------------------- src/gl/scene/gl_walls_draw.cpp | 2 ++ src/gl/stereo3d/scoped_color_mask.h | 2 ++ 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/gl/renderer/gl_renderstate.h b/src/gl/renderer/gl_renderstate.h index 3276502f12..76e2c791cd 100644 --- a/src/gl/renderer/gl_renderstate.h +++ b/src/gl/renderer/gl_renderstate.h @@ -120,6 +120,7 @@ class FRenderState FShader *activeShader; EPassType mPassType = NORMAL_PASS; + int mNumDrawBuffers = 1; bool ApplyShader(); @@ -491,6 +492,22 @@ public: return mPassType; } + void EnableDrawBuffers(int count) + { + count = MIN(count, 3); + if (mNumDrawBuffers != count) + { + static GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(count, buffers); + mNumDrawBuffers = count; + } + } + + int GetPassDrawBufferCount() + { + return mPassType == GBUFFER_PASS ? 3 : 1; + } + // Backwards compatibility crap follows void ApplyFixedFunction(); void DrawColormapOverlay(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 13eb254ce2..b1876c5be9 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -160,9 +160,8 @@ void FGLRenderer::Set3DViewport(bool mainview) { bool useSSAO = (gl_ssao != 0); mBuffers->BindSceneFB(useSSAO); - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; - glDrawBuffers(useSSAO ? 3 : 1, buffers); gl_RenderState.SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.Apply(); } @@ -479,6 +478,11 @@ void FGLRenderer::DrawScene(int drawmode) static int recursion=0; static int ssao_portals_available = 0; + if (drawmode == DM_MAINVIEW) + ssao_portals_available = gl_ssao_portals + 1; + else if (drawmode == DM_OFFSCREEN) + ssao_portals_available = 0; + if (camera != nullptr) { ActorRenderFlags savedflags = camera->renderflags; @@ -495,35 +499,14 @@ void FGLRenderer::DrawScene(int drawmode) } GLRenderer->mClipPortal = NULL; // this must be reset before any portal recursion takes place. - // Decide if we need to do ssao for this scene - bool applySSAO = gl_ssao != 0 && FGLRenderBuffers::IsEnabled(); - switch (drawmode) - { - case DM_MAINVIEW: ssao_portals_available = gl_ssao_portals; break; - case DM_OFFSCREEN: ssao_portals_available = 0; applySSAO = false; break; - case DM_PORTAL: applySSAO = applySSAO && (ssao_portals_available > 0); ssao_portals_available--; break; - } - - // If SSAO is active, switch to gbuffer shaders and use the framebuffer with gbuffers - if (applySSAO) - { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; - glDrawBuffers(3, buffers); - gl_RenderState.SetPassType(GBUFFER_PASS); - gl_RenderState.Apply(); - gl_RenderState.ApplyMatrices(); - } - RenderScene(recursion); - // Apply ambient occlusion and switch back to shaders without gbuffer output - if (applySSAO) + if (ssao_portals_available > 0 && gl_RenderState.GetPassType() == GBUFFER_PASS) { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; - glDrawBuffers(1, buffers); + gl_RenderState.EnableDrawBuffers(1); AmbientOccludeScene(); mBuffers->BindSceneFB(true); - gl_RenderState.SetPassType(NORMAL_PASS); + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.Apply(); gl_RenderState.ApplyMatrices(); } diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index dbc43fd22b..480ce4e86d 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -227,6 +227,7 @@ void GLWall::RenderFogBoundary() { int rel = rellight + getExtraLight(); gl_SetFog(lightlevel, rel, &Colormap, false); + gl_RenderState.EnableDrawBuffers(1); gl_RenderState.SetEffect(EFF_FOGBOUNDARY); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); glEnable(GL_POLYGON_OFFSET_FILL); @@ -235,6 +236,7 @@ void GLWall::RenderFogBoundary() glPolygonOffset(0.0f, 0.0f); glDisable(GL_POLYGON_OFFSET_FILL); gl_RenderState.SetEffect(EFF_NONE); + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); } else { diff --git a/src/gl/stereo3d/scoped_color_mask.h b/src/gl/stereo3d/scoped_color_mask.h index 42c02db3a9..e557720921 100644 --- a/src/gl/stereo3d/scoped_color_mask.h +++ b/src/gl/stereo3d/scoped_color_mask.h @@ -41,8 +41,10 @@ public: gl_RenderState.GetColorMask(saved[0], saved[1], saved[2], saved[3]); gl_RenderState.SetColorMask(r, g, b, a); gl_RenderState.ApplyColorMask(); + gl_RenderState.EnableDrawBuffers(1); } ~ScopedColorMask() { + gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.SetColorMask(saved[0], saved[1], saved[2], saved[3]); gl_RenderState.ApplyColorMask(); } From a3e19bf3375616583030d75bb3ef042b2b2b5427 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 22 Oct 2016 21:25:29 +0200 Subject: [PATCH 27/29] Fixed gl_ssao_portals not having effect --- src/gl/scene/gl_scene.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b1876c5be9..c214dfce70 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -509,6 +509,7 @@ void FGLRenderer::DrawScene(int drawmode) gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.Apply(); gl_RenderState.ApplyMatrices(); + ssao_portals_available--; } // Handle all portals after rendering the opaque objects but before From 6c1c0d297216bfeca3c6606d86aaf9bc22180aa7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 22 Oct 2016 21:35:49 +0200 Subject: [PATCH 28/29] Improve scene selection for SSAO so that the mainview drawmode always takes precedence --- src/gl/scene/gl_scene.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index c214dfce70..f052137732 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -478,10 +478,21 @@ void FGLRenderer::DrawScene(int drawmode) static int recursion=0; static int ssao_portals_available = 0; + bool applySSAO = false; if (drawmode == DM_MAINVIEW) - ssao_portals_available = gl_ssao_portals + 1; + { + ssao_portals_available = gl_ssao_portals; + applySSAO = true; + } else if (drawmode == DM_OFFSCREEN) + { ssao_portals_available = 0; + } + else if (ssao_portals_available > 0) + { + applySSAO = true; + ssao_portals_available--; + } if (camera != nullptr) { @@ -501,7 +512,7 @@ void FGLRenderer::DrawScene(int drawmode) RenderScene(recursion); - if (ssao_portals_available > 0 && gl_RenderState.GetPassType() == GBUFFER_PASS) + if (applySSAO && gl_RenderState.GetPassType() == GBUFFER_PASS) { gl_RenderState.EnableDrawBuffers(1); AmbientOccludeScene(); @@ -509,7 +520,6 @@ void FGLRenderer::DrawScene(int drawmode) gl_RenderState.EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount()); gl_RenderState.Apply(); gl_RenderState.ApplyMatrices(); - ssao_portals_available--; } // Handle all portals after rendering the opaque objects but before From bea113a908bd2b695e0d15607cb04065dc2810b7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 28 Nov 2016 02:32:57 +0100 Subject: [PATCH 29/29] Fix tonemap texture filtering (black screen) regression --- src/gl/renderer/gl_postprocess.cpp | 30 ++++++++++++++---------------- src/gl/renderer/gl_renderer.h | 2 +- src/gl/textures/gl_hwtexture.cpp | 5 +++++ src/gl/textures/gl_hwtexture.h | 1 + 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index dd8bccc8b9..f15171c533 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -468,7 +468,10 @@ void FGLRenderer::TonemapScene() FGLDebug::PushGroup("TonemapScene"); + CreateTonemapPalette(); + FGLPostProcessState savedState; + savedState.SaveTextureBindings(2); mBuffers->BindNextFB(); mBuffers->BindCurrentTexture(0); @@ -477,12 +480,18 @@ void FGLRenderer::TonemapScene() if (mTonemapShader->IsPaletteMode()) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mTonemapPalette->GetTextureHandle(0)); + 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); + glActiveTexture(GL_TEXTURE0); + mTonemapShader->PaletteLUT.Set(1); - BindTonemapPalette(1); } else { - savedState.SaveTextureBindings(2); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture); glActiveTexture(GL_TEXTURE0); @@ -496,13 +505,9 @@ void FGLRenderer::TonemapScene() FGLDebug::PopGroup(); } -void FGLRenderer::BindTonemapPalette(int texunit) +void FGLRenderer::CreateTonemapPalette() { - if (mTonemapPalette) - { - mTonemapPalette->Bind(texunit, 0, false); - } - else + if (!mTonemapPalette) { TArray lut; lut.Resize(512 * 512 * 4); @@ -523,14 +528,7 @@ void FGLRenderer::BindTonemapPalette(int texunit) } mTonemapPalette = new FHardwareTexture(512, 512, true); - mTonemapPalette->CreateTexture(&lut[0], 512, 512, texunit, false, 0, "mTonemapPalette"); - - glActiveTexture(GL_TEXTURE0 + texunit); - 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); - glActiveTexture(GL_TEXTURE0); + mTonemapPalette->CreateTexture(&lut[0], 512, 512, 0, false, 0, "mTonemapPalette"); } } diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 7eedd46940..869b46d2d0 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -195,7 +195,7 @@ public: void BloomScene(); void TonemapScene(); void ColormapScene(); - void BindTonemapPalette(int texunit); + void CreateTonemapPalette(); void ClearTonemapPalette(); void LensDistortScene(); void ApplyFXAA(); diff --git a/src/gl/textures/gl_hwtexture.cpp b/src/gl/textures/gl_hwtexture.cpp index edcda4398b..477d1986be 100644 --- a/src/gl/textures/gl_hwtexture.cpp +++ b/src/gl/textures/gl_hwtexture.cpp @@ -374,6 +374,11 @@ unsigned int FHardwareTexture::Bind(int texunit, int translation, bool needmipma return 0; } +unsigned int FHardwareTexture::GetTextureHandle(int translation) +{ + TranslatedTexture *pTex = GetTexID(translation); + return pTex->glTexID; +} void FHardwareTexture::Unbind(int texunit) { diff --git a/src/gl/textures/gl_hwtexture.h b/src/gl/textures/gl_hwtexture.h index 96eff02643..59fc981698 100644 --- a/src/gl/textures/gl_hwtexture.h +++ b/src/gl/textures/gl_hwtexture.h @@ -83,6 +83,7 @@ public: unsigned int Bind(int texunit, int translation, bool needmipmap); unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const FString &name); + unsigned int GetTextureHandle(int translation); void Clean(bool all); void CleanUnused(SpriteHits &usedtranslations);