From 98032bc73f7bbdd3a9f8254f42abd2e8aa717e5a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 2 Sep 2016 05:45:00 +0200 Subject: [PATCH] Change SSAO blur to be depth aware --- src/gl/renderer/gl_postprocess.cpp | 22 ++++-- src/gl/renderer/gl_renderbuffers.cpp | 6 +- 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 +++ 9 files changed, 184 insertions(+), 14 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 684985074..edf1148ef 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -209,8 +209,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(); @@ -225,8 +239,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_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 93625722d..9eb7c6f39 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -313,8 +313,8 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) AmbientWidth = width / 2; AmbientHeight = height / 2; - AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RGBA32F, AmbientWidth, AmbientHeight); - AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RGBA32F, AmbientWidth, AmbientHeight); + AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RG32F, AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG32F, AmbientWidth, AmbientHeight); AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); @@ -370,6 +370,8 @@ 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_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; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 2d32f0d20..ed45ec0f3 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -123,6 +123,10 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mColormapShader = nullptr; mLensShader = nullptr; + mLinearDepthShader = nullptr; + mDepthBlurShader = nullptr; + mSSAOShader = nullptr; + mSSAOCombineShader = nullptr; } void gl_LoadModels(); @@ -132,7 +136,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(); mBlurShader = new FBlurShader(); @@ -194,7 +200,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 (mBlurShader) delete mBlurShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index c487c4a77..8955acfd6 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 FBlurShader; @@ -94,6 +96,8 @@ public: FGLRenderBuffers *mBuffers; FLinearDepthShader *mLinearDepthShader; FSSAOShader *mSSAOShader; + FDepthBlurShader *mDepthBlurShader; + FSSAOCombineShader *mSSAOCombineShader; FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; FBlurShader *mBlurShader; diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 55682a91e..6b8c9cc48 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 fdff178ec..419ca939e 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 000000000..bd464d03d --- /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 f143e913f..e0d972c57 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 000000000..21fdff102 --- /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); +}