diff --git a/res/preload.json b/res/preload.json index cac23425..e10d1b68 100644 --- a/res/preload.json +++ b/res/preload.json @@ -6,10 +6,12 @@ "lines", "entity", "background", - "skybox_gen" + "skybox_gen", + "shadows" ], "post-effects": [ - "default" + "default", + "ssao" ], "textures": [ "gui/menubg", diff --git a/res/resources.json b/res/resources.json index 93922266..0311f790 100644 --- a/res/resources.json +++ b/res/resources.json @@ -4,5 +4,8 @@ "third-person-front", "third-person-back", "cinematic" + ], + "post-effect-slot": [ + "default" ] } diff --git a/res/scripts/hud.lua b/res/scripts/hud.lua index 093d43c3..f415cf39 100644 --- a/res/scripts/hud.lua +++ b/res/scripts/hud.lua @@ -55,4 +55,8 @@ function on_hud_open() player.set_vel(pid, 0, 1, 0) end end) + + local slot = gfx.posteffects.index("core:default") + gfx.posteffects.set_effect(slot, "ssao") + --gfx.posteffects.set_intensity(slot, 1.0) end diff --git a/res/shaders/background.glslf b/res/shaders/background.glslf index f7ff07c8..6915e41c 100644 --- a/res/shaders/background.glslf +++ b/res/shaders/background.glslf @@ -1,9 +1,13 @@ in vec3 v_coord; -out vec4 f_color; +layout (location = 0) out vec4 f_color; +layout (location = 1) out vec4 f_position; +layout (location = 2) out vec4 f_normal; uniform samplerCube u_cubemap; void main(){ vec3 dir = normalize(v_coord); + f_position = vec4(100000.0); + f_normal = vec4(0.0); f_color = texture(u_cubemap, dir); } diff --git a/res/shaders/effect.glslf b/res/shaders/effect.glslf index a6325cca..3f7782c6 100644 --- a/res/shaders/effect.glslf +++ b/res/shaders/effect.glslf @@ -2,8 +2,15 @@ in vec2 v_uv; out vec4 f_color; uniform sampler2D u_screen; +uniform sampler2D u_position; +uniform sampler2D u_normal; +uniform sampler2D u_noise; +uniform sampler2D u_shadows; + uniform ivec2 u_screenSize; uniform float u_intensity; +uniform float u_timer; +uniform mat4 u_projection; #include <__effect__> diff --git a/res/shaders/effects/default.glsl b/res/shaders/effects/default.glsl index c2f9effa..1059d29b 100644 --- a/res/shaders/effects/default.glsl +++ b/res/shaders/effects/default.glsl @@ -1,3 +1,50 @@ -vec4 effect() { - return texture(u_screen, v_uv); +uniform vec3 samples[64]; + +int kernelSize = 32; +float radius = 0.25; +float bias = 0.025; + +float near_plane = 0.5f; +float far_plane = 200.0f; + +// required when using a perspective projection matrix +float linearize_depth(float depth) { + float z = depth * 2.0 - 1.0; // Back to NDC + return (2.0 * near_plane * far_plane) / (far_plane + near_plane - z * (far_plane - near_plane)); +} + +float fmod(float x, float y) { + return x - y * floor(x/y); +} + +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); + + vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 TBN = mat3(tangent, bitangent, normal); + + float occlusion = 0.0; + for(int i = 0; i < kernelSize; ++i) + { + vec3 samplePos = TBN * samples[i]; + samplePos = position + samplePos * radius; + + vec4 offset = vec4(samplePos, 1.0); + offset = u_projection * offset; + offset.xyz /= offset.w; + offset.xyz = offset.xyz * 0.5 + 0.5; + + float sampleDepth = texture(u_position, offset.xy).z; + float rangeCheck = smoothstep(0.0, 1.0, radius / abs(position.z - sampleDepth)); + occlusion += (sampleDepth >= samplePos.z + bias ? 1.0 : 0.0) * rangeCheck; + } + occlusion = 1.1 - (occlusion / kernelSize); + float d = texture(u_shadows, v_uv).r; + return vec4(color * occlusion, 1.0); } diff --git a/res/shaders/effects/ssao.glsl b/res/shaders/effects/ssao.glsl new file mode 100644 index 00000000..f7add4f9 --- /dev/null +++ b/res/shaders/effects/ssao.glsl @@ -0,0 +1,11 @@ +uniform vec3 samples[64]; + +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 = texture(u_noise, v_uv * noiseScale).xyz; + return vec4(randomVec, 1.0); +} diff --git a/res/shaders/entity.glslf b/res/shaders/entity.glslf index e7a8a754..3d2a251a 100644 --- a/res/shaders/entity.glslf +++ b/res/shaders/entity.glslf @@ -1,8 +1,13 @@ in vec4 a_color; in vec2 a_texCoord; +in vec3 a_position; in vec3 a_dir; +in vec3 a_normal; in float a_fog; -out vec4 f_color; + +layout (location = 0) out vec4 f_color; +layout (location = 1) out vec4 f_position; +layout (location = 2) out vec4 f_normal; uniform sampler2D u_texture0; uniform samplerCube u_cubemap; @@ -20,4 +25,6 @@ void main() { discard; f_color = mix(a_color * tex_color, vec4(fogColor,1.0), a_fog); f_color.a = alpha; + f_position = vec4(a_position, 1.0); + f_normal = vec4(a_normal, 1.0); } diff --git a/res/shaders/entity.glslv b/res/shaders/entity.glslv index 3d916e9a..57ed9866 100644 --- a/res/shaders/entity.glslv +++ b/res/shaders/entity.glslv @@ -7,7 +7,9 @@ layout (location = 3) in vec4 v_light; out vec4 a_color; out vec2 a_texCoord; +out vec3 a_normal; out float a_fog; +out vec3 a_position; out vec3 a_dir; uniform mat4 u_model; @@ -31,6 +33,8 @@ void main() { vec3 pos3d = modelpos.xyz - u_cameraPos; modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); + a_normal = vec3(0.0, 1.0, 0.0);//v_normal.xyz * 2.0 - 1.0; + vec3 light = v_light.rgb; float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / u_torchlightDistance); @@ -48,4 +52,6 @@ void main() { a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve), min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity))); gl_Position = u_proj * u_view * modelpos; + + a_position = (u_view * modelpos).xyz; } diff --git a/res/shaders/main.glslf b/res/shaders/main.glslf index d856acc2..837ffaf1 100644 --- a/res/shaders/main.glslf +++ b/res/shaders/main.glslf @@ -1,19 +1,53 @@ +layout (location = 0) out vec4 f_color; +layout (location = 1) out vec4 f_position; +layout (location = 2) out vec4 f_normal; + in vec4 a_color; in vec2 a_texCoord; in float a_fog; +in vec3 a_position; in vec3 a_dir; -out vec4 f_color; +in vec3 a_normal; +in vec3 a_realnormal; +in vec4 a_modelpos; uniform sampler2D u_texture0; uniform samplerCube u_cubemap; +uniform sampler2DShadow u_shadows; + +// flags uniform bool u_alphaClip; uniform bool u_debugLights; +uniform bool u_debugNormals; +uniform bool u_enableShadows; + +uniform mat4 u_shadowsMatrix; + +const int BLUR_SAMPLES = 6; void main() { + float shadow = 1.0; + if (u_enableShadows) { + vec4 mpos = u_shadowsMatrix * vec4(a_modelpos.xyz, 1.0); + vec3 projCoords = mpos.xyz / mpos.w; + projCoords = projCoords * 0.5 + 0.5; + projCoords.z -= 0.0001; + + shadow = 0.0; + + for (int i = 0; i < BLUR_SAMPLES; i++) { + shadow += texture(u_shadows, projCoords.xyz + vec3( + -0.002*(i%2==0?1:0)*i/BLUR_SAMPLES, + -0.002*(i%2==0?0:1)*i/BLUR_SAMPLES, + -0.0005 * i/BLUR_SAMPLES)); + } + shadow /= BLUR_SAMPLES; + shadow += 0.5; + shadow = shadow * 0.7 + 0.3; + } + vec3 fogColor = texture(u_cubemap, a_dir).rgb; vec4 tex_color = texture(u_texture0, a_texCoord); - if (u_debugLights) - tex_color.rgb = vec3(1.0); float alpha = a_color.a * tex_color.a; if (u_alphaClip) { if (alpha < 0.2f) @@ -23,6 +57,14 @@ void main() { if (alpha < 0.002f) discard; } + if (u_debugLights) + tex_color.rgb = u_debugNormals ? (a_normal * 0.5 + 0.5) : vec3(1.0); + else if (u_debugNormals) { + tex_color.rgb *= a_normal * 0.5 + 0.5; + } f_color = mix(a_color * tex_color, vec4(fogColor,1.0), a_fog); + f_color.rgb *= shadow; f_color.a = alpha; + f_position = vec4(a_position, 1.0); + f_normal = vec4(a_normal, 1.0); } diff --git a/res/shaders/main.glslv b/res/shaders/main.glslv index 24ec6cae..ab77d17b 100644 --- a/res/shaders/main.glslv +++ b/res/shaders/main.glslv @@ -3,12 +3,17 @@ layout (location = 0) in vec3 v_position; layout (location = 1) in vec2 v_texCoord; layout (location = 2) in vec4 v_light; +layout (location = 3) in vec4 v_normal; out vec4 a_color; out vec2 a_texCoord; +out vec3 a_normal; out float a_distance; out float a_fog; +out vec3 a_position; +out vec4 a_modelpos; out vec3 a_dir; +out vec3 a_realnormal; uniform mat4 u_model; uniform mat4 u_proj; @@ -25,12 +30,19 @@ uniform samplerCube u_cubemap; uniform vec3 u_torchlightColor; uniform float u_torchlightDistance; +uniform bool u_enableShadows; void main() { vec4 modelpos = u_model * vec4(v_position, 1.0f); vec3 pos3d = modelpos.xyz-u_cameraPos; modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); + a_realnormal = v_normal.xyz; + mat3 normalMatrix = transpose(inverse(mat3(u_view * u_model))); + a_normal = v_normal.xyz * 2.0 - 1.0; + a_normal = normalMatrix * (false ? -a_normal : a_normal); + //a_normal = v_normal.xyz * 2.0 - 1.0; + vec3 light = v_light.rgb; float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / u_torchlightDistance); @@ -47,4 +59,7 @@ void main() { a_fog = min(1.0, max(pow(depth * u_fogFactor, u_fogCurve), min(pow(depth * u_weatherFogDencity, u_weatherFogCurve), u_weatherFogOpacity))); gl_Position = u_proj * u_view * modelpos; + + a_position = (u_view * modelpos).xyz; + a_modelpos = modelpos; } diff --git a/res/shaders/shadows.glslf b/res/shaders/shadows.glslf new file mode 100644 index 00000000..53d6f5d2 --- /dev/null +++ b/res/shaders/shadows.glslf @@ -0,0 +1,11 @@ +in vec2 a_texCoord; + +uniform sampler2D u_texture0; + +void main() { + vec4 tex_color = texture(u_texture0, a_texCoord); + if (tex_color.a < 0.5) { + discard; + } + // depth will be written anyway +} diff --git a/res/shaders/shadows.glslv b/res/shaders/shadows.glslv new file mode 100644 index 00000000..4d4094ac --- /dev/null +++ b/res/shaders/shadows.glslv @@ -0,0 +1,17 @@ +#include + +layout (location = 0) in vec3 v_position; +layout (location = 1) in vec2 v_texCoord; +layout (location = 2) in vec4 v_light; +layout (location = 3) in vec4 v_normal; + +out vec2 a_texCoord; + +uniform mat4 u_model; +uniform mat4 u_proj; +uniform mat4 u_view; + +void main() { + a_texCoord = v_texCoord; + gl_Position = u_proj * u_view * u_model * vec4(v_position, 1.0f); +} diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index ced38093..74003b2b 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -178,6 +178,8 @@ Hud::Hud(Engine& engine, LevelFrontend& frontend, Player& player) uicamera = std::make_unique(glm::vec3(), 1); uicamera->perspective = false; uicamera->flipped = true; + uicamera->near = -1.0f; + uicamera->far = 1.0f; debugPanel = create_debug_panel( engine, frontend.getLevel(), player, allowDebugCheats diff --git a/src/frontend/screens/MenuScreen.cpp b/src/frontend/screens/MenuScreen.cpp index f7e091ba..be114ed3 100644 --- a/src/frontend/screens/MenuScreen.cpp +++ b/src/frontend/screens/MenuScreen.cpp @@ -22,6 +22,8 @@ MenuScreen::MenuScreen(Engine& engine) : Screen(engine) { uicamera = std::make_unique(glm::vec3(), engine.getWindow().getSize().y); uicamera->perspective = false; + uicamera->near = -1.0f; + uicamera->far = 1.0f; uicamera->flipped = true; } diff --git a/src/graphics/core/DrawContext.cpp b/src/graphics/core/DrawContext.cpp index 6bb0115d..fc37fd46 100644 --- a/src/graphics/core/DrawContext.cpp +++ b/src/graphics/core/DrawContext.cpp @@ -100,7 +100,7 @@ void DrawContext::setViewport(const glm::uvec2& viewport) { glViewport(0, 0, viewport.x, viewport.y); } -void DrawContext::setFramebuffer(Framebuffer* fbo) { +void DrawContext::setFramebuffer(Bindable* fbo) { if (this->fbo == fbo) return; this->fbo = fbo; diff --git a/src/graphics/core/DrawContext.hpp b/src/graphics/core/DrawContext.hpp index 7e1e18d5..ce52b99a 100644 --- a/src/graphics/core/DrawContext.hpp +++ b/src/graphics/core/DrawContext.hpp @@ -16,7 +16,7 @@ class DrawContext { glm::uvec2 viewport; Batch2D* g2d; Flushable* flushable = nullptr; - Framebuffer* fbo = nullptr; + Bindable* fbo = nullptr; bool depthMask = true; bool depthTest = false; bool cullFace = false; @@ -37,7 +37,7 @@ public: DrawContext sub(Flushable* flushable=nullptr) const; void setViewport(const glm::uvec2& viewport); - void setFramebuffer(Framebuffer* fbo); + void setFramebuffer(Bindable* fbo); void setDepthMask(bool flag); void setDepthTest(bool flag); void setCullFace(bool flag); diff --git a/src/graphics/core/Framebuffer.cpp b/src/graphics/core/Framebuffer.cpp index b0a452f4..c8ed0c42 100644 --- a/src/graphics/core/Framebuffer.cpp +++ b/src/graphics/core/Framebuffer.cpp @@ -2,6 +2,9 @@ #include #include "Texture.hpp" +#include "debug/Logger.hpp" + +static debug::Logger logger("gl-framebuffer"); Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr texture) : fbo(fbo), depth(depth), texture(std::move(texture)) @@ -38,18 +41,41 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha) // Setup color attachment (texture) texture = create_texture(width, height, format); - + + glGenTextures(1, &positions); + glBindTexture(GL_TEXTURE_2D, positions); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positions, 0); + + glGenTextures(1, &normals); + glBindTexture(GL_TEXTURE_2D, normals); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normals, 0); + + unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; + glDrawBuffers(3, attachments); + // Setup depth attachment glGenRenderbuffers(1, &depth); glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + logger.error() << "framebuffer is not complete!"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); } Framebuffer::~Framebuffer() { glDeleteFramebuffers(1, &fbo); - glDeleteRenderbuffers(1, &depth); + glDeleteTextures(1, &normals); + glDeleteTextures(1, &depth); } void Framebuffer::bind() { @@ -60,6 +86,19 @@ void Framebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void Framebuffer::bindBuffers() { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->getId()); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, positions); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, normals); + + glActiveTexture(GL_TEXTURE0); +} + void Framebuffer::resize(uint width, uint height) { if (this->width == width && this->height == height) { return; @@ -67,11 +106,22 @@ void Framebuffer::resize(uint width, uint height) { this->width = width; this->height = height; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glBindRenderbuffer(GL_RENDERBUFFER, depth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glBindTexture(GL_TEXTURE_2D, positions); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positions, 0); + + glBindTexture(GL_TEXTURE_2D, normals); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normals, 0); + + glBindTexture(GL_TEXTURE_2D, 0); + texture = create_texture(width, height, format); glBindFramebuffer(GL_FRAMEBUFFER, 0); } diff --git a/src/graphics/core/Framebuffer.hpp b/src/graphics/core/Framebuffer.hpp index 795ca2c4..35df9ffa 100644 --- a/src/graphics/core/Framebuffer.hpp +++ b/src/graphics/core/Framebuffer.hpp @@ -1,14 +1,17 @@ #pragma once #include "typedefs.hpp" +#include "commons.hpp" #include class Texture; -class Framebuffer { +class Framebuffer : public Bindable { uint fbo; uint depth; + uint positions; + uint normals; uint width; uint height; uint format; @@ -19,10 +22,12 @@ public: ~Framebuffer(); /// @brief Use framebuffer - void bind(); + void bind() override; /// @brief Stop using framebuffer - void unbind(); + void unbind() override; + + void bindBuffers(); /// @brief Update framebuffer texture size /// @param width new width diff --git a/src/graphics/core/GBuffer.cpp b/src/graphics/core/GBuffer.cpp new file mode 100644 index 00000000..f504287e --- /dev/null +++ b/src/graphics/core/GBuffer.cpp @@ -0,0 +1,186 @@ +#include "GBuffer.hpp" + +#include + +#include "debug/Logger.hpp" + +static debug::Logger logger("gl-gbuffer"); + +void GBuffer::createColorBuffer() { + glGenTextures(1, &colorBuffer); + glBindTexture(GL_TEXTURE_2D, colorBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width, + height, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 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); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0 + ); +} + +void GBuffer::createPositionsBuffer() { + glGenTextures(1, &positionsBuffer); + glBindTexture(GL_TEXTURE_2D, positionsBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA16F, + width, + height, + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positionsBuffer, 0 + ); +} + +void GBuffer::createNormalsBuffer() { + glGenTextures(1, &normalsBuffer); + glBindTexture(GL_TEXTURE_2D, normalsBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA16F, + width, + height, + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normalsBuffer, 0 + ); +} + +void GBuffer::createDepthBuffer() { + glGenRenderbuffers(1, &depthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer + ); +} + +GBuffer::GBuffer(uint width, uint height) : width(width), height(height) { + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + createColorBuffer(); + createPositionsBuffer(); + createNormalsBuffer(); + + GLenum attachments[3] = { + GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 + }; + glDrawBuffers(3, attachments); + + createDepthBuffer(); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + logger.error() << "framebuffer is not complete!"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +GBuffer::~GBuffer() { + glDeleteTextures(1, &colorBuffer); + glDeleteTextures(1, &positionsBuffer); + glDeleteTextures(1, &normalsBuffer); + glDeleteRenderbuffers(1, &depthBuffer); + glDeleteFramebuffers(1, &fbo); +} + +void GBuffer::bind() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); +} + +void GBuffer::unbind() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void GBuffer::bindBuffers() { + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, normalsBuffer); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, positionsBuffer); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, colorBuffer); +} + +void GBuffer::resize(uint width, uint height) { + if (this->width == width && this->height == height) { + return; + } + this->width = width; + this->height = height; + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindTexture(GL_TEXTURE_2D, colorBuffer); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + width, + height, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + nullptr + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0 + ); + + glBindTexture(GL_TEXTURE_2D, positionsBuffer); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positionsBuffer, 0 + ); + + glBindTexture(GL_TEXTURE_2D, normalsBuffer); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normalsBuffer, 0 + ); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +uint GBuffer::getWidth() const { + return width; +} + +uint GBuffer::getHeight() const { + return height; +} diff --git a/src/graphics/core/GBuffer.hpp b/src/graphics/core/GBuffer.hpp new file mode 100644 index 00000000..6269c542 --- /dev/null +++ b/src/graphics/core/GBuffer.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "typedefs.hpp" +#include "commons.hpp" + +class GBuffer : public Bindable{ +public: + GBuffer(uint width, uint height); + ~GBuffer(); + + void bind() override; + void unbind() override; + + void bindBuffers(); + + void resize(uint width, uint height); + + uint getWidth() const; + uint getHeight() const; +private: + uint width; + uint height; + + uint fbo; + uint colorBuffer; + uint positionsBuffer; + uint normalsBuffer; + uint depthBuffer; + + void createColorBuffer(); + void createPositionsBuffer(); + void createNormalsBuffer(); + void createDepthBuffer(); +}; diff --git a/src/graphics/core/PostProcessing.cpp b/src/graphics/core/PostProcessing.cpp index 2968cb4d..c1b6dc96 100644 --- a/src/graphics/core/PostProcessing.cpp +++ b/src/graphics/core/PostProcessing.cpp @@ -6,22 +6,56 @@ #include "DrawContext.hpp" #include "PostEffect.hpp" #include "assets/Assets.hpp" +#include "window/Camera.hpp" #include +#include PostProcessing::PostProcessing(size_t effectSlotsCount) : effectSlots(effectSlotsCount) { // Fullscreen quad mesh bulding - PostProcessingVertex meshData[]{ - {{-1.0f, -1.0f}}, - {{-1.0f, 1.0f}}, - {{1.0f, 1.0f}}, - {{-1.0f, -1.0f}}, - {{1.0f, 1.0f}}, - {{1.0f, -1.0f}}, + PostProcessingVertex meshData[] { + {{-1.0f, -1.0f}}, + {{-1.0f, 1.0f}}, + {{1.0f, 1.0f}}, + {{-1.0f, -1.0f}}, + {{1.0f, 1.0f}}, + {{1.0f, -1.0f}}, }; quadMesh = std::make_unique>(meshData, 6); + + std::vector ssaoNoise; + for (unsigned int i = 0; i < 16; i++) + { + glm::vec3 noise( + (rand() / static_cast(RAND_MAX)) * 2.0 - 1.0, + (rand() / static_cast(RAND_MAX)) * 2.0 - 1.0, + 0.0f); + ssaoNoise.push_back(noise); + } + glGenTextures(1, &noiseTexture); + glBindTexture(GL_TEXTURE_2D, noiseTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, ssaoNoise.data()); + 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); + glBindTexture(GL_TEXTURE_2D, 0); + + std::uniform_real_distribution randomFloats(0.0, 1.0); + std::default_random_engine generator; + for (unsigned int i = 0; i < 64; ++i) + { + glm::vec3 sample( + randomFloats(generator) * 2.0 - 1.0, + randomFloats(generator) * 2.0 - 1.0, + randomFloats(generator) + ); + sample = glm::normalize(sample); + sample *= randomFloats(generator); + ssaoKernel.push_back(sample); + } } PostProcessing::~PostProcessing() = default; @@ -39,7 +73,7 @@ void PostProcessing::use(DrawContext& context) { } void PostProcessing::render( - const DrawContext& context, const Assets& assets, float timer + const DrawContext& context, const Assets& assets, float timer, const Camera& camera, uint depthMap ) { if (fbo == nullptr) { throw std::runtime_error("'use(...)' was never called"); @@ -51,8 +85,38 @@ void PostProcessing::render( if (totalPasses == 0) { auto& effect = assets.require("default"); - effect.use(); fbo->getTexture()->bind(); + fbo->bindBuffers(); + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, noiseTexture); + glActiveTexture(GL_TEXTURE0); + + glActiveTexture(GL_TEXTURE4); + glBindTexture(GL_TEXTURE_2D, depthMap); + glActiveTexture(GL_TEXTURE0); + + const auto& viewport = context.getViewport(); + + auto& shader = effect.use(); + if (!ssaoConfigured) { + for (unsigned int i = 0; i < 64; ++i) { + auto name = "samples["+ std::to_string(i) + "]"; + shader.uniform3f(name, ssaoKernel[i]); + } + ssaoConfigured = true; + } + shader.uniform1i("u_screen", 0); + shader.uniform1i("u_position", 1); + shader.uniform1i("u_normal", 2); + shader.uniform1i("u_noise", 3); + shader.uniform1i("u_shadows", 4); + shader.uniform2i("u_screenSize", viewport); + shader.uniform1f("u_timer", timer); + shader.uniform1f("near_plane", camera.near); + shader.uniform1f("far_plane", camera.far); + shader.uniformMatrix("u_projection", camera.getProjection()); + quadMesh->draw(); return; } @@ -64,15 +128,25 @@ void PostProcessing::render( } auto& shader = effect->use(); + for (unsigned int i = 0; i < 64; ++i) { + shader.uniform3f("samples["+ std::to_string(i) + "]", ssaoKernel[i]); + } + const auto& viewport = context.getViewport(); shader.uniform1i("u_screen", 0); + shader.uniform1i("u_position", 1); + shader.uniform1i("u_normal", 2); + shader.uniform1i("u_noise", 3); shader.uniform2i("u_screenSize", viewport); shader.uniform1f("u_timer", timer); - + shader.uniformMatrix("u_projection", camera.getProjView(false)); fbo->getTexture()->bind(); + fbo->bindBuffers(); + if (currentPass < totalPasses) { fboSecond->bind(); } + quadMesh->draw(); if (currentPass < totalPasses) { fboSecond->unbind(); diff --git a/src/graphics/core/PostProcessing.hpp b/src/graphics/core/PostProcessing.hpp index c6b3ae14..a90d8abc 100644 --- a/src/graphics/core/PostProcessing.hpp +++ b/src/graphics/core/PostProcessing.hpp @@ -11,6 +11,7 @@ class Framebuffer; class DrawContext; class ImageData; class PostEffect; +class Camera; struct PostProcessingVertex { glm::vec2 position; @@ -30,6 +31,10 @@ class PostProcessing { /// @brief Fullscreen quad mesh as the post-processing canvas std::unique_ptr> quadMesh; std::vector> effectSlots; + + std::vector ssaoKernel; + uint noiseTexture; + bool ssaoConfigured = false; public: PostProcessing(size_t effectSlotsCount); ~PostProcessing(); @@ -42,7 +47,7 @@ public: /// with framebuffer texture bound /// @param context graphics context /// @throws std::runtime_error if use(...) wasn't called before - void render(const DrawContext& context, const Assets& assets, float timer); + void render(const DrawContext& context, const Assets& assets, float timer, const Camera& camera, uint depthMap); void setEffect(size_t slot, std::shared_ptr effect); diff --git a/src/graphics/core/ShadowMap.cpp b/src/graphics/core/ShadowMap.cpp new file mode 100644 index 00000000..e5032d8b --- /dev/null +++ b/src/graphics/core/ShadowMap.cpp @@ -0,0 +1,47 @@ +#include "ShadowMap.hpp" + +#include + +ShadowMap::ShadowMap(int resolution) : resolution(resolution) { + glGenTextures(1, &depthMap); + glBindTexture(GL_TEXTURE_2D, depthMap); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, + resolution, resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + 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_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + float border[4] {1.0f, 1.0f, 1.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR, border); + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +ShadowMap::~ShadowMap() { + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &depthMap); +} + +void ShadowMap::bind() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glClear(GL_DEPTH_BUFFER_BIT); +} + +void ShadowMap::unbind() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +uint ShadowMap::getDepthMap() const { + return depthMap; +} + +int ShadowMap::getResolution() const { + return resolution; +} diff --git a/src/graphics/core/ShadowMap.hpp b/src/graphics/core/ShadowMap.hpp new file mode 100644 index 00000000..828c51aa --- /dev/null +++ b/src/graphics/core/ShadowMap.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "typedefs.hpp" + +class ShadowMap { +public: + ShadowMap(int resolution); + ~ShadowMap(); + + void bind(); + void unbind(); + uint getDepthMap() const; + int getResolution() const; +private: + uint fbo; + uint depthMap; + int resolution; +}; diff --git a/src/graphics/core/commons.hpp b/src/graphics/core/commons.hpp index 7c26b75b..2ed03db1 100644 --- a/src/graphics/core/commons.hpp +++ b/src/graphics/core/commons.hpp @@ -69,3 +69,11 @@ public: virtual void flush() = 0; }; + +class Bindable { +public: + virtual ~Bindable() = default; + + virtual void bind() = 0; + virtual void unbind() = 0; +}; diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 3baeb0e4..2ed50ce1 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -10,7 +10,7 @@ #include "frontend/ContentGfxCache.hpp" const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265f, 0.833149f, -0.163704f); -const float DIRECTIONAL_LIGHT_FACTOR = 0.3f; +const float DIRECTIONAL_LIGHT_FACTOR = 0.2f; BlocksRenderer::BlocksRenderer( size_t capacity, @@ -39,13 +39,17 @@ BlocksRenderer::~BlocksRenderer() { /// Basic vertex add method void BlocksRenderer::vertex( - const glm::vec3& coord, float u, float v, const glm::vec4& light + const glm::vec3& coord, float u, float v, const glm::vec4& light, const glm::vec3& normal ) { vertexBuffer[vertexCount].position = coord; vertexBuffer[vertexCount].uv = {u,v}; + vertexBuffer[vertexCount].normal[0] = static_cast(normal.r * 127 + 128); + vertexBuffer[vertexCount].normal[1] = static_cast(normal.g * 127 + 128); + vertexBuffer[vertexCount].normal[2] = static_cast(normal.b * 127 + 128); + vertexBuffer[vertexCount].color[0] = static_cast(light.r * 255); vertexBuffer[vertexCount].color[1] = static_cast(light.g * 255); vertexBuffer[vertexCount].color[2] = static_cast(light.b * 255); @@ -82,10 +86,10 @@ void BlocksRenderer::face( auto Y = axisY * h; auto Z = axisZ * d; float s = 0.5f; - vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, lights[0] * tint); - vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, lights[1] * tint); - vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint); - vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * tint); + vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, lights[0] * tint, axisZ); + vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, lights[1] * tint, axisZ); + vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, lights[2] * tint, axisZ); + vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, lights[3] * tint, axisZ); index(0, 1, 3, 1, 2, 3); } @@ -103,7 +107,7 @@ void BlocksRenderer::vertexAO( axisX, axisY ); - vertex(coord, u, v, light * tint); + vertex(coord, u, v, light * tint, axisZ); } void BlocksRenderer::faceAO( @@ -134,11 +138,12 @@ void BlocksRenderer::faceAO( vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ); vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ); } else { + auto axisZ = glm::normalize(Z); glm::vec4 tint(1.0f); - vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); - vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint); - vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint); - vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint); + vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisZ); + vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisZ); + vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisZ); + vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisZ); } index(0, 1, 2, 0, 2, 3); } @@ -163,10 +168,10 @@ void BlocksRenderer::face( d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR; tint *= d; } - vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); - vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint); - vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint); - vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint); + vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, Z); + vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, Z); + vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, Z); + vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, Z); index(0, 1, 2, 0, 2, 3); } @@ -337,7 +342,8 @@ void BlocksRenderer::blockCustomModel( coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, vertex.uv.x, vertex.uv.y, - glm::vec4(d, d, d, d) * aoColor + glm::vec4(d, d, d, d) * aoColor, + n ); indexBuffer[indexCount++] = vertexOffset++; } diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 1edcbfcc..0bb9b31d 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -44,7 +44,7 @@ class BlocksRenderer { SortingMeshData sortingMesh; - void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); + void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light, const glm::vec3& normal); void index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f); void vertexAO( diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 199d818b..5cc7e81c 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -143,7 +143,7 @@ void ChunksRenderer::update() { } const Mesh* ChunksRenderer::retrieveChunk( - size_t index, const Camera& camera, Shader& shader, bool culling + size_t index, const Camera& camera, bool culling ) { auto chunk = chunks.getChunks()[index]; if (chunk == nullptr) { @@ -219,7 +219,7 @@ void ChunksRenderer::drawChunks( // TODO: minimize draw calls number for (int i = indices.size()-1; i >= 0; i--) { auto& chunk = chunks.getChunks()[indices[i].index]; - auto mesh = retrieveChunk(indices[i].index, camera, shader, culling); + auto mesh = retrieveChunk(indices[i].index, camera, culling); if (mesh) { glm::vec3 coord( diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index aa9833af..4efb9792 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -50,7 +50,7 @@ class ChunksRenderer { std::vector indices; util::ThreadPool, RendererResult> threadPool; const Mesh* retrieveChunk( - size_t index, const Camera& camera, Shader& shader, bool culling + size_t index, const Camera& camera, bool culling ); public: ChunksRenderer( diff --git a/src/graphics/render/Skybox.cpp b/src/graphics/render/Skybox.cpp index d78b3917..67b4efec 100644 --- a/src/graphics/render/Skybox.cpp +++ b/src/graphics/render/Skybox.cpp @@ -136,8 +136,8 @@ void Skybox::draw( batch3d->sprite(pos, glm::vec3(0, 0, 1), up, 1, 1, UVRegion(), tint); } - - drawStars(angle, opacity); + batch3d->flush(); + //drawStars(angle, opacity); } void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) { diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 20640a78..c74ff31b 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -41,6 +41,8 @@ #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" #include "graphics/core/Font.hpp" +#include "graphics/core/ShadowMap.hpp" +#include "graphics/core/GBuffer.hpp" #include "BlockWrapsRenderer.hpp" #include "ParticlesRenderer.hpp" #include "PrecipitationRenderer.hpp" @@ -100,6 +102,10 @@ WorldRenderer::WorldRenderer( settings.graphics.skyboxResolution.get(), assets->require("skybox_gen") ); + + shadowMap = std::make_unique(1024); + + shadowCamera = std::make_unique(); } WorldRenderer::~WorldRenderer() = default; @@ -119,6 +125,7 @@ void WorldRenderer::setupWorldShader( shader.uniform1f("u_fogFactor", fogFactor); shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); shader.uniform1i("u_debugLights", lightsDebug); + shader.uniform1i("u_debugNormals", false); shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity()); shader.uniform1f("u_weatherFogDencity", weather.fogDencity()); shader.uniform1f("u_weatherFogCurve", weather.fogCurve()); @@ -126,6 +133,15 @@ void WorldRenderer::setupWorldShader( shader.uniform2f("u_lightDir", skybox->getLightDir()); shader.uniform3f("u_cameraPos", camera.position); shader.uniform1i("u_cubemap", 1); + shader.uniform1i("u_enableShadows", gbufferPipeline); + + if (gbufferPipeline) { + shader.uniformMatrix("u_shadowsMatrix", shadowCamera->getProjView()); + glActiveTexture(GL_TEXTURE4); + shader.uniform1i("u_shadows", 4); + glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthMap()); + glActiveTexture(GL_TEXTURE0); + } auto indices = level.content.getIndices(); // Light emission when an emissive item is chosen @@ -354,10 +370,52 @@ void WorldRenderer::draw( const auto& assets = *engine.getAssets(); auto& linesShader = assets.require("lines"); + auto& shadowsShader = assets.require("shadows"); + + if (gbufferPipeline) { + float shadowMapScale = 0.05f; + float shadowMapSize = shadowMap->getResolution() * shadowMapScale; + *shadowCamera = Camera(camera.position, shadowMapSize); + shadowCamera->near = 0.5f; + shadowCamera->far = 600.0f; + shadowCamera->perspective = false; + shadowCamera->setAspectRatio(1.0f); + shadowCamera->rotate(glm::radians(-65.0f), glm::radians(-35.0f), glm::radians(-35.0f)); + //shadowCamera.perspective = false; + /*shadowCamera.rotation = //glm::inverse( + glm::lookAt({}, glm::normalize(shadowCamera.position-camera.position), glm::vec3(0, 1, 0)); + //);*/ + shadowCamera->updateVectors(); + //shadowCamera->position += camera.dir * shadowMapSize * 0.5f; + shadowCamera->position -= shadowCamera->front * 100.0f; + shadowCamera->position -= shadowCamera->right * (shadowMap->getResolution() * shadowMapScale) * 0.5f; + shadowCamera->position -= shadowCamera->up * (shadowMap->getResolution() * shadowMapScale) * 0.5f; + shadowCamera->position = glm::floor(shadowCamera->position); + { + frustumCulling->update(shadowCamera->getProjView()); + auto sctx = pctx.sub(); + sctx.setDepthTest(true); + sctx.setCullFace(true); + sctx.setViewport({shadowMap->getResolution(), shadowMap->getResolution()}); + shadowMap->bind(); + setupWorldShader(shadowsShader, *shadowCamera, settings, 0.0f); + chunks->drawChunks(*shadowCamera, shadowsShader); + shadowMap->unbind(); + } + } /* World render scope with diegetic HUD included */ { DrawContext wctx = pctx.sub(); - postProcessing.use(wctx); + if (gbufferPipeline) { + if (gbuffer == nullptr) { + gbuffer = std::make_unique(vp.x, vp.y); + } else { + gbuffer->resize(vp.x, vp.y); + } + wctx.setFramebuffer(gbuffer.get()); + } else { + postProcessing.use(wctx); + } display::clearDepth(); @@ -370,25 +428,25 @@ void WorldRenderer::draw( ctx.setCullFace(true); renderLevel(ctx, camera, settings, uiDelta, pause, hudVisible); // Debug lines - if (hudVisible) { - if (debug) { - guides->renderDebugLines( - ctx, camera, *lineBatch, linesShader, showChunkBorders - ); - } - if (player.currentCamera == player.fpCamera) { - renderHands(camera, delta); - } - } + // if (hudVisible) { + // if (debug) { + // guides->renderDebugLines( + // ctx, camera, *lineBatch, linesShader, showChunkBorders + // ); + // } + // if (player.currentCamera == player.fpCamera) { + // renderHands(camera, delta); + // } + // } } - { - DrawContext ctx = wctx.sub(); - texts->render(ctx, camera, settings, hudVisible, true); - } - renderBlockOverlay(wctx); + // { + // DrawContext ctx = wctx.sub(); + // texts->render(ctx, camera, settings, hudVisible, true); + // } + //renderBlockOverlay(wctx); } - postProcessing.render(pctx, assets, timer); + postProcessing.render(pctx, assets, timer, camera, shadowMap->getDepthMap()); } void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index fbfd4998..9759dd39 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -30,6 +30,8 @@ class PostProcessing; class DrawContext; class ModelBatch; class Assets; +class ShadowMap; +class GBuffer; struct EngineSettings; class WorldRenderer { @@ -44,12 +46,18 @@ class WorldRenderer { std::unique_ptr guides; std::unique_ptr chunks; std::unique_ptr skybox; + std::unique_ptr shadowMap; Weather weather {}; + + std::unique_ptr shadowCamera; float timer = 0.0f; bool debug = false; bool lightsDebug = false; + std::unique_ptr gbuffer; + bool gbufferPipeline = false; + /// @brief Render block selection lines void renderBlockSelection(); diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index cfc2f16c..905e34cc 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -14,11 +14,13 @@ struct ChunkVertex { glm::vec3 position; glm::vec2 uv; std::array color; + std::array normal; static constexpr VertexAttribute ATTRIBUTES[] = { {VertexAttribute::Type::FLOAT, false, 3}, {VertexAttribute::Type::FLOAT, false, 2}, {VertexAttribute::Type::UNSIGNED_BYTE, true, 4}, + {VertexAttribute::Type::UNSIGNED_BYTE, true, 4}, {{}, 0}}; }; diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index dc379a68..0cea8a66 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -38,6 +38,8 @@ GUI::GUI(Engine& engine) std::make_unique(glm::vec3(), engine.getWindow().getSize().y); uicamera->perspective = false; uicamera->flipped = true; + uicamera->near = -1.0f; + uicamera->far = 1.0f; menu = std::make_shared(*this); menu->setId("menu"); diff --git a/src/window/Camera.cpp b/src/window/Camera.cpp index 14939740..1854ff0e 100644 --- a/src/window/Camera.cpp +++ b/src/window/Camera.cpp @@ -31,9 +31,9 @@ glm::mat4 Camera::getProjection() const { if (perspective) { return glm::perspective(fov * zoom, ar, near, far); } else if (flipped) { - return glm::ortho(0.0f, fov * ar, fov, 0.0f); + return glm::ortho(0.0f, fov * ar, fov, 0.0f, near, far); } else { - return glm::ortho(0.0f, fov * ar, 0.0f, fov); + return glm::ortho(0.0f, fov * ar, 0.0f, fov, near, far); } } @@ -45,7 +45,8 @@ glm::mat4 Camera::getView(bool pos) const { if (perspective) { return glm::lookAt(camera_pos, camera_pos + front, up); } else { - return glm::translate(glm::mat4(1.0f), camera_pos); + return glm::lookAt(camera_pos, camera_pos + front, up); + //return glm::translate(glm::mat4(1.0f), camera_pos); } }