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); }