From fdbf1296de555e284ab669d4c246164aeb86449b Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 14 Oct 2025 19:35:50 +0200 Subject: [PATCH] feat: finalize directional light shadows --- include/renderer/renderer.h | 9 ++-- src/main.cpp | 7 ++- src/renderer/engine.cpp | 3 -- src/renderer/renderer.cpp | 96 ++++++++++++++++--------------------- src/shaders/pbr.fs | 48 +++++++++++++++---- src/window/window.cpp | 1 + 6 files changed, 91 insertions(+), 73 deletions(-) diff --git a/include/renderer/renderer.h b/include/renderer/renderer.h index 0488c38..b540966 100644 --- a/include/renderer/renderer.h +++ b/include/renderer/renderer.h @@ -16,16 +16,13 @@ public: void OnWindowResized(int w, int h); private: - void ApplyLights(entt::registry& registry); - void UpdateView(entt::registry& registry); - void RenderScene(entt::registry& registry); - - void SwitchShader(Shader* newShader); + void ApplyLights(entt::registry& registry, Shader &shader); + void UpdateView(entt::registry& registry, Shader &shader); + void RenderScene(entt::registry& registry, Shader &shader); private: Shader m_shader; Shader m_depthShader; - Shader* m_currentShader; unsigned int m_depth_fbo; unsigned int m_depthMap; diff --git a/src/main.cpp b/src/main.cpp index c167a43..472e33e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,9 +44,14 @@ public: Object* targetObj = Object::LoadFile("./assets/wizard/wizard.obj"); const auto targetEntity = m_registry.create(); - m_registry.emplace(targetEntity, glm::vec3(0.f, 0.5f, 0.f)); + m_registry.emplace(targetEntity, glm::vec3(0.f, 0.0f, 0.f)); m_registry.emplace(targetEntity, std::unique_ptr(targetObj)); + Object* cubeObj = Object::LoadFile("./assets/cube.obj"); + const auto cubeEntity = m_registry.create(); + m_registry.emplace(cubeEntity, glm::vec3(-1.5f, 0.4f, 0.f)); + m_registry.emplace(cubeEntity, std::unique_ptr(cubeObj)); + Object* floorObj = Object::LoadFile("./assets/plane.obj"); const auto floorEntt = m_registry.create(); m_registry.emplace(floorEntt, glm::vec3(0.f)); diff --git a/src/renderer/engine.cpp b/src/renderer/engine.cpp index 84b4276..ab25987 100644 --- a/src/renderer/engine.cpp +++ b/src/renderer/engine.cpp @@ -28,9 +28,6 @@ void Engine::Run(std::unique_ptr app) { s_window->ProcessEvents(); s_app->OnUpdate(); - - glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); s_app->OnRender(); diff --git a/src/renderer/renderer.cpp b/src/renderer/renderer.cpp index 52364cb..a904ad6 100644 --- a/src/renderer/renderer.cpp +++ b/src/renderer/renderer.cpp @@ -38,16 +38,10 @@ Renderer::Renderer() m_model = glm::mat4(1.f); - SwitchShader(&m_shader); - + m_shader.use(); m_shader.setMat4("u_projection", m_proj); } -void Renderer::SwitchShader(Shader *newShader) { - m_currentShader = newShader; - m_currentShader->use(); -} - void Renderer::OnWindowResized(int w, int h) { m_proj = glm::perspective( static_cast(M_PI_2), @@ -59,24 +53,24 @@ void Renderer::OnWindowResized(int w, int h) { m_depthShader.setMat4("u_projection", m_proj); } -void Renderer::ApplyLights(entt::registry& registry) { +void Renderer::ApplyLights(entt::registry& registry, Shader &shader) { auto lights = registry.view(); // TODO: Pass Lights Data to depth shader as well - m_shader.setInt("lightsCount", static_cast(lights.size())); + shader.setInt("lightsCount", static_cast(lights.size())); size_t lightIndex = 0; for (auto entity : lights) { auto &comp = registry.get(entity); auto &transf = registry.get(entity); - m_shader.setVec3("lights[" + std::to_string(lightIndex) + "].position", transf.position); - m_shader.setVec3("lights[" + std::to_string(lightIndex) + "].color", comp.color); - m_shader.setFloat("lights[" + std::to_string(lightIndex) + "].intensity", comp.intensity); + shader.setVec3("lights[" + std::to_string(lightIndex) + "].position", transf.position); + shader.setVec3("lights[" + std::to_string(lightIndex) + "].color", comp.color); + shader.setFloat("lights[" + std::to_string(lightIndex) + "].intensity", comp.intensity); ++lightIndex; } } -void Renderer::UpdateView(entt::registry& registry) { +void Renderer::UpdateView(entt::registry& registry, Shader &shader) { auto cam = registry.view().back(); auto camTransform = registry.get(cam); @@ -85,12 +79,12 @@ void Renderer::UpdateView(entt::registry& registry) { camTransform.position + camTransform.rotation, glm::vec3(0.f, 1.f, 0.f) ); - m_shader.setMat4("u_view", m_view); + shader.setMat4("u_view", m_view); - m_shader.setVec3("viewPos", camTransform.position); + shader.setVec3("viewPos", camTransform.position); } -void Renderer::RenderScene(entt::registry& registry) { +void Renderer::RenderScene(entt::registry& registry, Shader &shader) { auto view = registry.view(); for (auto [entity, transf, mesh] : view.each()) { @@ -101,32 +95,31 @@ void Renderer::RenderScene(entt::registry& registry) { if (registry.all_of(entity)) { auto &comp = registry.get(entity); - m_currentShader->setBool("isLight", true); - m_currentShader->setVec3("currentLightColor", comp.color); + shader.setBool("isLight", true); + shader.setVec3("currentLightColor", comp.color); } else { - m_currentShader->setBool("isLight", false); - m_currentShader->setVec3("currentLightColor", glm::vec3(0.f)); + shader.setBool("isLight", false); + shader.setVec3("currentLightColor", glm::vec3(0.f)); } glm::mat4 rotation = glm::yawPitchRoll(transf.rotation.y, transf.rotation.x, transf.rotation.z); m_model = glm::translate(glm::mat4(1.f), transf.position) * rotation; - m_currentShader->setMat4("u_model", m_model); + shader.setMat4("u_model", m_model); - mesh.object->Render(*m_currentShader); + mesh.object->Render(shader); } } void Renderer::GenerateShadowMaps(entt::registry& registry) { - SwitchShader(&m_depthShader); + const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; - ApplyLights(registry); - UpdateView(registry); + m_depthShader.use(); + ApplyLights(registry, m_depthShader); + UpdateView(registry, m_depthShader); glGenFramebuffers(1, &m_depth_fbo); - const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; - glGenTextures(1, &m_depthMap); glBindTexture(GL_TEXTURE_2D, m_depthMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, @@ -145,8 +138,6 @@ void Renderer::GenerateShadowMaps(entt::registry& registry) { glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, 0); - - m_shader.setInt("shadowMap", 31); } void Renderer::Render(entt::registry& registry) { @@ -158,52 +149,47 @@ void Renderer::Render(entt::registry& registry) { auto shadowLight = registry.view().back(); auto &comp = registry.get(shadowLight); - float near_plane = 0.1f, far_plane = 50.0f; // pick bounds that cover your scene + float near_plane = 0.1f, far_plane = 50.0f; glm::vec3 lightPos = comp.position; glm::vec3 target = glm::vec3(0.0f, 0.5f, 0.0f); glm::mat4 lightView = glm::lookAt(lightPos, target, glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 lightProjection = glm::ortho(-6.0f, 6.0f, -6.0f, 6.0f, 1.0f, 20.0f); glm::mat4 lightSpaceMatrix = lightProjection * lightView; - // lightView = glm::lookAt(/*eye*/ -lightDir * distance, /*center*/ vec3(0), up) + m_depthShader.use(); + m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix); - // glm::mat4 lightSpaceMatrix = lightProjection * lightView; - SwitchShader(&m_depthShader); - m_currentShader->setMat4("u_lightSpace", lightSpaceMatrix); - - // enable culling and render front faces to the shadow map - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); // only for the depth pass - // or use polygon offset: - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(2.0f, 4.0f); + // glEnable(GL_CULL_FACE); + // glCullFace(GL_FRONT); // only for the depth pass + // glEnable(GL_POLYGON_OFFSET_FILL); + // glPolygonOffset(2.0f, 4.0f); + glCullFace(GL_FRONT); glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); glBindFramebuffer(GL_FRAMEBUFFER, m_depth_fbo); glClear(GL_DEPTH_BUFFER_BIT); - RenderScene(registry); + RenderScene(registry, m_depthShader); glBindFramebuffer(GL_FRAMEBUFFER, 0); + glCullFace(GL_BACK); - // enable culling and render front faces to the shadow map - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); // only for the depth pass - // or use polygon offset: - glDisable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.f, 1.f); + // glEnable(GL_CULL_FACE); + // glCullFace(GL_BACK); // only for the depth pass + // glDisable(GL_POLYGON_OFFSET_FILL); + // glPolygonOffset(0.f, 1.f); glViewport(0, 0, Window::GetWidth(), Window::GetHeight()); + glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - SwitchShader(&m_shader); + m_shader.use(); + m_shader.setInt("shadowMap", 31); - ApplyLights(registry); - - UpdateView(registry); - - m_currentShader->setMat4("u_lightSpace", lightSpaceMatrix); + ApplyLights(registry, m_shader); + UpdateView(registry, m_shader); + m_shader.setMat4("u_lightSpace", lightSpaceMatrix); glActiveTexture(GL_TEXTURE31); glBindTexture(GL_TEXTURE_2D, m_depthMap); - RenderScene(registry); + RenderScene(registry, m_shader); } \ No newline at end of file diff --git a/src/shaders/pbr.fs b/src/shaders/pbr.fs index f728665..02d2a25 100644 --- a/src/shaders/pbr.fs +++ b/src/shaders/pbr.fs @@ -45,33 +45,65 @@ uniform float opacity; #define PI 3.14159265359 #define LIGHT_COLOR vec3(1.0, 1.0, 1.0) +// float ShadowCalculation(vec4 fragPosLightSpace, vec3 N, vec3 L) +// { +// // transform to [0,1] +// vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; +// projCoords = projCoords * 0.5 + 0.5; + +// // if outside light's orthographic frustum => not in shadow +// if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) +// return 0.0; + +// // get depth from shadow map +// float closestDepth = texture(shadowMap, projCoords.xy).r; +// float currentDepth = projCoords.z; + +// // bias to prevent self-shadowing (depend on slope) +// float bias = max(0.001 * (1.0 - dot(N, L)), 0.0005); + +// // PCF (3x3) +// float shadow = 0.0; +// vec2 texelSize = 1.0 / textureSize(shadowMap, 0); +// for(int x = -1; x <= 1; ++x) +// { +// for(int y = -1; y <= 1; ++y) +// { +// float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; +// shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0); +// } +// } +// shadow /= 9.0; + +// return shadow; +// } + float ShadowCalculation(vec4 fragPosLightSpace, vec3 N, vec3 L) { // transform to [0,1] vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; projCoords = projCoords * 0.5 + 0.5; - - // if outside light's orthographic frustum => not in shadow - if (projCoords.z > 1.0 || projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) + if(projCoords.z > 1.0) { return 0.0; + } // get depth from shadow map float closestDepth = texture(shadowMap, projCoords.xy).r; float currentDepth = projCoords.z; // bias to prevent self-shadowing (depend on slope) - float bias = max(0.001 * (1.0 - dot(N, L)), 0.0005); + float bias = max(0.001 * (1.0 - dot(N, L)), 0.0005); + // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; - // PCF (3x3) float shadow = 0.0; vec2 texelSize = 1.0 / textureSize(shadowMap, 0); for(int x = -1; x <= 1; ++x) { for(int y = -1; y <= 1; ++y) { - float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; - shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0); - } + float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; + shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; + } } shadow /= 9.0; diff --git a/src/window/window.cpp b/src/window/window.cpp index 329fdb9..e7a6785 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -54,6 +54,7 @@ Window::Window(const char* title, int width, int height) { glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); glDebugMessageCallback(MessageCallback, nullptr); glViewport(0, 0, m_width, m_height);