diff --git a/src/gl/renderer/gl_postprocess.cpp b/src/gl/renderer/gl_postprocess.cpp index c7d0494c80..bd35fedd3d 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 05cca7f312..06a50d89aa 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 4f2ca81a12..bf53aa7de9 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 c1976565b8..e00d836bfe 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 898193e59c..814fd9de85 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 d9d4a34257..55682a91e0 100644 --- a/src/gl/shaders/gl_ambientshader.cpp +++ b/src/gl/shaders/gl_ambientshader.cpp @@ -71,12 +71,20 @@ void FSSAOShader::Bind() { if (!mShader) { + const char *defines = R"( + #define USE_RANDOM_TEXTURE + #define RANDOM_TEXTURE_WIDTH 4.0 + #define NUM_DIRECTIONS 8.0 + #define NUM_STEPS 4.0 + )"; + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", "", 330); + mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", defines, 330); mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/ssao"); mShader.SetAttribLocation(0, "PositionInProjection"); DepthTexture.Init(mShader, "DepthTexture"); + RandomTexture.Init(mShader, "RandomTexture"); UVToViewA.Init(mShader, "UVToViewA"); UVToViewB.Init(mShader, "UVToViewB"); InvFullResolution.Init(mShader, "InvFullResolution"); @@ -84,6 +92,7 @@ void FSSAOShader::Bind() NegInvR2.Init(mShader, "NegInvR2"); RadiusToScreen.Init(mShader, "RadiusToScreen"); AOMultiplier.Init(mShader, "AOMultiplier"); + AOStrength.Init(mShader, "AOStrength"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_ambientshader.h b/src/gl/shaders/gl_ambientshader.h index 44f9165964..fdff178ec2 100644 --- a/src/gl/shaders/gl_ambientshader.h +++ b/src/gl/shaders/gl_ambientshader.h @@ -24,6 +24,7 @@ public: void Bind(); FBufferedUniformSampler DepthTexture; + FBufferedUniformSampler RandomTexture; FBufferedUniform2f UVToViewA; FBufferedUniform2f UVToViewB; FBufferedUniform2f InvFullResolution; @@ -31,6 +32,7 @@ public: FBufferedUniform1f NegInvR2; FBufferedUniform1f RadiusToScreen; FBufferedUniform1f AOMultiplier; + FBufferedUniform1f AOStrength; private: FShaderProgram mShader; diff --git a/wadsrc/static/shaders/glsl/ssao.fp b/wadsrc/static/shaders/glsl/ssao.fp index c9f8534d9f..f143e913f7 100644 --- a/wadsrc/static/shaders/glsl/ssao.fp +++ b/wadsrc/static/shaders/glsl/ssao.fp @@ -11,15 +11,14 @@ uniform float NegInvR2; uniform float RadiusToScreen; uniform float AOMultiplier; +uniform float AOStrength; + uniform sampler2D DepthTexture; -#if USE_RANDOM_TEXTURE +#if defined(USE_RANDOM_TEXTURE) uniform sampler2D RandomTexture; #endif -#define NUM_DIRECTIONS 8.0 -#define NUM_STEPS 4.0 - #define PI 3.14159265358979323846 // Calculate eye space position for the specified texture coordinate @@ -54,13 +53,12 @@ vec2 RotateDirection(vec2 dir, vec2 cossin) vec4 GetJitter() { -#if !USE_RANDOM_TEXTURE +#if !defined(USE_RANDOM_TEXTURE) return vec4(1,0,1,1); //vec3 rand = noise3(TexCoord.x + TexCoord.y); //float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS; //return vec4(cos(angle), sin(angle), rand.y, rand.z); #else - #define RANDOM_TEXTURE_WIDTH 4.0 return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH); #endif } @@ -109,7 +107,11 @@ void main() { vec3 viewPosition = FetchViewPos(TexCoord); vec3 viewNormal = ReconstructNormal(viewPosition); - float occlusion = ComputeAO(viewPosition, viewNormal); + float occlusion = ComputeAO(viewPosition, viewNormal) * AOStrength + (1.0 - AOStrength); + + // GZDoom does not use linear buffers at the moment, apply some gamma to get it closer to correct + occlusion = occlusion * occlusion; + //FragColor = vec4(viewPosition.x * 0.001 + 0.5, viewPosition.y * 0.001 + 0.5, viewPosition.z * 0.001, 1.0); //FragColor = vec4(viewNormal.x * 0.5 + 0.5, viewNormal.y * 0.5 + 0.5, viewNormal.z * 0.5 + 0.5, 1.0); //FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0);