From 9525d3690f64ac06c8f5cb083c122b4bbeaf1cf5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 25 Aug 2016 06:25:05 +0200 Subject: [PATCH 01/19] Added gl_light_math and changed pixelpos + lights to be in eye space --- src/gl/dynlights/gl_dynlight1.cpp | 29 ++++++- src/gl/renderer/gl_renderstate.cpp | 1 + src/gl/shaders/gl_shader.cpp | 1 + src/gl/shaders/gl_shader.h | 1 + src/gl/system/gl_cvars.h | 1 + wadsrc/static/language.enu | 6 +- wadsrc/static/menudef.z | 8 ++ wadsrc/static/shaders/glsl/main.fp | 102 ++++++++++++++++++++++-- wadsrc/static/shaders/glsl/main.vp | 2 +- wadsrc/static/shaders/glsl/shaderdefs.i | 1 + 10 files changed, 140 insertions(+), 12 deletions(-) diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 361b94618..56db94e4d 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -80,6 +80,11 @@ CUSTOM_CVAR (Bool, gl_lights_additive, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG gl_RecreateAllAttachedLights(); } +CUSTOM_CVAR(Int, gl_light_math, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0 || self > 2) self = 0; +} + //========================================================================== // // Sets up the parameters to render one dynamic light onto one plane @@ -128,10 +133,28 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bo i = 1; } + float worldPos[4] = { (float)pos.X, (float)pos.Z, (float)pos.Y, 1.0f }; + float eyePos[4]; + gl_RenderState.mViewMatrix.multMatrixPoint(worldPos, eyePos); + + if (gl_light_math != 0) + { + // Adjust light slightly to make the range better match plain attenuation + radius *= 1.5; + + // Move light up because flasks/vials have their light source location at/below the floor. + // + // If the point is exactly on the wall plane it might cause some acne as some pixels could + // be in front and some behind. Move light just a tiny bit to avoid this. + eyePos[0] += 0.01f; + eyePos[1] += 5.01f; + eyePos[2] += 0.01f; + } + float *data = &ldata.arrays[i][ldata.arrays[i].Reserve(8)]; - data[0] = pos.X; - data[1] = pos.Z; - data[2] = pos.Y; + data[0] = eyePos[0]; + data[1] = eyePos[1]; + data[2] = eyePos[2]; data[3] = radius; data[4] = r; data[5] = g; diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 83303d61e..61b3e13d7 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -144,6 +144,7 @@ bool FRenderState::ApplyShader() activeShader->muTimer.Set(gl_frameMS * mShaderTimer / 1000.f); activeShader->muAlphaThreshold.Set(mAlphaThreshold); activeShader->muLightIndex.Set(mLightIndex); // will always be -1 for now + activeShader->muLightMath.Set(gl_light_math); activeShader->muClipSplit.Set(mClipSplit); if (mGlowEnabled) diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 67b9a2d6a..4acfd4bbe 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -246,6 +246,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muColormapStart.Init(hShader, "uFixedColormapStart"); muColormapRange.Init(hShader, "uFixedColormapRange"); muLightIndex.Init(hShader, "uLightIndex"); + muLightMath.Init(hShader, "uLightMath"); muFogColor.Init(hShader, "uFogColor"); muDynLightColor.Init(hShader, "uDynLightColor"); muObjectColor.Init(hShader, "uObjectColor"); diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 75e4b4e5e..09b43310d 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -221,6 +221,7 @@ class FShader FUniform1i muFixedColormap; FUniform4f muColormapStart; FUniform4f muColormapRange; + FBufferedUniform1i muLightMath; FBufferedUniform1i muLightIndex; FBufferedUniformPE muFogColor; FBufferedUniform4f muDynLightColor; diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index 0c31f53a8..290f3ea8c 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -29,6 +29,7 @@ EXTERN_CVAR (Float, gl_lights_size); EXTERN_CVAR (Bool, gl_lights_additive); EXTERN_CVAR (Bool, gl_light_sprites); EXTERN_CVAR (Bool, gl_light_particles); +EXTERN_CVAR (Int, gl_light_math); EXTERN_CVAR(Int, gl_fogmode) EXTERN_CVAR(Int, gl_lightmode) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 1e20ebeb2..79f71edf8 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2603,6 +2603,7 @@ GLLIGHTMNU_LIGHTPARTICLES = "Lights affect particles"; GLLIGHTMNU_FORCEADDITIVE = "Force additive lighting"; GLLIGHTMNU_LIGHTINTENSITY = "Light intensity"; GLLIGHTMNU_LIGHTSIZE = "Light size"; +GLLIGHTMNU_LIGHTMATH = "Light quality"; // OpenGL Preferences GLPREFMNU_TITLE = "OPENGL PREFERENCES"; @@ -2700,4 +2701,7 @@ OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; OPTVAL_REINHARD = "Reinhard"; -OPTVAL_PALETTE = "Palette"; \ No newline at end of file +OPTVAL_PALETTE = "Palette"; +OPTVAL_LOW = "Low"; +OPTVAL_MEDIUM = "Medium"; +OPTVAL_HIGH = "High"; diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 2386b1076..0d080d709 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -25,6 +25,13 @@ OptionValue "FilterModes" 4, "$OPTVAL_TRILINEAR" } +OptionValue "LightMathModes" +{ + 0, "$OPTVAL_LOW" + 1, "$OPTVAL_MEDIUM" + 2, "$OPTVAL_HIGH" +} + OptionValue "HWGammaModes" { 0, "$OPTVAL_ON" @@ -193,6 +200,7 @@ OptionMenu "GLLightOptions" Option "$GLLIGHTMNU_LIGHTSPRITES", gl_light_sprites, "YesNo" Option "$GLLIGHTMNU_LIGHTPARTICLES", gl_light_particles, "YesNo" Option "$GLLIGHTMNU_FORCEADDITIVE", gl_lights_additive, "YesNo" + Option "$GLLIGHTMNU_LIGHTMATH", gl_light_math, "LightMathModes" Slider "$GLLIGHTMNU_LIGHTINTENSITY", gl_lights_intensity, 0.0, 1.0, 0.1 Slider "$GLLIGHTMNU_LIGHTSIZE", gl_lights_size, 0.0, 2.0, 0.1 } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index b10c99a17..2a783e00c 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -25,6 +25,88 @@ vec4 Process(vec4 color); vec4 ProcessTexel(); vec4 ProcessLight(vec4 color); +// Smoothed normal used for the face, in eye space. Should be converted to an 'in' variable in the future. +vec3 pixelnormal; + +//=========================================================================== +// +// Calculates the face normal vector for the fragment, in eye space +// +//=========================================================================== + +vec3 calculateFaceNormal() +{ +#if __VERSION__ < 450 + vec3 dFdxPos = dFdx(pixelpos.xyz); + vec3 dFdyPos = dFdy(pixelpos.xyz); +#else + vec3 dFdxPos = dFdxCoarse(pixelpos.xyz); + vec3 dFdyPos = dFdyCoarse(pixelpos.xyz); +#endif + return normalize(cross(dFdxPos,dFdyPos)); +} + +//=========================================================================== +// +// Standard lambertian diffuse light calculation +// +//=========================================================================== + +float diffuseContribution(vec3 eyeLightDirection, vec3 eyeNormal) +{ + return max(dot(eyeNormal, eyeLightDirection), 0.0f); +} + +//=========================================================================== +// +// Blinn specular light calculation +// +//=========================================================================== + +float blinnSpecularContribution(float diffuseContribution, vec3 eyeLightDirection, vec3 eyePosition, vec3 eyeNormal, float glossiness, float specularLevel) +{ + if (diffuseContribution > 0.0f) + { + vec3 viewDir = normalize(-eyePosition); + vec3 halfDir = normalize(eyeLightDirection + viewDir); + float specAngle = max(dot(halfDir, eyeNormal), 0.0f); + float phExp = glossiness * 4.0f; + return specularLevel * pow(specAngle, phExp); + } + else + { + return 0.0f; + } +} + +//=========================================================================== +// +// Calculates the brightness of a dynamic point light +// +//=========================================================================== + +float pointLightAttenuation(vec4 lightpos) +{ + float attenuation = max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + if (uLightMath == 0) + { + return attenuation; + } + else + { + vec3 lightDirection = normalize(lightpos.xyz - pixelpos.xyz); + float diffuseAmount = diffuseContribution(lightDirection, pixelnormal); + if (uLightMath == 1) + { + return attenuation * diffuseAmount; + } + else + { + float specularAmount = blinnSpecularContribution(diffuseAmount, lightDirection, pixelpos.xyz, pixelnormal, 3.0, 1.2); + return attenuation * (diffuseAmount + specularAmount); + } + } +} //=========================================================================== // @@ -223,7 +305,7 @@ vec4 getLightColor(float fogdist, float fogfactor) vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb += lightcolor.rgb; } // @@ -233,8 +315,8 @@ vec4 getLightColor(float fogdist, float fogfactor) { vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + + lightcolor.rgb *= pointLightAttenuation(lightpos); dynlight.rgb -= lightcolor.rgb; } } @@ -267,6 +349,13 @@ vec4 applyFog(vec4 frag, float fogfactor) void main() { vec4 frag = ProcessTexel(); + +#if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS + if (uLightMath != 0) // Remove this if pixelnormal is converted to an 'in' variable + { + pixelnormal = calculateFaceNormal(); + } +#endif #ifndef NO_ALPHATEST if (frag.a <= uAlphaThreshold) discard; @@ -292,12 +381,11 @@ void main() } else { - fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + fogdist = max(16.0, length(pixelpos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); } - frag *= getLightColor(fogdist, fogfactor); #if defined NUM_UBO_LIGHTS || defined SHADER_STORAGE_LIGHTS @@ -316,7 +404,7 @@ void main() vec4 lightpos = lights[i]; vec4 lightcolor = lights[i+1]; - lightcolor.rgb *= max(lightpos.w - distance(pixelpos.xyz, lightpos.xyz),0.0) / lightpos.w; + lightcolor.rgb *= pointLightAttenuation(lightpos); addlight.rgb += lightcolor.rgb; } frag.rgb = clamp(frag.rgb + desaturate(addlight).rgb, 0.0, 1.0); @@ -363,7 +451,7 @@ void main() } else { - fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz)); + fogdist = max(16.0, length(pixelpos.xyz)); } fogfactor = exp2 (uFogDensity * fogdist); diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index a2c1bac5b..27faafb86 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -43,7 +43,7 @@ void main() vColor = aColor; #ifndef SIMPLE - pixelpos.xyz = worldcoord.xyz; + pixelpos.xyz = eyeCoordPos.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; glowdist.x = -((uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z) - worldcoord.y; diff --git a/wadsrc/static/shaders/glsl/shaderdefs.i b/wadsrc/static/shaders/glsl/shaderdefs.i index 3701694bc..0f0545b2d 100644 --- a/wadsrc/static/shaders/glsl/shaderdefs.i +++ b/wadsrc/static/shaders/glsl/shaderdefs.i @@ -44,6 +44,7 @@ uniform int uFogEnabled; // dynamic lights uniform int uLightIndex; +uniform int uLightMath; // 0, when using only attenuation, 1 for diffuse light, 2 for blinn specular light // quad drawer stuff #ifdef USE_QUAD_DRAWER From 737e70077421023fcebf7a2c177afa032f3a7297 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 29 Aug 2016 13:10:22 +0200 Subject: [PATCH 02/19] Added SSAO pass --- src/CMakeLists.txt | 1 + src/gl/renderer/gl_postprocess.cpp | 106 ++++++++++++++- src/gl/renderer/gl_renderbuffers.cpp | 152 +++++++++++++++++----- src/gl/renderer/gl_renderbuffers.h | 30 +++-- src/gl/renderer/gl_renderer.cpp | 5 + src/gl/renderer/gl_renderer.h | 9 ++ src/gl/scene/gl_scene.cpp | 10 +- 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.z | 1 + wadsrc/static/shaders/glsl/lineardepth.fp | 16 +++ wadsrc/static/shaders/glsl/ssao.fp | 117 +++++++++++++++++ 14 files changed, 531 insertions(+), 47 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 03f3372f0..13ef11ec3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1113,6 +1113,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_tonemapshader.cpp gl/shaders/gl_lensshader.cpp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 3a83f4caf..c7d0494c8 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -68,6 +68,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" @@ -106,6 +107,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) @@ -117,6 +132,95 @@ void FGLRenderer::RenderScreenQuad() GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); } +void FGLRenderer::PostProcessScene() +{ + if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture(); + AmbientOccludeScene(); + 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(); +} + //----------------------------------------------------------------------------- // // Adds bloom contribution to scene texture @@ -126,7 +230,7 @@ void FGLRenderer::RenderScreenQuad() void FGLRenderer::BloomScene() { // Only bloom things if enabled and no special fixed light mode is active - if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || gl_fixedcolormap != CM_DEFAULT) + if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || 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 fd98522d8..c1976565b 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -86,15 +86,16 @@ FGLRenderBuffers::~FGLRenderBuffers() ClearScene(); ClearPipeline(); ClearBloom(); + ClearAmbientOcclusion(); } void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); - DeleteRenderBuffer(mSceneMultisample); - DeleteRenderBuffer(mSceneDepthStencil); - DeleteRenderBuffer(mSceneDepth); - DeleteRenderBuffer(mSceneStencil); + DeleteRenderBuffer(mSceneMSColor); + DeleteRenderBuffer(mSceneMSDepthStencil); + DeleteRenderBuffer(mSceneMSDepth); + DeleteRenderBuffer(mSceneMSStencil); } void FGLRenderBuffers::ClearPipeline() @@ -104,6 +105,9 @@ void FGLRenderBuffers::ClearPipeline() DeleteFrameBuffer(mPipelineFB[i]); DeleteTexture(mPipelineTexture[i]); } + DeleteTexture(mPipelineDepthStencil); + DeleteTexture(mPipelineDepth); + DeleteTexture(mPipelineStencil); } void FGLRenderBuffers::ClearBloom() @@ -119,6 +123,14 @@ void FGLRenderBuffers::ClearBloom() } } +void FGLRenderBuffers::ClearAmbientOcclusion() +{ + DeleteFrameBuffer(AmbientFB0); + DeleteFrameBuffer(AmbientFB1); + DeleteTexture(AmbientTexture0); + DeleteTexture(AmbientTexture1); +} + void FGLRenderBuffers::DeleteTexture(GLuint &handle) { if (handle != 0) @@ -178,11 +190,12 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei } // Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts - if (mBloomWidth != sceneWidth || mBloomHeight != sceneHeight) + if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight) { CreateBloom(sceneWidth, sceneHeight); - mBloomWidth = sceneWidth; - mBloomHeight = sceneHeight; + CreateAmbientOcclusion(sceneWidth, sceneHeight); + mSceneWidth = sceneWidth; + mSceneHeight = sceneHeight; } glBindTexture(GL_TEXTURE_2D, textureBinding); @@ -198,8 +211,8 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei mWidth = 0; mHeight = 0; mSamples = 0; - mBloomWidth = 0; - mBloomHeight = 0; + mSceneWidth = 0; + mSceneHeight = 0; } return !FailedCreate; @@ -216,18 +229,27 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples) ClearScene(); if (samples > 1) - mSceneMultisample = CreateRenderBuffer("SceneMultisample", GetHdrFormat(), samples, width, height); - - if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) { - mSceneDepth = CreateRenderBuffer("SceneDepth", GL_DEPTH_COMPONENT24, samples, width, height); - mSceneStencil = CreateRenderBuffer("SceneStencil", GL_STENCIL_INDEX8, samples, width, height); - mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepth, mSceneStencil, samples > 1); + mSceneMSColor = CreateRenderBuffer("SceneMSColor", GetHdrFormat(), samples, width, height); + + if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) + { + mSceneMSDepth = CreateRenderBuffer("SceneMSDepth", GL_DEPTH_COMPONENT24, samples, width, height); + mSceneMSStencil = CreateRenderBuffer("SceneMSStencil", GL_STENCIL_INDEX8, samples, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMSColor, mSceneMSDepth, mSceneMSStencil, true); + } + else + { + mSceneMSDepthStencil = CreateRenderBuffer("SceneMSDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height); + mSceneFB = CreateFrameBuffer("SceneFB", mSceneMSColor, mSceneMSDepthStencil, true); + } } else { - mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height); - mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1); + if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mPipelineDepth, mPipelineStencil, false); + else + mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mPipelineDepthStencil, false); } } @@ -241,10 +263,23 @@ void FGLRenderBuffers::CreatePipeline(int width, int height) { ClearPipeline(); + if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) + { + mPipelineDepth = Create2DTexture("PipelineDepth", GL_DEPTH_COMPONENT24, width, height); + mPipelineStencil = Create2DTexture("PipelineStencil", GL_STENCIL_INDEX8, width, height); + } + else + { + mPipelineDepthStencil = Create2DTexture("PipelineDepthStencil", GL_DEPTH24_STENCIL8, width, height); + } + for (int i = 0; i < NumPipelineTextures; i++) { mPipelineTexture[i] = Create2DTexture("PipelineTexture", GetHdrFormat(), width, height); - mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i]); + if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) + mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i], mPipelineDepth, mPipelineStencil, false); + else + mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i], mPipelineDepthStencil, false); } } @@ -280,6 +315,27 @@ 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", GetHdrFormat(), AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GetHdrFormat(), AmbientWidth, AmbientHeight); + AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); + AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); +} + //========================================================================== // // Fallback support for older OpenGL where RGBA16F might not be available @@ -299,12 +355,24 @@ GLuint FGLRenderBuffers::GetHdrFormat() GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height) { - GLuint type = (format == GL_RGBA16F) ? 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, GL_RGBA, type, nullptr); + + GLenum dataformat, datatype; + switch (format) // Special thanks to the designers of OpenGL.. + { + 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_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; + default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture"); + } + + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -359,34 +427,45 @@ 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 colorbuffer, GLuint depthstencil, bool fromRenderBuffers) { GLuint handle = 0; glGenFramebuffers(1, &handle); glBindFramebuffer(GL_FRAMEBUFFER, handle); FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); - if (colorIsARenderBuffer) + if (fromRenderBuffers) + { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); + } else + { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0); + } if (CheckFrameBufferCompleteness()) ClearFrameBuffer(true, true); return handle; } -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer) +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool fromRenderBuffers) { GLuint handle = 0; glGenFramebuffers(1, &handle); glBindFramebuffer(GL_FRAMEBUFFER, handle); FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); - if (colorIsARenderBuffer) + if (fromRenderBuffers) + { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil); + } 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_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencil, 0); + } if (CheckFrameBufferCompleteness()) ClearFrameBuffer(true, true); return handle; @@ -441,7 +520,7 @@ void FGLRenderBuffers::ClearFrameBuffer(bool stencil, bool depth) glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencilValue); glGetDoublev(GL_DEPTH_CLEAR_VALUE, &depthValue); glDisable(GL_SCISSOR_TEST); - glClearColor(0.0, 0.0, 0.0, 0.0); + glClearColor(1.0, 0.0, 0.0, 0.0); glClearDepth(0.0); glClearStencil(0); GLenum flags = GL_COLOR_BUFFER_BIT; @@ -471,7 +550,7 @@ void FGLRenderBuffers::BlitSceneToTexture() glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]); - glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0) { @@ -494,6 +573,21 @@ void FGLRenderBuffers::BindSceneFB() glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); } +//========================================================================== +// +// Binds the depth texture to the specified texture unit +// +//========================================================================== + +void FGLRenderBuffers::BindSceneDepthTexture(int index) +{ + glActiveTexture(GL_TEXTURE0 + index); + if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0) + glBindTexture(GL_TEXTURE_2D, mPipelineDepth); + else + glBindTexture(GL_TEXTURE_2D, mPipelineDepthStencil); +} + //========================================================================== // // Binds the current scene/effect/hud texture to the specified texture unit diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index ee6d8de5e..898193e59 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -23,6 +23,7 @@ public: bool Setup(int width, int height, int sceneWidth, int sceneHeight); void BindSceneFB(); + void BindSceneDepthTexture(int index); void BlitSceneToTexture(); void BindCurrentTexture(int index); @@ -35,6 +36,14 @@ public: enum { NumBloomLevels = 4 }; FGLBloomTextureLevel BloomLevels[NumBloomLevels]; + // Ambient occlusion buffers + GLuint AmbientTexture0 = 0; + GLuint AmbientTexture1 = 0; + GLuint AmbientFB0 = 0; + GLuint AmbientFB1 = 0; + int AmbientWidth = 0; + int AmbientHeight = 0; + static bool IsEnabled(); int GetWidth() const { return mWidth; } @@ -44,15 +53,17 @@ private: void ClearScene(); void ClearPipeline(); void ClearBloom(); + void ClearAmbientOcclusion(); void CreateScene(int width, int height, int samples); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); + void CreateAmbientOcclusion(int width, int height); GLuint Create2DTexture(const FString &name, GLuint format, int width, int height); 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 colorbuffer, GLuint depthstencil, bool fromRenderBuffers); + GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool fromRenderBuffers); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); void DeleteTexture(GLuint &handle); @@ -65,22 +76,25 @@ private: int mHeight = 0; int mSamples = 0; int mMaxSamples = 0; - int mBloomWidth = 0; - int mBloomHeight = 0; + int mSceneWidth = 0; + int mSceneHeight = 0; static const int NumPipelineTextures = 2; int mCurrentPipelineTexture = 0; // Buffers for the scene - GLuint mSceneMultisample = 0; - GLuint mSceneDepthStencil = 0; - GLuint mSceneDepth = 0; - GLuint mSceneStencil = 0; + GLuint mSceneMSColor = 0; + GLuint mSceneMSDepthStencil = 0; + GLuint mSceneMSDepth = 0; + GLuint mSceneMSStencil = 0; GLuint mSceneFB = 0; // Effect/HUD buffers GLuint mPipelineTexture[NumPipelineTextures]; GLuint mPipelineFB[NumPipelineTextures]; + GLuint mPipelineDepthStencil = 0; + GLuint mPipelineDepth = 0; + GLuint mPipelineStencil = 0; // Back buffer frame buffer GLuint mOutputFB = 0; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index c8f2eb224..9e64c13b0 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -64,6 +64,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" @@ -120,6 +121,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(); mBlurShader = new FBlurShader(); @@ -179,6 +182,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 (mBlurShader) delete mBlurShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 4b663680f..b07870738 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 FBlurShader; @@ -89,6 +91,8 @@ public: int mOldFBID; FGLRenderBuffers *mBuffers; + FLinearDepthShader *mLinearDepthShader; + FSSAOShader *mSSAOShader; FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; FBlurShader *mBlurShader; @@ -164,6 +168,8 @@ public: void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); + void PostProcessScene(); + void AmbientOccludeScene(); void BloomScene(); void TonemapScene(); void BindTonemapPalette(int texunit); @@ -186,6 +192,9 @@ public: void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints, double originx, double originy, double scalex, double scaley, DAngle rotation, FDynamicColormap *colormap, int lightlevel); + + 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 08591283c..7537010b3 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -221,7 +221,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 @@ -855,13 +855,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo ProcessScene(toscreen); if (mainview && toscreen) EndDrawScene(retval); // do not call this for camera textures. - if (mainview) - { - if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture(); - BloomScene(); - TonemapScene(); - LensDistortScene(); - } + if (mainview) PostProcessScene(); mDrawingScene2D = false; eye->TearDown(); } diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp new file mode 100644 index 000000000..d9d4a3425 --- /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 000000000..44f916596 --- /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 d686a4a43..fa2a20ad4 100644 --- a/src/gl/stereo3d/gl_stereo3d.cpp +++ b/src/gl/stereo3d/gl_stereo3d.cpp @@ -49,7 +49,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 010c70565..6c455b94c 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2634,6 +2634,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.z b/wadsrc/static/menudef.z index 0d080d709..aae2ae76d 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -230,4 +230,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 000000000..f61bb3995 --- /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 000000000..c9f8534d9 --- /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 240ebf94a1d3c8463a4a4e8eb36ae3b2d95160d5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 29 Aug 2016 22:42:46 +0200 Subject: [PATCH 03/19] Remove radius increase in point light modes --- src/gl/dynlights/gl_dynlight1.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 56db94e4d..858bcfd09 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -139,9 +139,6 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, bo if (gl_light_math != 0) { - // Adjust light slightly to make the range better match plain attenuation - radius *= 1.5; - // Move light up because flasks/vials have their light source location at/below the floor. // // If the point is exactly on the wall plane it might cause some acne as some pixels could From 55ea4a7729b012fb1cda06e274d5dd4d991e6b8b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 30 Aug 2016 01:09:21 +0200 Subject: [PATCH 04/19] Add ssao random texture --- src/gl/renderer/gl_postprocess.cpp | 10 +++++++++ src/gl/renderer/gl_postprocessstate.cpp | 26 ++++++++++++++++++++++-- src/gl/renderer/gl_postprocessstate.h | 5 ++++- src/gl/renderer/gl_renderbuffers.cpp | 27 +++++++++++++++++++++++-- src/gl/renderer/gl_renderbuffers.h | 3 ++- src/gl/shaders/gl_ambientshader.cpp | 11 +++++++++- src/gl/shaders/gl_ambientshader.h | 2 ++ wadsrc/static/shaders/glsl/ssao.fp | 16 ++++++++------- 8 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index c7d0494c8..bd35fedd3 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -108,6 +108,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) @@ -155,11 +156,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]; @@ -185,8 +188,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); @@ -194,6 +203,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/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp index 05cca7f31..06a50d89a 100644 --- a/src/gl/renderer/gl_postprocessstate.cpp +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -58,7 +58,7 @@ FGLPostProcessState::FGLPostProcessState() { glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[0]); glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) { @@ -88,6 +88,15 @@ FGLPostProcessState::FGLPostProcessState() glDisable(GL_BLEND); } +void FGLPostProcessState::SaveTextureBinding1() +{ + glActiveTexture(GL_TEXTURE1); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[1]); + glBindTexture(GL_TEXTURE_2D, 0); + textureBinding1Saved = true; + glActiveTexture(GL_TEXTURE0); +} + //----------------------------------------------------------------------------- // // Restores state at the end of post processing @@ -121,6 +130,12 @@ FGLPostProcessState::~FGLPostProcessState() glUseProgram(currentProgram); + if (textureBinding1Saved) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) @@ -128,6 +143,13 @@ FGLPostProcessState::~FGLPostProcessState() glBindSampler(0, samplerBinding[0]); glBindSampler(1, samplerBinding[1]); } - glBindTexture(GL_TEXTURE_2D, textureBinding); + glBindTexture(GL_TEXTURE_2D, textureBinding[0]); + + if (textureBinding1Saved) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textureBinding[1]); + } + glActiveTexture(activeTex); } diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h index 4f2ca81a1..bf53aa7de 100644 --- a/src/gl/renderer/gl_postprocessstate.h +++ b/src/gl/renderer/gl_postprocessstate.h @@ -14,12 +14,14 @@ public: FGLPostProcessState(); ~FGLPostProcessState(); + void SaveTextureBinding1(); + private: FGLPostProcessState(const FGLPostProcessState &) = delete; FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; GLint activeTex; - GLint textureBinding; + GLint textureBinding[2]; GLint samplerBinding[2]; GLboolean blendEnabled; GLboolean scissorEnabled; @@ -32,6 +34,7 @@ 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 c1976565b..e00d836bf 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -53,6 +53,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); @@ -129,6 +130,7 @@ void FGLRenderBuffers::ClearAmbientOcclusion() DeleteFrameBuffer(AmbientFB1); DeleteTexture(AmbientTexture0); DeleteTexture(AmbientTexture1); + DeleteTexture(AmbientRandomTexture); } void FGLRenderBuffers::DeleteTexture(GLuint &handle) @@ -334,6 +336,26 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) AmbientTexture1 = Create2DTexture("AmbientTexture1", GetHdrFormat(), 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 * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 1] = (int16_t)clamp(y * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 2] = (int16_t)clamp(z * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 3] = (int16_t)clamp(w * 32768.0, -32767.0, 32768.0); + } + + AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); } //========================================================================== @@ -353,7 +375,7 @@ GLuint FGLRenderBuffers::GetHdrFormat() // //========================================================================== -GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height) +GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data) { GLuint handle = 0; glGenTextures(1, &handle); @@ -369,10 +391,11 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int 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, nullptr); + 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); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 898193e59..814fd9de8 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -43,6 +43,7 @@ public: GLuint AmbientFB1 = 0; int AmbientWidth = 0; int AmbientHeight = 0; + GLuint AmbientRandomTexture = 0; static bool IsEnabled(); @@ -58,7 +59,7 @@ private: void CreatePipeline(int width, int height); void CreateBloom(int width, int height); void CreateAmbientOcclusion(int width, int height); - GLuint Create2DTexture(const FString &name, GLuint format, int width, int height); + GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr); 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); diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index d9d4a3425..55682a91e 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 44f916596..fdff178ec 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 c9f8534d9..f143e913f 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 8a2737a0ce3b2cc40e03dc3037a315c8105b8a83 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 1 Sep 2016 07:15:40 +0200 Subject: [PATCH 05/19] Fix precision issue in SSAO shader --- src/gl/renderer/gl_postprocess.cpp | 8 ++++---- src/gl/renderer/gl_renderbuffers.cpp | 5 +++-- src/gl/renderer/gl_renderbuffers.h | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index bd35fedd3..62815f718 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -112,11 +112,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; @@ -165,8 +165,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.cpp b/src/gl/renderer/gl_renderbuffers.cpp index e00d836bf..6da85bba7 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -332,8 +332,8 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) AmbientWidth = width / 2; AmbientHeight = height / 2; - AmbientTexture0 = Create2DTexture("AmbientTexture0", GetHdrFormat(), AmbientWidth, AmbientHeight); - AmbientTexture1 = Create2DTexture("AmbientTexture1", GetHdrFormat(), AmbientWidth, AmbientHeight); + AmbientTexture0 = Create2DTexture("AmbientTexture0", GL_RGBA32F, AmbientWidth, AmbientHeight); + AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RGBA32F, AmbientWidth, AmbientHeight); AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0); AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1); @@ -388,6 +388,7 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int 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_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_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 814fd9de8..5dc2e49bd 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -50,6 +50,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 98032bc73f7bbdd3a9f8254f42abd2e8aa717e5a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 2 Sep 2016 05:45:00 +0200 Subject: [PATCH 06/19] 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); +} From 902097d6da05cc4e4ca315d40bccef7dcf791d8a Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Sep 2016 04:12:00 +0200 Subject: [PATCH 07/19] Resolve multisampling depth in shader --- src/gl/renderer/gl_postprocess.cpp | 20 ++- src/gl/renderer/gl_renderbuffers.cpp | 186 ++++++++++++++++------ src/gl/renderer/gl_renderbuffers.h | 27 +++- src/gl/shaders/gl_ambientshader.cpp | 28 ++-- src/gl/shaders/gl_ambientshader.h | 15 +- wadsrc/static/shaders/glsl/lineardepth.fp | 19 +++ 6 files changed, 211 insertions(+), 84 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index edf1148ef..1cd893f1c 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -136,8 +136,8 @@ void FGLRenderer::RenderScreenQuad() void FGLRenderer::PostProcessScene() { - mBuffers->BlitSceneToTexture(); AmbientOccludeScene(); + mBuffers->BlitSceneToTexture(); BloomScene(); TonemapScene(); ColormapScene(); @@ -165,6 +165,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]; @@ -177,12 +178,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 @@ -227,7 +231,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/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index f66ea1354..b2cee5704 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -53,6 +53,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) @@ -86,15 +87,14 @@ FGLRenderBuffers::~FGLRenderBuffers() ClearScene(); ClearPipeline(); ClearBloom(); + ClearAmbientOcclusion(); } void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); - DeleteRenderBuffer(mSceneMultisample); - DeleteRenderBuffer(mSceneDepthStencil); - DeleteRenderBuffer(mSceneDepth); - DeleteRenderBuffer(mSceneStencil); + DeleteTexture(mSceneMultisample); + DeleteTexture(mSceneDepthStencil); } void FGLRenderBuffers::ClearPipeline() @@ -119,6 +119,15 @@ void FGLRenderBuffers::ClearBloom() } } +void FGLRenderBuffers::ClearAmbientOcclusion() +{ + DeleteFrameBuffer(AmbientFB0); + DeleteFrameBuffer(AmbientFB1); + DeleteTexture(AmbientTexture0); + DeleteTexture(AmbientTexture1); + DeleteTexture(AmbientRandomTexture); +} + void FGLRenderBuffers::DeleteTexture(GLuint &handle) { if (handle != 0) @@ -186,11 +195,12 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei } // Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts - if (mBloomWidth != sceneWidth || mBloomHeight != sceneHeight) + if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight) { CreateBloom(sceneWidth, sceneHeight); - mBloomWidth = sceneWidth; - mBloomHeight = sceneHeight; + CreateAmbientOcclusion(sceneWidth, sceneHeight); + mSceneWidth = sceneWidth; + mSceneHeight = sceneHeight; } glBindTexture(GL_TEXTURE_2D, textureBinding); @@ -206,8 +216,8 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei mWidth = 0; mHeight = 0; mSamples = 0; - mBloomWidth = 0; - mBloomHeight = 0; + mSceneWidth = 0; + mSceneHeight = 0; } return !FailedCreate; @@ -224,9 +234,15 @@ 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); + } + else + { + mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height); + } - mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height); mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1); } @@ -279,20 +295,77 @@ 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 * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 1] = (int16_t)clamp(y * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 2] = (int16_t)clamp(z * 32768.0, -32767.0, 32768.0); + randomValues[i * 4 + 3] = (int16_t)clamp(w * 32768.0, -32767.0, 32768.0); + } + + AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues); +} + //========================================================================== // // Creates a 2D texture defaulting to linear filtering and clamp to edge // //========================================================================== -GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height) +GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data) { - GLuint type = (format == GL_RGBA16F) ? 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, GL_RGBA, type, nullptr); + + 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); @@ -300,6 +373,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 @@ -347,34 +431,22 @@ 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 colorbuffer, 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, colorbuffer, 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_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0); + } if (CheckFrameBufferCompleteness()) ClearFrameBuffer(true, true); return handle; @@ -394,22 +466,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; } @@ -482,6 +555,21 @@ void FGLRenderBuffers::BindSceneFB() glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB); } +//========================================================================== +// +// 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); +} + //========================================================================== // // Binds the current scene/effect/hud texture to the specified texture unit diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 08303a912..32430f2ed 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -23,6 +23,7 @@ public: bool Setup(int width, int height, int sceneWidth, int sceneHeight); void BindSceneFB(); + void BindSceneDepthTexture(int index); void BlitSceneToTexture(); void BindCurrentTexture(int index); @@ -35,24 +36,38 @@ public: enum { NumBloomLevels = 4 }; FGLBloomTextureLevel BloomLevels[NumBloomLevels]; + // 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; } int GetHeight() const { return mHeight; } + int GetSceneWidth() const { return mSceneWidth; } + int GetSceneHeight() const { return mSceneHeight; } + private: void ClearScene(); void ClearPipeline(); void ClearBloom(); + void ClearAmbientOcclusion(); void CreateScene(int width, int height, int samples); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); - GLuint Create2DTexture(const FString &name, GLuint format, int width, int height); + 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 colorbuffer, GLuint depthstencil, bool multisample); bool CheckFrameBufferCompleteness(); void ClearFrameBuffer(bool stencil, bool depth); void DeleteTexture(GLuint &handle); @@ -63,8 +78,8 @@ private: int mHeight = 0; int mSamples = 0; int mMaxSamples = 0; - int mBloomWidth = 0; - int mBloomHeight = 0; + int mSceneWidth = 0; + int mSceneHeight = 0; static const int NumPipelineTextures = 2; int mCurrentPipelineTexture = 0; @@ -72,8 +87,6 @@ private: // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 0; - GLuint mSceneDepth = 0; - GLuint mSceneStencil = 0; GLuint mSceneFB = 0; // Effect/HUD buffers diff --git a/src/gl/shaders/gl_ambientshader.cpp b/src/gl/shaders/gl_ambientshader.cpp index 6b8c9cc48..f3b6eced6 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 419ca939e..5f9ef630b 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 f61bb3995..31df9dc32 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 e7765bb240820c608dcb710a94a7b42d19ea465c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 3 Sep 2016 04:29:50 +0200 Subject: [PATCH 08/19] Move SSAO pass to be before translucent rendering Fix depth sampling location when not using fullscreen scene --- src/gl/renderer/gl_postprocess.cpp | 4 ++-- 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(+), 5 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 1cd893f1c..56032704e 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -136,7 +136,6 @@ void FGLRenderer::RenderScreenQuad() void FGLRenderer::PostProcessScene() { - AmbientOccludeScene(); mBuffers->BlitSceneToTexture(); BloomScene(); TonemapScene(); @@ -187,6 +186,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 @@ -246,7 +247,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 d5df31784..087bd9f62 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -503,6 +503,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 f3b6eced6..54a651281 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 5f9ef630b..5b18ea85f 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 31df9dc32..7e4eee745 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 3727c5ed0fc50f2bcaff689766e9d728ddf017a5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 4 Sep 2016 08:15:29 +0200 Subject: [PATCH 09/19] Mark portals in scene alpha channel for the SSAO pass --- src/gl/renderer/gl_postprocess.cpp | 5 +++++ src/gl/renderer/gl_renderbuffers.cpp | 15 +++++++++++++++ src/gl/renderer/gl_renderbuffers.h | 1 + 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 +- 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 56032704e..512209454 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -179,8 +179,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/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index b2cee5704..b0ea123a0 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -555,6 +555,21 @@ void FGLRenderBuffers::BindSceneFB() glBindFramebuffer(GL_FRAMEBUFFER, 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 depth texture to the specified texture unit diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 32430f2ed..2661908e3 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -23,6 +23,7 @@ public: bool Setup(int width, int height, int sceneWidth, int sceneHeight); void BindSceneFB(); + void BindSceneColorTexture(int index); void BindSceneDepthTexture(int index); void BlitSceneToTexture(); diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index cd3efb9e3..20ded84aa 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -429,14 +429,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_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 54a651281..3fbd03434 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 5b18ea85f..9c97791ba 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 7e4eee745..61e5e8126 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 d1b8745f6..65f12b405 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 8861b1aaffe2f0f6b9cb416cf2ad7ed5a6e8ad0b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Sep 2016 09:47:46 +0200 Subject: [PATCH 10/19] 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 b4fd4d05f..06c85a7bc 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -168,7 +168,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 63fb604e988298edf1ad9cf13e1f8a1ad95b747e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 9 Sep 2016 18:19:00 +0200 Subject: [PATCH 11/19] 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 06c85a7bc..e00ca7305 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -192,7 +192,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 61e5e8126..558738bd9 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 03d0b09f293b20d454dd5a7357096a2aae557746 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 10 Sep 2016 22:39:09 +0200 Subject: [PATCH 12/19] 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 e00ca7305..9b791a3f1 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -118,11 +118,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) @@ -163,7 +158,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; @@ -174,6 +168,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); @@ -225,14 +221,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 bd464d03d..c4f4438d3 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 a0b6a0275c5c521455e843709153ed1d7270435b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 11 Sep 2016 11:09:40 +0200 Subject: [PATCH 13/19] Fix random texture sampling bug --- src/gl/renderer/gl_postprocess.cpp | 2 ++ src/gl/renderer/gl_renderbuffers.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 9b791a3f1..f79ab2bf1 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -201,6 +201,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); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 9c442ce4e..dec9ab8ed 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -342,10 +342,10 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height) double z = distribution(generator); double w = distribution(generator); - randomValues[i * 4 + 0] = (int16_t)clamp(x * 32768.0, -32767.0, 32768.0); - randomValues[i * 4 + 1] = (int16_t)clamp(y * 32768.0, -32767.0, 32768.0); - randomValues[i * 4 + 2] = (int16_t)clamp(z * 32768.0, -32767.0, 32768.0); - randomValues[i * 4 + 3] = (int16_t)clamp(w * 32768.0, -32767.0, 32768.0); + 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); From 1e2935f4e0bb49e7af64ace8d1b26db04cb58727 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 18 Sep 2016 15:57:22 +0200 Subject: [PATCH 14/19] Added exposure pass calculating the bloom/tonemap exposure based on what the eye is seeing --- src/gl/renderer/gl_postprocess.cpp | 90 ++++++++++++++++++- src/gl/renderer/gl_postprocessstate.cpp | 26 +++++- src/gl/renderer/gl_postprocessstate.h | 5 +- src/gl/renderer/gl_renderbuffers.cpp | 66 ++++++++++++-- src/gl/renderer/gl_renderbuffers.h | 22 ++++- src/gl/renderer/gl_renderer.cpp | 9 ++ src/gl/renderer/gl_renderer.h | 8 +- src/gl/scene/gl_scene.cpp | 15 +--- src/gl/shaders/gl_bloomshader.cpp | 2 +- src/gl/shaders/gl_bloomshader.h | 2 +- src/gl/shaders/gl_tonemapshader.cpp | 50 ++++++++++- src/gl/shaders/gl_tonemapshader.h | 41 ++++++++- wadsrc/static/shaders/glsl/bloomextract.fp | 5 +- wadsrc/static/shaders/glsl/exposureaverage.fp | 23 +++++ wadsrc/static/shaders/glsl/exposurecombine.fp | 16 ++++ wadsrc/static/shaders/glsl/exposureextract.fp | 13 +++ wadsrc/static/shaders/glsl/tonemap.fp | 5 +- 17 files changed, 358 insertions(+), 40 deletions(-) create mode 100644 wadsrc/static/shaders/glsl/exposureaverage.fp create mode 100644 wadsrc/static/shaders/glsl/exposurecombine.fp create mode 100644 wadsrc/static/shaders/glsl/exposureextract.fp diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index b6b658a41..1cdad9f9b 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -75,7 +75,10 @@ CUSTOM_CVAR(Float, gl_bloom_amount, 1.4f, 0) if (self < 0.1f) self = 0.1f; } -CVAR(Float, gl_exposure, 0.0f, 0) +CVAR(Float, gl_exposure_scale, 0.75f, 0) +CVAR(Float, gl_exposure_min, 0.35f, 0) +CVAR(Float, gl_exposure_base, 0.35f, 0) +CVAR(Float, gl_exposure_speed, 0.05f, 0) CUSTOM_CVAR(Int, gl_tonemap, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { @@ -106,6 +109,78 @@ void FGLRenderer::RenderScreenQuad() GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); } +//----------------------------------------------------------------------------- +// +// Extracts light average from the scene and updates the camera exposure texture +// +//----------------------------------------------------------------------------- + +void FGLRenderer::UpdateCameraExposure() +{ + if (!gl_bloom && gl_tonemap == 0) + return; + + FGLDebug::PushGroup("UpdateCameraExposure"); + + FGLPostProcessState savedState; + savedState.SaveTextureBinding1(); + + // Extract light level from scene texture: + const auto &level0 = mBuffers->ExposureLevels[0]; + glBindFramebuffer(GL_FRAMEBUFFER, level0.Framebuffer); + glViewport(0, 0, level0.Width, level0.Height); + mBuffers->BindCurrentTexture(0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + mExposureExtractShader->Bind(); + mExposureExtractShader->SceneTexture.Set(0); + mExposureExtractShader->Scale.Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height); + mExposureExtractShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); + RenderScreenQuad(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Find the average value: + for (int i = 0; i + 1 < mBuffers->ExposureLevels.Size(); i++) + { + const auto &level = mBuffers->ExposureLevels[i]; + const auto &next = mBuffers->ExposureLevels[i + 1]; + + glBindFramebuffer(GL_FRAMEBUFFER, next.Framebuffer); + glViewport(0, 0, next.Width, next.Height); + glBindTexture(GL_TEXTURE_2D, level.Texture); + mExposureAverageShader->Bind(); + mExposureAverageShader->ExposureTexture.Set(0); + RenderScreenQuad(); + } + + // Combine average value with current camera exposure: + glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->ExposureFB); + glViewport(0, 0, 1, 1); + if (!mBuffers->FirstExposureFrame) + { + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + mBuffers->FirstExposureFrame = false; + } + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureLevels.Last().Texture); + mExposureCombineShader->Bind(); + mExposureCombineShader->ExposureTexture.Set(0); + mExposureCombineShader->ExposureBase.Set(gl_exposure_base); + mExposureCombineShader->ExposureMin.Set(gl_exposure_min); + mExposureCombineShader->ExposureScale.Set(gl_exposure_scale); + mExposureCombineShader->ExposureSpeed.Set(gl_exposure_speed); + RenderScreenQuad(); + glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); + + FGLDebug::PopGroup(); +} + //----------------------------------------------------------------------------- // // Adds bloom contribution to scene texture @@ -121,6 +196,7 @@ void FGLRenderer::BloomScene() FGLDebug::PushGroup("BloomScene"); FGLPostProcessState savedState; + savedState.SaveTextureBinding1(); const float blurAmount = gl_bloom_amount; int sampleCount = gl_bloom_kernel_size; @@ -133,9 +209,12 @@ void FGLRenderer::BloomScene() mBuffers->BindCurrentTexture(0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture); + glActiveTexture(GL_TEXTURE0); mBloomExtractShader->Bind(); mBloomExtractShader->SceneTexture.Set(0); - mBloomExtractShader->Exposure.Set(mCameraExposure); + mBloomExtractShader->ExposureTexture.Set(1); mBloomExtractShader->Scale.Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height); mBloomExtractShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); RenderScreenQuad(); @@ -220,7 +299,12 @@ void FGLRenderer::TonemapScene() } else { - mTonemapShader->Exposure.Set(mCameraExposure); + savedState.SaveTextureBinding1(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureTexture); + glActiveTexture(GL_TEXTURE0); + + mTonemapShader->ExposureTexture.Set(1); } RenderScreenQuad(); diff --git a/src/gl/renderer/gl_postprocessstate.cpp b/src/gl/renderer/gl_postprocessstate.cpp index 9d995783d..57b7862f5 100644 --- a/src/gl/renderer/gl_postprocessstate.cpp +++ b/src/gl/renderer/gl_postprocessstate.cpp @@ -45,7 +45,7 @@ FGLPostProcessState::FGLPostProcessState() { glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); glActiveTexture(GL_TEXTURE0); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[0]); glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) { @@ -75,6 +75,15 @@ FGLPostProcessState::FGLPostProcessState() glDisable(GL_BLEND); } +void FGLPostProcessState::SaveTextureBinding1() +{ + glActiveTexture(GL_TEXTURE1); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding[1]); + glBindTexture(GL_TEXTURE_2D, 0); + textureBinding1Saved = true; + glActiveTexture(GL_TEXTURE0); +} + //----------------------------------------------------------------------------- // // Restores state at the end of post processing @@ -108,6 +117,12 @@ FGLPostProcessState::~FGLPostProcessState() glUseProgram(currentProgram); + if (textureBinding1Saved) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); if (gl.flags & RFL_SAMPLER_OBJECTS) @@ -115,6 +130,13 @@ FGLPostProcessState::~FGLPostProcessState() glBindSampler(0, samplerBinding[0]); glBindSampler(1, samplerBinding[1]); } - glBindTexture(GL_TEXTURE_2D, textureBinding); + glBindTexture(GL_TEXTURE_2D, textureBinding[0]); + + if (textureBinding1Saved) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textureBinding[1]); + } + glActiveTexture(activeTex); } diff --git a/src/gl/renderer/gl_postprocessstate.h b/src/gl/renderer/gl_postprocessstate.h index 4f2ca81a1..bf53aa7de 100644 --- a/src/gl/renderer/gl_postprocessstate.h +++ b/src/gl/renderer/gl_postprocessstate.h @@ -14,12 +14,14 @@ public: FGLPostProcessState(); ~FGLPostProcessState(); + void SaveTextureBinding1(); + private: FGLPostProcessState(const FGLPostProcessState &) = delete; FGLPostProcessState &operator=(const FGLPostProcessState &) = delete; GLint activeTex; - GLint textureBinding; + GLint textureBinding[2]; GLint samplerBinding[2]; GLboolean blendEnabled; GLboolean scissorEnabled; @@ -32,6 +34,7 @@ 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 4383d706e..b2471e4b9 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -74,6 +74,7 @@ FGLRenderBuffers::~FGLRenderBuffers() ClearPipeline(); ClearEyeBuffers(); ClearBloom(); + ClearExposureLevels(); } void FGLRenderBuffers::ClearScene() @@ -107,6 +108,18 @@ void FGLRenderBuffers::ClearBloom() } } +void FGLRenderBuffers::ClearExposureLevels() +{ + for (auto &level : ExposureLevels) + { + DeleteTexture(level.Texture); + DeleteFrameBuffer(level.Framebuffer); + } + ExposureLevels.Clear(); + DeleteTexture(ExposureTexture); + DeleteFrameBuffer(ExposureFB); +} + void FGLRenderBuffers::ClearEyeBuffers() { for (auto handle : mEyeFBs) @@ -186,11 +199,12 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei } // Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts - if (mBloomWidth != sceneWidth || mBloomHeight != sceneHeight) + if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight) { CreateBloom(sceneWidth, sceneHeight); - mBloomWidth = sceneWidth; - mBloomHeight = sceneHeight; + CreateExposureLevels(sceneWidth, sceneHeight); + mSceneWidth = sceneWidth; + mSceneHeight = sceneHeight; } glBindTexture(GL_TEXTURE_2D, textureBinding); @@ -204,11 +218,12 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei ClearPipeline(); ClearEyeBuffers(); ClearBloom(); + ClearExposureLevels(); mWidth = 0; mHeight = 0; mSamples = 0; - mBloomWidth = 0; - mBloomHeight = 0; + mSceneWidth = 0; + mSceneHeight = 0; } return !FailedCreate; @@ -281,6 +296,41 @@ void FGLRenderBuffers::CreateBloom(int width, int height) } } +//========================================================================== +// +// Creates camera exposure level buffers +// +//========================================================================== + +void FGLRenderBuffers::CreateExposureLevels(int width, int height) +{ + ClearExposureLevels(); + + int i = 0; + do + { + width = MAX(width / 2, 1); + height = MAX(height / 2, 1); + + FString textureName, fbName; + textureName.Format("Exposure.Texture%d", i); + fbName.Format("Exposure.Framebuffer%d", i); + i++; + + FGLExposureTextureLevel level; + level.Width = width; + level.Height = height; + level.Texture = Create2DTexture(textureName, GL_R32F, level.Width, level.Height); + level.Framebuffer = CreateFrameBuffer(fbName, level.Texture); + ExposureLevels.Push(level); + } while (width > 1 || height > 1); + + ExposureTexture = Create2DTexture("Exposure.CameraTexture", GL_R32F, 1, 1); + ExposureFB = CreateFrameBuffer("Exposure.CameraFB", ExposureTexture); + + FirstExposureFrame = true; +} + //========================================================================== // // Creates eye buffers if needed @@ -316,14 +366,14 @@ void FGLRenderBuffers::CreateEyeBuffers(int eye) // //========================================================================== -GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height) +GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data) { - GLuint type = (format == GL_RGBA16F) ? GL_FLOAT : GL_UNSIGNED_BYTE; + 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, GL_RGBA, type, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format != GL_R32F ? GL_RGBA : GL_RED, type, 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); diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 08731e39f..4477718f4 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -14,6 +14,15 @@ public: GLuint Height = 0; }; +class FGLExposureTextureLevel +{ +public: + GLuint Texture = 0; + GLuint Framebuffer = 0; + GLuint Width = 0; + GLuint Height = 0; +}; + class FGLRenderBuffers { public: @@ -39,6 +48,11 @@ public: enum { NumBloomLevels = 4 }; FGLBloomTextureLevel BloomLevels[NumBloomLevels]; + TArray ExposureLevels; + GLuint ExposureTexture = 0; + GLuint ExposureFB = 0; + bool FirstExposureFrame = true; + static bool IsEnabled(); int GetWidth() const { return mWidth; } @@ -49,11 +63,13 @@ private: void ClearPipeline(); void ClearEyeBuffers(); void ClearBloom(); + void ClearExposureLevels(); 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); - GLuint Create2DTexture(const FString &name, GLuint format, int width, int height); + GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr); 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); @@ -69,8 +85,8 @@ private: int mHeight = 0; int mSamples = 0; int mMaxSamples = 0; - int mBloomWidth = 0; - int mBloomHeight = 0; + int mSceneWidth = 0; + int mSceneHeight = 0; static const int NumPipelineTextures = 2; int mCurrentPipelineTexture = 0; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 4b59ad1a9..ab0e658e7 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -104,6 +104,9 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mPresentShader = nullptr; mBloomExtractShader = nullptr; mBloomCombineShader = nullptr; + mExposureExtractShader = nullptr; + mExposureAverageShader = nullptr; + mExposureCombineShader = nullptr; mBlurShader = nullptr; mTonemapShader = nullptr; mTonemapPalette = nullptr; @@ -119,6 +122,9 @@ void FGLRenderer::Initialize(int width, int height) mBuffers = new FGLRenderBuffers(); mBloomExtractShader = new FBloomExtractShader(); mBloomCombineShader = new FBloomCombineShader(); + mExposureExtractShader = new FExposureExtractShader(); + mExposureAverageShader = new FExposureAverageShader(); + mExposureCombineShader = new FExposureCombineShader(); mBlurShader = new FBlurShader(); mTonemapShader = new FTonemapShader(); mColormapShader = new FColormapShader(); @@ -179,6 +185,9 @@ FGLRenderer::~FGLRenderer() if (mPresentShader) delete mPresentShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; + if (mExposureExtractShader) delete mExposureExtractShader; + if (mExposureAverageShader) delete mExposureAverageShader; + if (mExposureCombineShader) delete mExposureCombineShader; if (mBlurShader) delete mBlurShader; if (mTonemapShader) delete mTonemapShader; if (mTonemapPalette) delete mTonemapPalette; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 162fb6dcf..b95408521 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -21,6 +21,9 @@ class DPSprite; class FGLRenderBuffers; class FBloomExtractShader; class FBloomCombineShader; +class FExposureExtractShader; +class FExposureAverageShader; +class FExposureCombineShader; class FBlurShader; class FTonemapShader; class FColormapShader; @@ -92,6 +95,9 @@ public: FGLRenderBuffers *mBuffers; FBloomExtractShader *mBloomExtractShader; FBloomCombineShader *mBloomCombineShader; + FExposureExtractShader *mExposureExtractShader; + FExposureAverageShader *mExposureAverageShader; + FExposureCombineShader *mExposureCombineShader; FBlurShader *mBlurShader; FTonemapShader *mTonemapShader; FColormapShader *mColormapShader; @@ -118,7 +124,6 @@ public: GL_IRECT mSceneViewport; GL_IRECT mOutputLetterbox; bool mDrawingScene2D = false; - float mCameraExposure = 1.0f; float mSceneClearColor[3]; @@ -166,6 +171,7 @@ public: void SetFixedColormap (player_t *player); void WriteSavePic (player_t *player, FILE *file, int width, int height); void EndDrawScene(sector_t * viewsector); + void UpdateCameraExposure(); void BloomScene(); void TonemapScene(); void ColormapScene(); diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index ccceeac5f..c66bd64e8 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -790,20 +790,6 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo mViewActor=camera; } - if (toscreen) - { - if (gl_exposure == 0.0f) - { - float light = viewsector->lightlevel / 255.0f; - float exposure = MAX(1.0f + (1.0f - light * light) * 0.9f, 0.5f); - mCameraExposure = mCameraExposure * 0.995f + exposure * 0.005f; - } - else - { - mCameraExposure = gl_exposure; - } - } - // 'viewsector' will not survive the rendering so it cannot be used anymore below. lviewsector = viewsector; @@ -839,6 +825,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo if (mainview && FGLRenderBuffers::IsEnabled()) { mBuffers->BlitSceneToTexture(); + UpdateCameraExposure(); BloomScene(); TonemapScene(); ColormapScene(); diff --git a/src/gl/shaders/gl_bloomshader.cpp b/src/gl/shaders/gl_bloomshader.cpp index a16c9ed1e..44253ae79 100644 --- a/src/gl/shaders/gl_bloomshader.cpp +++ b/src/gl/shaders/gl_bloomshader.cpp @@ -46,7 +46,7 @@ void FBloomExtractShader::Bind() mShader.Link("shaders/glsl/bloomextract"); mShader.SetAttribLocation(0, "PositionInProjection"); SceneTexture.Init(mShader, "SceneTexture"); - Exposure.Init(mShader, "ExposureAdjustment"); + ExposureTexture.Init(mShader, "ExposureTexture"); Scale.Init(mShader, "Scale"); Offset.Init(mShader, "Offset"); } diff --git a/src/gl/shaders/gl_bloomshader.h b/src/gl/shaders/gl_bloomshader.h index b20277a42..8b34bb479 100644 --- a/src/gl/shaders/gl_bloomshader.h +++ b/src/gl/shaders/gl_bloomshader.h @@ -9,7 +9,7 @@ public: void Bind(); FBufferedUniformSampler SceneTexture; - FBufferedUniform1f Exposure; + FBufferedUniformSampler ExposureTexture; FBufferedUniform2f Scale; FBufferedUniform2f Offset; diff --git a/src/gl/shaders/gl_tonemapshader.cpp b/src/gl/shaders/gl_tonemapshader.cpp index 144981b18..3db6db8ba 100644 --- a/src/gl/shaders/gl_tonemapshader.cpp +++ b/src/gl/shaders/gl_tonemapshader.cpp @@ -47,7 +47,7 @@ void FTonemapShader::Bind() shader.Link("shaders/glsl/tonemap"); shader.SetAttribLocation(0, "PositionInProjection"); SceneTexture.Init(shader, "InputTexture"); - Exposure.Init(shader, "ExposureAdjustment"); + ExposureTexture.Init(shader, "ExposureTexture"); PaletteLUT.Init(shader, "PaletteLUT"); } shader.Bind(); @@ -70,3 +70,51 @@ const char *FTonemapShader::GetDefines(int mode) case Palette: return "#define PALETTE\n"; } } + +void FExposureExtractShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/exposureextract.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/exposureextract"); + mShader.SetAttribLocation(0, "PositionInProjection"); + SceneTexture.Init(mShader, "SceneTexture"); + Scale.Init(mShader, "Scale"); + Offset.Init(mShader, "Offset"); + } + mShader.Bind(); +} + +void FExposureAverageShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 400); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/exposureaverage.fp", "", 400); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/exposureaverage"); + mShader.SetAttribLocation(0, "PositionInProjection"); + ExposureTexture.Init(mShader, "ExposureTexture"); + } + mShader.Bind(); +} + +void FExposureCombineShader::Bind() +{ + if (!mShader) + { + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/exposurecombine.fp", "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link("shaders/glsl/exposurecombine"); + mShader.SetAttribLocation(0, "PositionInProjection"); + ExposureTexture.Init(mShader, "ExposureTexture"); + ExposureBase.Init(mShader, "ExposureBase"); + ExposureMin.Init(mShader, "ExposureMin"); + ExposureScale.Init(mShader, "ExposureScale"); + ExposureSpeed.Init(mShader, "ExposureSpeed"); + } + mShader.Bind(); +} \ No newline at end of file diff --git a/src/gl/shaders/gl_tonemapshader.h b/src/gl/shaders/gl_tonemapshader.h index 7ec24117b..b4cd102de 100644 --- a/src/gl/shaders/gl_tonemapshader.h +++ b/src/gl/shaders/gl_tonemapshader.h @@ -9,7 +9,7 @@ public: void Bind(); FBufferedUniformSampler SceneTexture; - FBufferedUniform1f Exposure; + FBufferedUniformSampler ExposureTexture; FBufferedUniformSampler PaletteLUT; static bool IsPaletteMode(); @@ -31,4 +31,43 @@ private: FShaderProgram mShader[NumTonemapModes]; }; +class FExposureExtractShader +{ +public: + void Bind(); + + FBufferedUniformSampler SceneTexture; + FBufferedUniform2f Scale; + FBufferedUniform2f Offset; + +private: + FShaderProgram mShader; +}; + +class FExposureAverageShader +{ +public: + void Bind(); + + FBufferedUniformSampler ExposureTexture; + +private: + FShaderProgram mShader; +}; + +class FExposureCombineShader +{ +public: + void Bind(); + + FBufferedUniformSampler ExposureTexture; + FBufferedUniform1f ExposureBase; + FBufferedUniform1f ExposureMin; + FBufferedUniform1f ExposureScale; + FBufferedUniform1f ExposureSpeed; + +private: + FShaderProgram mShader; +}; + #endif \ No newline at end of file diff --git a/wadsrc/static/shaders/glsl/bloomextract.fp b/wadsrc/static/shaders/glsl/bloomextract.fp index bc94c3c0e..9c5aa0bea 100644 --- a/wadsrc/static/shaders/glsl/bloomextract.fp +++ b/wadsrc/static/shaders/glsl/bloomextract.fp @@ -3,12 +3,13 @@ in vec2 TexCoord; out vec4 FragColor; uniform sampler2D SceneTexture; -uniform float ExposureAdjustment; +uniform sampler2D ExposureTexture; uniform vec2 Scale; uniform vec2 Offset; void main() { + float exposureAdjustment = texture(ExposureTexture, vec2(0.5)).x; vec4 color = texture(SceneTexture, Offset + TexCoord * Scale); - FragColor = max(vec4(color.rgb * ExposureAdjustment - 1, 1), vec4(0)); + FragColor = max(vec4((color.rgb + vec3(0.001)) * exposureAdjustment - 1, 1), vec4(0)); } diff --git a/wadsrc/static/shaders/glsl/exposureaverage.fp b/wadsrc/static/shaders/glsl/exposureaverage.fp new file mode 100644 index 000000000..41c0909d2 --- /dev/null +++ b/wadsrc/static/shaders/glsl/exposureaverage.fp @@ -0,0 +1,23 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D ExposureTexture; + +void main() +{ +#if __VERSION__ < 400 + ivec2 size = textureSize(ExposureTexture, 0); + ivec2 tl = max(ivec2(TexCoord * vec2(size) - 0.5), ivec2(0)); + ivec2 br = min(tl + ivec2(1), size - ivec2(1)); + vec4 values = vec4( + texelFetch(ExposureTexture, tl, 0).x, + texelFetch(ExposureTexture, ivec2(tl.x, br.y), 0).x, + texelFetch(ExposureTexture, ivec2(br.x, tl.y), 0).x, + texelFetch(ExposureTexture, br, 0).x); +#else + vec4 values = textureGather(ExposureTexture, TexCoord); +#endif + + FragColor = vec4((values.x + values.y + values.z + values.w) * 0.25, 0.0, 0.0, 1.0); +} diff --git a/wadsrc/static/shaders/glsl/exposurecombine.fp b/wadsrc/static/shaders/glsl/exposurecombine.fp new file mode 100644 index 000000000..f806f8f86 --- /dev/null +++ b/wadsrc/static/shaders/glsl/exposurecombine.fp @@ -0,0 +1,16 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D ExposureTexture; +uniform float ExposureBase; +uniform float ExposureMin; +uniform float ExposureScale; +uniform float ExposureSpeed; + +void main() +{ + float light = texture(ExposureTexture, TexCoord).x; + float exposureAdjustment = 1.0 / max(ExposureBase + light * ExposureScale, ExposureMin); + FragColor = vec4(exposureAdjustment, 0.0, 0.0, ExposureSpeed); +} diff --git a/wadsrc/static/shaders/glsl/exposureextract.fp b/wadsrc/static/shaders/glsl/exposureextract.fp new file mode 100644 index 000000000..f673bf029 --- /dev/null +++ b/wadsrc/static/shaders/glsl/exposureextract.fp @@ -0,0 +1,13 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D SceneTexture; +uniform vec2 Scale; +uniform vec2 Offset; + +void main() +{ + vec4 color = texture(SceneTexture, Offset + TexCoord * Scale); + FragColor = vec4(max(max(color.r, color.g), color.b), 0.0, 0.0, 1.0); +} diff --git a/wadsrc/static/shaders/glsl/tonemap.fp b/wadsrc/static/shaders/glsl/tonemap.fp index d6574b295..5cb7cf8bd 100644 --- a/wadsrc/static/shaders/glsl/tonemap.fp +++ b/wadsrc/static/shaders/glsl/tonemap.fp @@ -3,7 +3,7 @@ in vec2 TexCoord; out vec4 FragColor; uniform sampler2D InputTexture; -uniform float ExposureAdjustment; +uniform sampler2D ExposureTexture; vec3 Linear(vec3 c) { @@ -84,7 +84,8 @@ void main() { vec3 color = texture(InputTexture, TexCoord).rgb; #ifndef PALETTE - color = color * ExposureAdjustment; + float exposureAdjustment = texture(ExposureTexture, vec2(0.5)).x; + color = color * exposureAdjustment; color = Linear(color); // needed because gzdoom's scene texture is not linear at the moment #endif FragColor = vec4(Tonemap(color), 1.0); From 210dd6d26a3e3041092d5aba14b1d140a8f377b6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 18 Sep 2016 19:31:09 +0200 Subject: [PATCH 15/19] Make bloom/exposure less aggressive --- 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 1cdad9f9b..7ce8be0ad 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -75,7 +75,7 @@ CUSTOM_CVAR(Float, gl_bloom_amount, 1.4f, 0) if (self < 0.1f) self = 0.1f; } -CVAR(Float, gl_exposure_scale, 0.75f, 0) +CVAR(Float, gl_exposure_scale, 1.3f, 0) CVAR(Float, gl_exposure_min, 0.35f, 0) CVAR(Float, gl_exposure_base, 0.35f, 0) CVAR(Float, gl_exposure_speed, 0.05f, 0) From 24f748da03dad1c43c2c8a779546da7bf97d3176 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 20 Sep 2016 02:57:57 +0200 Subject: [PATCH 16/19] 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 cd51e540a..2cfd739e9 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(); } @@ -343,7 +344,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 1c0a20348..7bec51be0 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 158163a48..26a449bf2 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); @@ -298,12 +301,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 @@ -386,27 +390,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(); } //========================================================================== @@ -415,10 +467,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++) @@ -428,11 +500,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); } } @@ -442,7 +514,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); } @@ -464,11 +536,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]; @@ -492,7 +561,7 @@ void FShaderManager::Clean() // //========================================================================== -int FShaderManager::Find(const char * shn) +int FShaderCollection::Find(const char * shn) { FName sfn = shn; @@ -506,21 +575,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; - } -} - //========================================================================== // @@ -528,7 +582,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) { @@ -546,36 +600,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 5af927e6d..793fa63dd 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; @@ -323,7 +324,6 @@ public: }; - //========================================================================== // // The global shader manager @@ -331,26 +331,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 84b7f5742..0b66f0569 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 @@ -433,5 +436,8 @@ void main() } } FragColor = frag; +#ifdef GBUFFER_PASS + FragData = vec4(uFogColor.rgb, 1.0); +#endif } From b6c64416be6180f53ffeee09755a1f65f9e6ba70 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 21 Sep 2016 02:04:56 +0200 Subject: [PATCH 17/19] 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_renderbuffers.cpp | 36 +++++++++++++++++++---- src/gl/renderer/gl_renderbuffers.h | 7 +++-- 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 +++++++++++++++++- 10 files changed, 150 insertions(+), 32 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 8b8afd52e..b3d125922 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -138,9 +138,6 @@ void FGLRenderer::PostProcessScene() void FGLRenderer::AmbientOccludeScene() { - if (!gl_ssao || !FGLRenderBuffers::IsEnabled()) - return; - FGLDebug::PushGroup("AmbientOccludeScene"); FGLPostProcessState savedState; @@ -227,20 +224,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_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index b52f2a0b6..54d597c4d 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -82,7 +82,9 @@ FGLRenderBuffers::~FGLRenderBuffers() void FGLRenderBuffers::ClearScene() { DeleteFrameBuffer(mSceneFB); + DeleteFrameBuffer(mSceneDataFB); DeleteTexture(mSceneMultisample); + DeleteTexture(mSceneData); DeleteTexture(mSceneDepthStencil); } @@ -253,13 +255,16 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples) { 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); } - 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); } //========================================================================== @@ -512,7 +517,7 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff return handle; } -GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool multisample) +GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample) { GLuint handle = 0; glGenFramebuffers(1, &handle); @@ -520,12 +525,16 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name); if (multisample) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer, 0); + 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); + 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()) @@ -668,9 +677,9 @@ 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); } //========================================================================== @@ -688,6 +697,21 @@ void FGLRenderBuffers::BindSceneColorTexture(int index) 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 diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 19a2979f2..080593881 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -31,8 +31,9 @@ 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(); @@ -90,7 +91,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 multisample); + 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); @@ -110,7 +111,9 @@ private: // Buffers for the scene GLuint mSceneMultisample = 0; GLuint mSceneDepthStencil = 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 db2be0d9d..a02d27852 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -320,7 +320,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 2659e8ea2..596f2c22b 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -157,7 +157,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. @@ -490,7 +494,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 @@ -498,6 +508,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 3fbd03434..4fa5b0e01 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 9c97791ba..f36b10625 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 f6dc61472..c1bc5c2fe 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -51,6 +51,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 0b66f0569..cdd6ffe3f 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -315,6 +315,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); +} //=========================================================================== // @@ -437,7 +463,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 21fdff102..7cd096276 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 7c862b85b3d9c939ac17031b6d4e1a7aa29bab7e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 22 Sep 2016 03:49:19 +0200 Subject: [PATCH 18/19] 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 596f2c22b..8331930bc 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -492,14 +492,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 @@ -508,15 +523,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 43505877143dbba40e8ef454625b053ff5b7ca6b Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 24 Sep 2016 08:40:28 +0200 Subject: [PATCH 19/19] Remove accidental UpdateCameraExposure duplicate from merge --- src/gl/renderer/gl_postprocess.cpp | 72 ------------------------------ 1 file changed, 72 deletions(-) diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index 0747e95d8..b3d125922 100644 --- a/src/gl/renderer/gl_postprocess.cpp +++ b/src/gl/renderer/gl_postprocess.cpp @@ -322,78 +322,6 @@ void FGLRenderer::UpdateCameraExposure() FGLDebug::PopGroup(); } -//----------------------------------------------------------------------------- -// -// Extracts light average from the scene and updates the camera exposure texture -// -//----------------------------------------------------------------------------- - -void FGLRenderer::UpdateCameraExposure() -{ - if (!gl_bloom && gl_tonemap == 0) - return; - - FGLDebug::PushGroup("UpdateCameraExposure"); - - FGLPostProcessState savedState; - savedState.SaveTextureBinding1(); - - // Extract light level from scene texture: - const auto &level0 = mBuffers->ExposureLevels[0]; - glBindFramebuffer(GL_FRAMEBUFFER, level0.Framebuffer); - glViewport(0, 0, level0.Width, level0.Height); - mBuffers->BindCurrentTexture(0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - mExposureExtractShader->Bind(); - mExposureExtractShader->SceneTexture.Set(0); - mExposureExtractShader->Scale.Set(mSceneViewport.width / (float)mScreenViewport.width, mSceneViewport.height / (float)mScreenViewport.height); - mExposureExtractShader->Offset.Set(mSceneViewport.left / (float)mScreenViewport.width, mSceneViewport.top / (float)mScreenViewport.height); - RenderScreenQuad(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // Find the average value: - for (int i = 0; i + 1 < mBuffers->ExposureLevels.Size(); i++) - { - const auto &level = mBuffers->ExposureLevels[i]; - const auto &next = mBuffers->ExposureLevels[i + 1]; - - glBindFramebuffer(GL_FRAMEBUFFER, next.Framebuffer); - glViewport(0, 0, next.Width, next.Height); - glBindTexture(GL_TEXTURE_2D, level.Texture); - mExposureAverageShader->Bind(); - mExposureAverageShader->ExposureTexture.Set(0); - RenderScreenQuad(); - } - - // Combine average value with current camera exposure: - glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->ExposureFB); - glViewport(0, 0, 1, 1); - if (!mBuffers->FirstExposureFrame) - { - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - else - { - mBuffers->FirstExposureFrame = false; - } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mBuffers->ExposureLevels.Last().Texture); - mExposureCombineShader->Bind(); - mExposureCombineShader->ExposureTexture.Set(0); - mExposureCombineShader->ExposureBase.Set(gl_exposure_base); - mExposureCombineShader->ExposureMin.Set(gl_exposure_min); - mExposureCombineShader->ExposureScale.Set(gl_exposure_scale); - mExposureCombineShader->ExposureSpeed.Set(gl_exposure_speed); - RenderScreenQuad(); - glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height); - - FGLDebug::PopGroup(); -} - //----------------------------------------------------------------------------- // // Adds bloom contribution to scene texture