diff --git a/resources/shaders/fragment/depth.glsl b/resources/shaders/fragment/depth.glsl index 3d6dfc27..e94a6b32 100644 --- a/resources/shaders/fragment/depth.glsl +++ b/resources/shaders/fragment/depth.glsl @@ -1,9 +1,9 @@ #version 330 core -in float FragDepth; +in float VertexDepth; out float FragValue; void main() { - FragValue = FragDepth; + FragValue = VertexDepth; } diff --git a/resources/shaders/fragment/distance.glsl b/resources/shaders/fragment/distance.glsl index e35ef12d..d5652933 100644 --- a/resources/shaders/fragment/distance.glsl +++ b/resources/shaders/fragment/distance.glsl @@ -5,5 +5,5 @@ in vec3 FragPos; out float FragValue; void main() { - FragValue = length(FragPos);// / 30.0; + FragValue = length(FragPos); } diff --git a/resources/shaders/fragment/normal.glsl b/resources/shaders/fragment/normal.glsl new file mode 100644 index 00000000..7aa40a52 --- /dev/null +++ b/resources/shaders/fragment/normal.glsl @@ -0,0 +1,9 @@ +#version 330 core + +in vec3 Normal; + +out vec3 NormalOut; + +void main() { + NormalOut = normalize(Normal); +} diff --git a/resources/shaders/fragment/ssao.glsl b/resources/shaders/fragment/ssao.glsl new file mode 100644 index 00000000..f02b5dc9 --- /dev/null +++ b/resources/shaders/fragment/ssao.glsl @@ -0,0 +1,47 @@ +#version 330 core +in vec2 TexCoords; + +uniform sampler2D depthTexture; // View-space depth texture +uniform sampler2D normalTexture; // View-space normal texture + +uniform mat4 projection; +uniform vec3 samples[128]; // SSAO Kernel + +out float SSAO; + +void main() { + vec3 fragViewPos = texture(depthTexture, TexCoords).xyz; // View-space position + float fragViewDepth = -fragViewPos.z; + vec3 normal = normalize(texture(normalTexture, TexCoords).xyz); + + float occlusion = 0.0; + float radius = 0.5; // Sample radius + float bias = 0.01; + + for (int i = 0; i < 128; ++i) { + vec3 randomVec = vec3(samples[i].y, samples[i].z, samples[i].x); + vec3 tangent = normalize(normalize(randomVec) - normal * dot(randomVec, normal)); + vec3 bitangent = cross(normal, tangent); + mat3 TBN = mat3(tangent, bitangent, normal); // Create tangent-space matrix + + vec3 samplePos = TBN * samples[i]; // Transform to view space + samplePos = fragViewPos + samplePos * radius; // Move sample position + + vec4 offset = vec4(samplePos, 1.0); + offset = projection * offset; + offset.xyz /= offset.w; + offset.xyz = offset.xyz * 0.5 + 0.5; + + float offsetDepth = -samplePos.z; + float newlySampledDepth = -texture(depthTexture, offset.xy).z; + + if(newlySampledDepth + bias < offsetDepth) + { + float rangeCheck = smoothstep(0.0, 1.0, radius / abs(newlySampledDepth - fragViewDepth)); + occlusion += rangeCheck; + } + } + + occlusion = 1.0 - (occlusion / 128.0); // Normalize occlusion value + SSAO = occlusion; +} diff --git a/resources/shaders/fragment/uber.glsl b/resources/shaders/fragment/uber.glsl index 6dac7ce8..d1fe5b9b 100644 --- a/resources/shaders/fragment/uber.glsl +++ b/resources/shaders/fragment/uber.glsl @@ -6,6 +6,7 @@ out vec4 FragColor; in vec3 FragPos; in vec3 Normal; +uniform vec2 viewportSize; uniform vec3 viewPos; // Camera position // ******** LIGHT DATA ******** @@ -47,6 +48,7 @@ uniform SpotLight spotLights[SPOT_LIGHT_MAX_NUM]; uniform sampler2D spotLightsShadowMap[SPOT_LIGHT_MAX_NUM]; uniform vec3 ambientLight; +uniform sampler2D ssao; // ******** MATERIAL DATA ******** struct Material { @@ -106,6 +108,12 @@ vec3 calculateAmbient() { return ambientLight * material.color; } +float getAmbientOcclusion() +{ + vec2 texCoords = gl_FragCoord.xy / viewportSize; + return texture(ssao, texCoords).r; +} + float calculateSpotFalloff(vec3 lightDir, vec3 spotlightDir, float innerCutoffCosine, float outerCutoffCosine) { float theta = dot(lightDir, normalize(-spotlightDir)); float epsilon = innerCutoffCosine - outerCutoffCosine; @@ -121,6 +129,7 @@ vec3 calculateSpotLights() { float distanceToLight = length(lightToFrag); float attenuation = 1.0 - (distanceToLight / spotLights[i].range); + attenuation = attenuation * attenuation; if (attenuation > 0.0) { vec3 lightDir = normalize(-lightToFrag); @@ -305,7 +314,7 @@ vec3 calculateDirectionalLights() { void main() { // Lighting - vec3 color = calculateAmbient(); + vec3 color = calculateAmbient() * getAmbientOcclusion(); color += calculatePointLights(); color += calculateDirectionalLights(); color += calculateSpotLights(); diff --git a/resources/shaders/fragment/viewspace_normal.glsl b/resources/shaders/fragment/viewspace_normal.glsl new file mode 100644 index 00000000..2363413c --- /dev/null +++ b/resources/shaders/fragment/viewspace_normal.glsl @@ -0,0 +1,8 @@ +#version 330 core +in vec3 Normal; + +out vec3 OutNormal; + +void main() { + OutNormal = normalize(Normal); +} diff --git a/resources/shaders/fragment/viewspace_position.glsl b/resources/shaders/fragment/viewspace_position.glsl new file mode 100644 index 00000000..56a43537 --- /dev/null +++ b/resources/shaders/fragment/viewspace_position.glsl @@ -0,0 +1,8 @@ +#version 330 core +in vec3 FragPos; + +out vec3 OutFragPos; + +void main() { + OutFragPos = FragPos; +} diff --git a/resources/shaders/vertex/depth.glsl b/resources/shaders/vertex/depth.glsl new file mode 100644 index 00000000..4c2eef0d --- /dev/null +++ b/resources/shaders/vertex/depth.glsl @@ -0,0 +1,14 @@ +#version 330 core + +layout(location = 0) in vec3 aPos; // Vertex position + +uniform mat4 projectionViewMatrix; // Model matrix +uniform mat4 modelMatrix; // Projection matrix + +out float VertexDepth; // Output the depth value to the fragment shader + +void main() { + vec4 viewSpacePosition = projectionViewMatrix * modelMatrix * vec4(aPos, 1.0); + gl_Position = viewSpacePosition; + VertexDepth = viewSpacePosition.z; +} \ No newline at end of file diff --git a/resources/shaders/vertex/distance.glsl b/resources/shaders/vertex/distance.glsl index 230de7fd..d47fbc4a 100644 --- a/resources/shaders/vertex/distance.glsl +++ b/resources/shaders/vertex/distance.glsl @@ -2,18 +2,13 @@ layout(location = 0) in vec3 aPos; // Vertex position -uniform mat4 lightSpaceMatrix; // Model matrix +uniform mat4 projectionViewMatrix; // Model matrix uniform mat4 modelMatrix; // Projection matrix out vec3 FragPos; // Output the depth value to the fragment shader void main() { - // Transform vertex position to world space, then to light space - vec4 lightSpacePosition = lightSpaceMatrix * modelMatrix * vec4(aPos, 1.0); - - // Set the final position - gl_Position = lightSpacePosition; - - // Calculate the depth in light space (NDC) range [0,1] - FragPos = lightSpacePosition.xyz; + vec4 viewSpacePosition = projectionViewMatrix * modelMatrix * vec4(aPos, 1.0); + gl_Position = viewSpacePosition; + FragPos = viewSpacePosition.xyz; } diff --git a/resources/shaders/vertex/normal.glsl b/resources/shaders/vertex/normal.glsl new file mode 100644 index 00000000..8f92517f --- /dev/null +++ b/resources/shaders/vertex/normal.glsl @@ -0,0 +1,15 @@ +#version 330 core + +layout(location = 1) in vec3 normal; // Vertex normal + +uniform mat4 modelMatrix; // Model matrix +uniform mat4 projectionViewMatrix; // View matrix + +out vec3 Normal; // Normal in world space + +void main() { + vec3 fragPos = vec3(modelMatrix * vec4(position, 1.0)); + Normal = normalize(mat3(transpose(inverse(modelMatrix))) * normal); + + gl_Position = projectionViewMatrix * vec4(fragPos, 1.0); +} diff --git a/resources/shaders/vertex/position_and_normal.glsl b/resources/shaders/vertex/position_and_normal.glsl index 989e327a..65cfd352 100644 --- a/resources/shaders/vertex/position_and_normal.glsl +++ b/resources/shaders/vertex/position_and_normal.glsl @@ -10,8 +10,10 @@ out vec3 FragPos; // Fragment position in world space out vec3 Normal; // Normal in world space void main() { + // Transform position and normal to world space FragPos = vec3(modelMatrix * vec4(position, 1.0)); Normal = normalize(mat3(transpose(inverse(modelMatrix))) * normal); + // Set final vertex position gl_Position = projectionViewMatrix * vec4(FragPos, 1.0); } diff --git a/resources/shaders/vertex/shadowmap.glsl b/resources/shaders/vertex/shadowmap.glsl deleted file mode 100644 index 21ddc47b..00000000 --- a/resources/shaders/vertex/shadowmap.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#version 330 core - -layout(location = 0) in vec3 aPos; // Vertex position - -uniform mat4 lightSpaceMatrix; // Model matrix -uniform mat4 modelMatrix; // Projection matrix - -out float FragDepth; // Output the depth value to the fragment shader - -void main() { - // Transform vertex position to world space, then to light space - vec4 lightSpacePosition = lightSpaceMatrix * modelMatrix * vec4(aPos, 1.0); - - // Set the final position - gl_Position = lightSpacePosition; - - // Calculate the depth in light space (NDC) range [0,1] - FragDepth = lightSpacePosition.z / lightSpacePosition.w; -} diff --git a/resources/shaders/vertex/viewspace_normal.glsl b/resources/shaders/vertex/viewspace_normal.glsl new file mode 100644 index 00000000..36980bc3 --- /dev/null +++ b/resources/shaders/vertex/viewspace_normal.glsl @@ -0,0 +1,16 @@ +#version 330 core +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aNormal; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +out vec3 Normal; // View-space normal + +void main() { + vec4 worldPos = model * vec4(aPos, 1.0); + vec4 viewPos = view * worldPos; + Normal = mat3(transpose(inverse(view))) * aNormal; // Transform normal to view space + gl_Position = projection * viewPos; +} diff --git a/resources/shaders/vertex/viewspace_position.glsl b/resources/shaders/vertex/viewspace_position.glsl new file mode 100644 index 00000000..3acbdbf5 --- /dev/null +++ b/resources/shaders/vertex/viewspace_position.glsl @@ -0,0 +1,17 @@ +#version 330 core +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aNormal; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +out vec3 FragPos; + +void main() { + vec4 worldPos = model * vec4(aPos, 1.0); + vec4 viewPos = view * worldPos; + + FragPos = viewPos.xyz; + gl_Position = projection * viewPos; +} diff --git a/src/Components/CameraComponent.hpp b/src/Components/CameraComponent.hpp index 8a275198..74e7d868 100644 --- a/src/Components/CameraComponent.hpp +++ b/src/Components/CameraComponent.hpp @@ -14,7 +14,7 @@ class CameraComponent { Orthographic }; - CameraComponent(float fov = 40.0f, float aspectRatio = 16.0f / 9.0f, float nearPlane = 0.01f, float farPlane = 2000.0f, ProjectionType projectionType = ProjectionType::Perspective) + CameraComponent(float fov = 40.0f, float aspectRatio = 16.0f / 9.0f, float nearPlane = 0.1f, float farPlane = 1000.0f, ProjectionType projectionType = ProjectionType::Perspective) : fov(fov), aspectRatio(aspectRatio), nearPlane(nearPlane), farPlane(farPlane), projectionType(projectionType) {} float fov; diff --git a/src/Rendering/FrameBuffers/DepthAtlasFrameBuffer.cpp b/src/Rendering/FrameBuffers/DepthAtlasFrameBuffer.cpp index 87c4502e..9b509844 100644 --- a/src/Rendering/FrameBuffers/DepthAtlasFrameBuffer.cpp +++ b/src/Rendering/FrameBuffers/DepthAtlasFrameBuffer.cpp @@ -83,8 +83,10 @@ void DepthAtlasFrameBuffer::unbind() { } void DepthAtlasFrameBuffer::clear() { + bind(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + unbind(); } void DepthAtlasFrameBuffer::setSize(uint32_t width, uint32_t height) { diff --git a/src/Rendering/FrameBuffers/SceneFrameBuffer.cpp b/src/Rendering/FrameBuffers/SceneFrameBuffer.cpp index a934d74f..c3dc7cee 100644 --- a/src/Rendering/FrameBuffers/SceneFrameBuffer.cpp +++ b/src/Rendering/FrameBuffers/SceneFrameBuffer.cpp @@ -67,9 +67,9 @@ void SceneFrameBuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void SceneFrameBuffer::clear() { +void SceneFrameBuffer::clear(glm::vec3 color) { bind(); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(color.x, color.y, color.z, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); unbind(); } diff --git a/src/Rendering/FrameBuffers/SceneFrameBuffer.hpp b/src/Rendering/FrameBuffers/SceneFrameBuffer.hpp index 21e471f5..30bb2e3e 100644 --- a/src/Rendering/FrameBuffers/SceneFrameBuffer.hpp +++ b/src/Rendering/FrameBuffers/SceneFrameBuffer.hpp @@ -22,7 +22,7 @@ class SceneFrameBuffer { void bind(); void unbind(); - void clear(); + void clear(glm::vec3 color = {0, 0, 0}); void setSize(uint32_t width, uint32_t height); glm::vec2 getSize() const; diff --git a/src/Rendering/Utils.hpp b/src/Rendering/Utils.hpp index 7bf50de4..3a2936f6 100644 --- a/src/Rendering/Utils.hpp +++ b/src/Rendering/Utils.hpp @@ -44,4 +44,40 @@ void applyShaderToFrameBuffer( frameBuffer.unbind(); } +template +void applyShaderToFrameBuffer( + SceneFrameBuffer& frameBuffer, + ShaderProgram& shaderProgram, + std::vector> textures, // List of texture bindings with texture unit indices + std::pair> array, + Uniforms... uniforms) // Parameter pack for uniform values +{ + // Bind framebuffer and activate shader program + frameBuffer.bind(); + shaderProgram.use(); + + // Bind textures to their corresponding texture units + int textureIndex = 0; + for (const auto& [name, texture] : textures) { + texture->activate(GL_TEXTURE0 + textureIndex); + shaderProgram.setUniform(name, textureIndex++); + } + + int index = 0; + for(const auto& val : array.second) + { + shaderProgram.setUniform(std::string(array.first) + "[" + std::to_string(index++) + "]", val); + } + + // Set uniforms using the parameter pack + (shaderProgram.setUniform(uniforms.first, uniforms.second), ...); + + // Draw fullscreen quad + utils::drawFullscreenQuad(); + + // Stop using the shader program and unbind framebuffer + shaderProgram.stopUsing(); + frameBuffer.unbind(); +} + } diff --git a/src/Systems/RenderingSystem.cpp b/src/Systems/RenderingSystem.cpp index f18cff36..ac1fe130 100644 --- a/src/Systems/RenderingSystem.cpp +++ b/src/Systems/RenderingSystem.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -27,7 +28,30 @@ RenderingSystem::RenderingSystem(std::shared_ptr registry) _modelShaderProgram.attachShader(modelFragmentShader); _modelShaderProgram.link(); + const auto& distanceVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/distance.glsl", Shader::Type::Vertex); }); + const auto& distanceFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/distance.glsl", Shader::Type::Fragment); }); + _distanceShaderProgram.attachShader(distanceVertexShader); + _distanceShaderProgram.attachShader(distanceFragmentShader); + _distanceShaderProgram.link(); + + const auto& viewSpaceNormalVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/viewspace_normal.glsl", Shader::Type::Vertex); }); + const auto& viewSpaceNormalFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/viewspace_normal.glsl", Shader::Type::Fragment); }); + _viewSpaceNormalShaderProgram.attachShader(viewSpaceNormalVertexShader); + _viewSpaceNormalShaderProgram.attachShader(viewSpaceNormalFragmentShader); + _viewSpaceNormalShaderProgram.link(); + + const auto& viewSpaceDepthVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/viewspace_position.glsl", Shader::Type::Vertex); }); + const auto& viewSpaceDepthFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/viewspace_position.glsl", Shader::Type::Fragment); }); + _viewSpacePositionShaderProgram.attachShader(viewSpaceDepthVertexShader); + _viewSpacePositionShaderProgram.attachShader(viewSpaceDepthFragmentShader); + _viewSpacePositionShaderProgram.link(); + const auto& texCoordsVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/texcoords.glsl", Shader::Type::Vertex); }); + const auto& ssaoFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/ssao.glsl", Shader::Type::Fragment); }); + _ssaoShaderProgram.attachShader(texCoordsVertexShader); + _ssaoShaderProgram.attachShader(ssaoFragmentShader); + _ssaoShaderProgram.link(); + const auto& toneMappingFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/tonemapping_aces.glsl", Shader::Type::Fragment); }); _toneMappingShaderProgram.attachShader(texCoordsVertexShader); _toneMappingShaderProgram.attachShader(toneMappingFragmentShader); @@ -89,17 +113,11 @@ RenderingSystem::RenderingSystem(std::shared_ptr registry) _skyboxShaderProgram.attachShader(cubeMapFragmentShader); _skyboxShaderProgram.link(); - const auto& shadowMapVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/shadowmap.glsl", Shader::Type::Vertex); }); + const auto& depthVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/depth.glsl", Shader::Type::Vertex); }); const auto& depthFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/depth.glsl", Shader::Type::Fragment); }); - _shadowMapShaderProgram.attachShader(shadowMapVertexShader); - _shadowMapShaderProgram.attachShader(depthFragmentShader); - _shadowMapShaderProgram.link(); - - const auto& distanceVertexShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/vertex/distance.glsl", Shader::Type::Vertex); }); - const auto& distanceFragmentShader = utils::assets::addAndRead(_registry.get(), []() { return Shader("resources/shaders/fragment/distance.glsl", Shader::Type::Fragment); }); - _shadowMapDistanceShaderProgram.attachShader(distanceVertexShader); - _shadowMapDistanceShaderProgram.attachShader(distanceFragmentShader); - _shadowMapDistanceShaderProgram.link(); + _depthShaderProgram.attachShader(depthVertexShader); + _depthShaderProgram.attachShader(depthFragmentShader); + _depthShaderProgram.link(); } void RenderingSystem::setSize(uint32_t width, uint32_t height) @@ -115,6 +133,9 @@ void RenderingSystem::setSize(uint32_t width, uint32_t height) _bloomedFrameBuffer.setSize(width, height); _antiAliasedFrameBuffer.setSize(width, height); _outlinedObjectsFrameBuffer.setSize(width, height); + _viewSpaceNormalFrameBuffer.setSize(width, height); + _viewSpacePositionFrameBuffer.setSize(width, height); + _ssaoFrameBuffer.setSize(width, height); size_t downscaleFactor = 2; for(size_t i = 0; i < BloomSteps; ++i) @@ -144,6 +165,10 @@ void RenderingSystem::clearFrameBuffers() _horizontallyDilatedFrameBuffer.clear(); _fullyDilatedFrameBuffer.clear(); _differenceFrameBuffer.clear(); + _viewSpaceNormalFrameBuffer.clear(); + _viewSpacePositionFrameBuffer.clear(); + _ssaoFrameBuffer.clear(glm::vec3{1.0, 1.0, 1.0}); + for(auto& buffer : _downscaledFrameBuffers) { buffer.clear(); @@ -167,6 +192,13 @@ void RenderingSystem::render() // Rendering Preparation clearFrameBuffers(); + // Rendering Supporting Textures + renderCameraDepth(); + renderNormals(); + + // Ambient Occlusion + renderSSAO(); + // Main Rendering Pass renderSkybox(); renderModels(); @@ -176,13 +208,122 @@ void RenderingSystem::render() renderOutline(_registry->getSelectedEntities()); // Post-Processing - renderBloom(); + bloom(); toneMapping(); antiAliasing(); renderOverlayModels(); } +void RenderingSystem::renderCameraDepth() +{ + SHKYERA_PROFILE("RenderingSystem::renderCameraDepth"); + + _viewSpacePositionShaderProgram.use(); + _viewSpacePositionFrameBuffer.bind(); + + const auto& cameraTransform = _registry->getComponent(_registry->getCamera()); + const auto& cameraComponent = _registry->getComponent(_registry->getCamera()); + + const glm::mat4& viewMatrix = _registry->getComponent(_registry->getCamera()).getViewMatrix(cameraTransform); + const glm::mat4& projectionMatrix = _registry->getComponent(_registry->getCamera()).getProjectionMatrix(); + + _viewSpacePositionShaderProgram.setUniform("projection", projectionMatrix); + _viewSpacePositionShaderProgram.setUniform("view", viewMatrix); + + for (const auto& [entity, modelComponent] : _registry->getComponentSet()) { + const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(entity, _registry); + _viewSpacePositionShaderProgram.setUniform("model", transformMatrix); + + modelComponent.updateImpl(); + } + + _viewSpacePositionFrameBuffer.unbind(); + _viewSpacePositionShaderProgram.stopUsing(); +} + +void RenderingSystem::renderNormals() +{ + SHKYERA_PROFILE("RenderingSystem::renderNormals"); + + _viewSpaceNormalShaderProgram.use(); + _viewSpaceNormalFrameBuffer.bind(); + + const auto& cameraTransform = _registry->getComponent(_registry->getCamera()); + const auto& cameraComponent = _registry->getComponent(_registry->getCamera()); + + const glm::mat4& viewMatrix = _registry->getComponent(_registry->getCamera()).getViewMatrix(cameraTransform); + const glm::mat4& projectionMatrix = _registry->getComponent(_registry->getCamera()).getProjectionMatrix(); + + _viewSpaceNormalShaderProgram.setUniform("projection", projectionMatrix); + _viewSpaceNormalShaderProgram.setUniform("view", viewMatrix); + + for (const auto& [entity, modelComponent] : _registry->getComponentSet()) { + const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(entity, _registry); + _viewSpaceNormalShaderProgram.setUniform("model", transformMatrix); + + modelComponent.updateImpl(); + } + + _viewSpaceNormalFrameBuffer.unbind(); + _viewSpaceNormalShaderProgram.stopUsing(); +} + +void RenderingSystem::renderSSAO() +{ + SHKYERA_PROFILE("RenderingSystem::renderSSAO"); + + static std::vector ssaoKernel; + + if(ssaoKernel.empty()) + { + std::default_random_engine generator; + std::uniform_real_distribution randomFloats(0.0f, 1.0f); + for (int i = 0; i < 128; ++i) { + glm::vec3 sample( + randomFloats(generator) * 2.0 - 1.0, + randomFloats(generator) * 2.0 - 1.0, + randomFloats(generator) * 0.95 + 0.05 + ); + sample = glm::normalize(sample); + sample *= randomFloats(generator); + + float scale = (float)i / 128.0; + scale = glm::mix(0.1f, 1.0f, scale * scale); + sample *= scale; + + ssaoKernel.push_back(sample); + } + } + + const glm::mat4& projectionMatrix = _registry->getComponent(_registry->getCamera()).getProjectionMatrix(); + + // Bind framebuffer and activate shader program + _ssaoFrameBuffer.bind(); + _ssaoShaderProgram.use(); + + // Bind textures to their corresponding texture units + _viewSpacePositionFrameBuffer.getTexture().activate(GL_TEXTURE0); + _ssaoShaderProgram.setUniform("depthTexture", 0); + _viewSpaceNormalFrameBuffer.getTexture().activate(GL_TEXTURE1); + _ssaoShaderProgram.setUniform("normalTexture", 1); + + for(int i = 0; i < 128; i++) + { + _ssaoShaderProgram.setUniform("samples[" + std::to_string(i) + "]", ssaoKernel[i]); + } + + // Set uniforms using the parameter pack + _ssaoShaderProgram.setUniform("projection", projectionMatrix); + + // Draw fullscreen quad + utils::drawFullscreenQuad(); + + // Stop using the shader program and unbind framebuffer + _ssaoShaderProgram.stopUsing(); + _ssaoFrameBuffer.unbind(); +} + void RenderingSystem::renderOutline(const std::unordered_set& entities) { if(std::none_of(entities.begin(), entities.end(), [this](auto e) { return _registry->hasComponent(e); })) @@ -312,19 +453,24 @@ void RenderingSystem::renderDirectionalLightShadowMaps() for(uint8_t levelOfDetail = 0; levelOfDetail < DirectionalLightComponent::LevelsOfDetail; ++levelOfDetail) { shadowMapAtlas.bind(levelOfDetail); - _shadowMapShaderProgram.use(); + _depthShaderProgram.use(); + + const auto nearPlane = _registry->getComponent(_registry->getCamera()).nearPlane; + const auto farPlane = _registry->getComponent(_registry->getCamera()).farPlane; + _depthShaderProgram.setUniform("near", nearPlane); + _depthShaderProgram.setUniform("far", farPlane); const glm::mat4& lightSpaceMatrix = directionalLightComponent.getLightSpaceMatrix(lightTransformMatrix, cameraTransform, cameraComponent, levelOfDetail); - _shadowMapShaderProgram.setUniform("lightSpaceMatrix", lightSpaceMatrix); + _depthShaderProgram.setUniform("projectionViewMatrix", lightSpaceMatrix); for (const auto& [modelEntity, modelComponent] : _registry->getComponentSet()) { const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(modelEntity, _registry); - _shadowMapShaderProgram.setUniform("modelMatrix", transformMatrix); + _depthShaderProgram.setUniform("modelMatrix", transformMatrix); modelComponent.updateImpl(); } - _shadowMapShaderProgram.stopUsing(); + _depthShaderProgram.stopUsing(); shadowMapAtlas.unbind(); } } @@ -388,18 +534,18 @@ void RenderingSystem::renderPointLightShadowMaps() projection * glm::lookAt(lightPosition, lightPosition + glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3( 0.0f, -1.0f, 0.0f)) // -Z }; - _shadowMapDistanceShaderProgram.use(); + _distanceShaderProgram.use(); for(uint8_t face = 0; face < 6; ++face) { shadowMapCubeAtlas.bind(face); const glm::mat4& lightSpaceMatrix = captureViews[face]; - _shadowMapDistanceShaderProgram.setUniform("lightSpaceMatrix", lightSpaceMatrix); + _distanceShaderProgram.setUniform("projectionViewMatrix", lightSpaceMatrix); for (const auto& [modelEntity, modelComponent] : _registry->getComponentSet()) { const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(modelEntity, _registry); - _shadowMapDistanceShaderProgram.setUniform("modelMatrix", transformMatrix); + _distanceShaderProgram.setUniform("modelMatrix", transformMatrix); modelComponent.updateImpl(); } @@ -407,7 +553,7 @@ void RenderingSystem::renderPointLightShadowMaps() shadowMapCubeAtlas.unbind(); } - _shadowMapDistanceShaderProgram.stopUsing(); + _distanceShaderProgram.stopUsing(); } } @@ -461,18 +607,18 @@ void RenderingSystem::renderSpotLightShadowMaps() const auto& lightOuterCutoff = _registry->getComponent(lightEntity).outerCutoff; const auto lightSpaceMatrix = _registry->getComponent(lightEntity).getLightSpaceMatrix(lightTransformMatrix); - _shadowMapDistanceShaderProgram.use(); + _distanceShaderProgram.use(); shadowMap.bind(0); - _shadowMapDistanceShaderProgram.setUniform("lightSpaceMatrix", lightSpaceMatrix); + _distanceShaderProgram.setUniform("projectionViewMatrix", lightSpaceMatrix); for (const auto& [modelEntity, modelComponent] : _registry->getComponentSet()) { const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(modelEntity, _registry); - _shadowMapDistanceShaderProgram.setUniform("modelMatrix", transformMatrix); + _distanceShaderProgram.setUniform("modelMatrix", transformMatrix); modelComponent.updateImpl(); } shadowMap.unbind(); - _shadowMapDistanceShaderProgram.stopUsing(); + _distanceShaderProgram.stopUsing(); } } @@ -577,6 +723,14 @@ void RenderingSystem::renderModels() } _modelShaderProgram.setUniform("numSpotLights", spotLightIndex); + { // SSAO + _ssaoFrameBuffer.getTexture().activate(GL_TEXTURE0 + textureIndex); + _modelShaderProgram.setUniform("ssao", textureIndex); + ++textureIndex; + + _modelShaderProgram.setUniform("viewportSize", _mostRecentFrameBufferPtr->getSize()); + } + for (const auto& [entity, modelComponent] : _registry->getComponentSet()) { const auto& transformMatrix = TransformComponent::getGlobalTransformMatrix(entity, _registry); _modelShaderProgram.setUniform("modelMatrix", transformMatrix); @@ -594,7 +748,7 @@ void RenderingSystem::renderModels() _mostRecentFrameBufferPtr->unbind(); } -void RenderingSystem::renderBloom() +void RenderingSystem::bloom() { SHKYERA_PROFILE("RenderingSystem::renderBloom"); diff --git a/src/Systems/RenderingSystem.hpp b/src/Systems/RenderingSystem.hpp index 737fa61a..9d1d60d5 100644 --- a/src/Systems/RenderingSystem.hpp +++ b/src/Systems/RenderingSystem.hpp @@ -23,8 +23,11 @@ class RenderingSystem { private: void clearFrameBuffers(); + void renderCameraDepth(); + void renderNormals(); + void renderSSAO(); void renderModels(); - void renderBloom(); + void bloom(); void toneMapping(); void renderWireframes(); void renderOutline(const std::unordered_set& entities); @@ -50,6 +53,14 @@ class RenderingSystem { SceneFrameBuffer _antiAliasedFrameBuffer; ShaderProgram _antiAliasingShaderProgram; + // Screen-Space Ambient Occlusion + SceneFrameBuffer _viewSpacePositionFrameBuffer; + SceneFrameBuffer _viewSpaceNormalFrameBuffer; + SceneFrameBuffer _ssaoFrameBuffer; + ShaderProgram _viewSpaceNormalShaderProgram; + ShaderProgram _viewSpacePositionShaderProgram; + ShaderProgram _ssaoShaderProgram; + // Tone Mapping SceneFrameBuffer _toneMappedFrameBuffer; ShaderProgram _toneMappingShaderProgram; @@ -82,10 +93,10 @@ class RenderingSystem { // Light rendering std::unordered_map _directionalLightToShadowMap; - ShaderProgram _shadowMapShaderProgram; + ShaderProgram _depthShaderProgram; std::unordered_map _pointLightToShadowMap; - ShaderProgram _shadowMapDistanceShaderProgram; + ShaderProgram _distanceShaderProgram; std::unordered_map _spotLightToShadowMap; }; diff --git a/src/main.cpp b/src/main.cpp index b1357d64..0175fe35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -91,6 +91,9 @@ void loadScene(std::shared_ptr registry) { addWireframe(registry, {3, 9, 3}, "Sphere Wireframe", utils::assets::fromFactory(registry.get())); // Add World Plane + auto bunny = addModel(registry, {0, -1, 0}, "Bunny", utils::assets::readPermanent("resources/models/bunny.obj")); + registry->getComponent(bunny).setScale({15, 15, 15}); + auto worldPlane = addModel(registry, {0, -2, 0}, "Plane", utils::assets::fromFactory(registry.get())); registry->getComponent(worldPlane).setScale({15, 1, 15}); @@ -102,7 +105,7 @@ void loadScene(std::shared_ptr registry) { registry->getComponent(pointLight).setName("Point Light"); registry->addComponent(pointLight); registry->getComponent(pointLight).range = 15; - registry->getComponent(pointLight).intensity = 1; + registry->getComponent(pointLight).intensity = 0;//1; // Add Skybox auto sky = registry->addEntity(); @@ -112,7 +115,7 @@ void loadScene(std::shared_ptr registry) { registry->getComponent(sky).setName("Sun"); registry->addComponent(sky); registry->getComponent(sky).color = glm::vec3{0.95, 0.95, 0.95}; - registry->getComponent(sky).intensity = 0.3; + registry->getComponent(sky).intensity = 0;//0.3; registry->addComponent(sky); auto redSpotLight = registry->addEntity(); @@ -123,7 +126,7 @@ void loadScene(std::shared_ptr registry) { registry->getComponent(redSpotLight).setName("Red Spot Light"); registry->addComponent(redSpotLight); registry->getComponent(redSpotLight).color = glm::vec3{0.95, 0.55, 0.15}; - registry->getComponent(redSpotLight).intensity = 2.0; + registry->getComponent(redSpotLight).intensity = 0;//2.0; registry->getComponent(redSpotLight).range = 50.0; registry->getComponent(redSpotLight).innerCutoff = glm::radians(10.0); registry->getComponent(redSpotLight).outerCutoff = glm::radians(15.0); @@ -136,7 +139,7 @@ void loadScene(std::shared_ptr registry) { registry->getComponent(blueSpotLight).setName("Blue Spot Light"); registry->addComponent(blueSpotLight); registry->getComponent(blueSpotLight).color = glm::vec3{0.15, 0.35, 0.95}; - registry->getComponent(blueSpotLight).intensity = 2.0; + registry->getComponent(blueSpotLight).intensity = 0;//2.0; registry->getComponent(blueSpotLight).range = 50.0; registry->getComponent(blueSpotLight).innerCutoff = glm::radians(10.0); registry->getComponent(blueSpotLight).outerCutoff = glm::radians(15.0);