diff --git a/res/preload.json b/res/preload.json index e3069eef..eb41f40d 100644 --- a/res/preload.json +++ b/res/preload.json @@ -14,6 +14,10 @@ { "name": "ssao", "advanced": true + }, + { + "name": "deferred_lighting", + "advanced": true } ], "textures": [ diff --git a/res/scripts/hud.lua b/res/scripts/hud.lua index e8cc137d..cfeaad66 100644 --- a/res/scripts/hud.lua +++ b/res/scripts/hud.lua @@ -1,14 +1,14 @@ local function configure_SSAO() local slot = gfx.posteffects.index("core:default") gfx.posteffects.set_effect(slot, "ssao") - gfx.posteffects.set_intensity(slot, 1.0) + -- gfx.posteffects.set_intensity(slot, 1.0) -- Generating random SSAO samples local buffer = Bytearray(0) for i = 0, 63 do local x = math.random() * 2.0 - 1.0 local y = math.random() * 2.0 - 1.0 - local z = math.random() + local z = math.random() * 2.0 local len = math.sqrt(x * x + y * y + z * z) if len > 0 then x = x / len @@ -77,4 +77,6 @@ function on_hud_open() player.set_vel(pid, 0, 1, 0) end end) + + configure_SSAO() end diff --git a/res/shaders/effect.glslf b/res/shaders/effect.glslf index 32f69048..792b6c2b 100644 --- a/res/shaders/effect.glslf +++ b/res/shaders/effect.glslf @@ -5,6 +5,7 @@ uniform sampler2D u_screen; uniform sampler2D u_position; uniform sampler2D u_normal; uniform sampler2D u_noise; +uniform sampler2D u_ssao; uniform sampler2D u_shadows; uniform ivec2 u_screenSize; diff --git a/res/shaders/effects/default.glsl b/res/shaders/effects/default.glsl index f7a94851..c2f9effa 100644 --- a/res/shaders/effects/default.glsl +++ b/res/shaders/effects/default.glsl @@ -1,4 +1,3 @@ vec4 effect() { - //return vec4(vec3(pow(texture(u_shadows, v_uv).r, 5.0) * 1000.0), 1.0); return texture(u_screen, v_uv); } diff --git a/res/shaders/effects/deferred_lighting.glsl b/res/shaders/effects/deferred_lighting.glsl new file mode 100644 index 00000000..ea9c32bb --- /dev/null +++ b/res/shaders/effects/deferred_lighting.glsl @@ -0,0 +1,11 @@ +vec4 effect() { + float ssao = 0.0; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + vec2 offset = vec2(x, y) / u_screenSize; + ssao += texture(u_ssao, v_uv + offset * 2.0).r; + } + } + ssao /= 9.0; + return vec4(texture(u_screen, v_uv).rgb * mix(1.0, ssao, 1.0), 1.0); +} diff --git a/res/shaders/effects/ssao.glsl b/res/shaders/effects/ssao.glsl index 3446ecdb..c021b13a 100644 --- a/res/shaders/effects/ssao.glsl +++ b/res/shaders/effects/ssao.glsl @@ -1,13 +1,12 @@ #param vec3 u_ssaoSamples[64] #param int u_kernelSize = 16 -#param float u_radius = 0.25 -#param float u_bias = 0.025 +#param float u_radius = 0.2 +#param float u_bias = 0.006 vec4 effect() { vec2 noiseScale = u_screenSize / 4.0; vec3 position = texture(u_position, v_uv).xyz; - vec3 color = texture(u_screen, v_uv).rgb; vec3 normal = texture(u_normal, v_uv).xyz; vec3 randomVec = normalize(texture(u_noise, v_uv * noiseScale).xyz); @@ -31,7 +30,7 @@ vec4 effect() { } occlusion = min(1.0, 1.05 - (occlusion / u_kernelSize)); - float z = -position.z * 0.02; + float z = -position.z * 0.01; z = max(0.0, 1.0 - z); - return vec4(color * mix(1.0, occlusion, z), 1.0); + return vec4(occlusion, 0.0, 0.0, 1.0); } diff --git a/src/graphics/core/GBuffer.cpp b/src/graphics/core/GBuffer.cpp index 19f6c360..eabca78b 100644 --- a/src/graphics/core/GBuffer.cpp +++ b/src/graphics/core/GBuffer.cpp @@ -84,6 +84,26 @@ void GBuffer::createDepthBuffer() { ); } +void GBuffer::createSSAOBuffer() { + glGenTextures(1, &ssaoBuffer); + glBindTexture(GL_TEXTURE_2D, ssaoBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_R16F, + width, + height, + 0, + GL_RED, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +} + GBuffer::GBuffer(uint width, uint height) : width(width), height(height) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -100,7 +120,20 @@ GBuffer::GBuffer(uint width, uint height) : width(width), height(height) { createDepthBuffer(); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - logger.error() << "framebuffer is not complete!"; + logger.error() << "gbuffer is not complete!"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glGenFramebuffers(1, &ssaoFbo); + glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); + createSSAOBuffer(); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuffer, 0 + ); + GLenum ssaoAttachments[1] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, ssaoAttachments); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + logger.error() << "SSAO framebuffer is not complete!"; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -109,8 +142,10 @@ GBuffer::~GBuffer() { glDeleteTextures(1, &colorBuffer); glDeleteTextures(1, &positionsBuffer); glDeleteTextures(1, &normalsBuffer); + glDeleteTextures(1, &ssaoBuffer); glDeleteRenderbuffers(1, &depthBuffer); glDeleteFramebuffers(1, &fbo); + glDeleteFramebuffers(1, &ssaoFbo); } void GBuffer::bind() { @@ -118,6 +153,11 @@ void GBuffer::bind() { glClear(GL_COLOR_BUFFER_BIT); } +void GBuffer::bindSSAO() const { + glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); + glClear(GL_COLOR_BUFFER_BIT); +} + void GBuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } @@ -133,6 +173,10 @@ void GBuffer::bindBuffers() const { glBindTexture(GL_TEXTURE_2D, colorBuffer); } +void GBuffer::bindSSAOBuffer() const { + glBindTexture(GL_TEXTURE_2D, ssaoBuffer); +} + void GBuffer::resize(uint width, uint height) { if (this->width == width && this->height == height) { return; @@ -180,6 +224,17 @@ void GBuffer::resize(uint width, uint height) { glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); + glBindTexture(GL_TEXTURE_2D, ssaoBuffer); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_FLOAT, nullptr + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuffer, 0 + ); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); } std::unique_ptr GBuffer::toImage() const { diff --git a/src/graphics/core/GBuffer.hpp b/src/graphics/core/GBuffer.hpp index c5e51d4a..7fa66e1a 100644 --- a/src/graphics/core/GBuffer.hpp +++ b/src/graphics/core/GBuffer.hpp @@ -10,9 +10,11 @@ public: ~GBuffer() override; void bind() override; + void bindSSAO() const; void unbind() override; void bindBuffers() const; + void bindSSAOBuffer() const; void resize(uint width, uint height); @@ -29,9 +31,12 @@ private: uint positionsBuffer; uint normalsBuffer; uint depthBuffer; + uint ssaoFbo; + uint ssaoBuffer; void createColorBuffer(); void createPositionsBuffer(); void createNormalsBuffer(); void createDepthBuffer(); + void createSSAOBuffer(); }; diff --git a/src/graphics/core/PostProcessing.cpp b/src/graphics/core/PostProcessing.cpp index 13244c89..4a2608f3 100644 --- a/src/graphics/core/PostProcessing.cpp +++ b/src/graphics/core/PostProcessing.cpp @@ -88,7 +88,9 @@ void PostProcessing::configureEffect( shader.uniform1i("u_position", 1); shader.uniform1i("u_normal", 2); } - shader.uniform1i("u_noise", 3); + shader.uniform1i("u_noise", 3); // used in SSAO pass + shader.uniform1i("u_ssao", 3); + shader.uniform1i("u_shadows", 4); shader.uniform2i("u_screenSize", viewport); shader.uniform1f("u_timer", timer); @@ -126,13 +128,25 @@ void PostProcessing::render( glBindTexture(GL_TEXTURE_2D, noiseTexture); glActiveTexture(GL_TEXTURE0); + + auto& ssaoEffect = assets.require("ssao"); + auto& shader = ssaoEffect.use(); + configureEffect(context, ssaoEffect, shader, timer, camera, shadowMap); + gbuffer->bindSSAO(); + quadMesh->draw(); + gbuffer->unbind(); + + glActiveTexture(GL_TEXTURE3); + gbuffer->bindSSAOBuffer(); } else { glActiveTexture(GL_TEXTURE0); fbo->getTexture()->bind(); } if (totalPasses == 0) { - auto& effect = assets.require("default"); + auto& effect = assets.require( + gbuffer ? "deferred_lighting" : "default" + ); auto& shader = effect.use(); configureEffect(context, effect, shader, timer, camera, shadowMap); quadMesh->draw(); diff --git a/src/logic/scripting/lua/libs/libposteffects.cpp b/src/logic/scripting/lua/libs/libposteffects.cpp index 5e3284bf..acd51953 100644 --- a/src/logic/scripting/lua/libs/libposteffects.cpp +++ b/src/logic/scripting/lua/libs/libposteffects.cpp @@ -17,7 +17,10 @@ static int l_set_effect(lua::State* L) { size_t index = static_cast(lua::tointeger(L, 1)); auto name = lua::require_string(L, 2); auto& assets = *engine->getAssets(); - auto effect = std::make_shared(assets.require(name)); + auto effect = assets.getShared(name); + if (effect == nullptr) { + throw std::runtime_error(std::string("post-effect '") + name + "' not found"); + } post_processing->setEffect(index, std::move(effect)); return 0; }