From 4747d297e8d7b471357057d7d0282a01beebd8ae Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Mon, 21 Sep 2026 14:49:59 -0400 Subject: [PATCH] Improved the shadows with a larger texture, PCF for the edges, and only calculating the shadows once. --- 33-shadow-mapping/config.json | 8 ++-- .../shaders/33-framebuffers.frag.glsl | 20 +++++++-- 33-shadow-mapping/src/scene.cpp | 42 +++++++++++-------- 33-shadow-mapping/src/scene.hpp | 4 +- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/33-shadow-mapping/config.json b/33-shadow-mapping/config.json index 585ef07..c742ea0 100644 --- a/33-shadow-mapping/config.json +++ b/33-shadow-mapping/config.json @@ -84,11 +84,11 @@ {"model": "human", "position": [1.28, 0.0, 1.85], "rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]}, "scale": 1.0, - "material": "shiny"}, + "material": "default"}, {"model": "human", "position": [3.13, 0.80, 3.04], "rotation": {"angle": 0.0, "axes": [1.0, 1.0, 1.0]}, "scale": 1.0, - "material": "shiny"}, + "material": "default"}, {"model": "window", "position": [1.5, 0.25, 0.0], "rotation": {"angle": 90.0, "axes": [1.0,0.0,0.0]}, "scale": 1.0, @@ -107,8 +107,6 @@ }, "light": { "directional": [ - ], - "positioned": [ { "position": [-2.0, 4.0, -1.0], "direction":[0.0, 0.0, 0.0], @@ -123,6 +121,8 @@ "on": true } ], + "positioned": [ + ], "spot": [ ], "camera": { diff --git a/33-shadow-mapping/shaders/33-framebuffers.frag.glsl b/33-shadow-mapping/shaders/33-framebuffers.frag.glsl index 7602e8b..1b61769 100644 --- a/33-shadow-mapping/shaders/33-framebuffers.frag.glsl +++ b/33-shadow-mapping/shaders/33-framebuffers.frag.glsl @@ -16,17 +16,31 @@ float ShadowCalculation(vec4 fragPosLightSpace, float bias) { // perform perspective divide vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; + // transform to [0,1] range projCoords = projCoords * 0.5 + 0.5; + + // avoid the frustrum + if(projCoords.z > 1.0) return 0.0; + // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords) float closestDepth = texture(shadowMap, projCoords.xy).r; + // get depth of current fragment from light's perspective float currentDepth = projCoords.z; + // check whether current frag pos is in shadow + // PCF + 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 shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; - - return shadow; + return shadow / 9.0; } void main() diff --git a/33-shadow-mapping/src/scene.cpp b/33-shadow-mapping/src/scene.cpp index 19ff320..febcf10 100644 --- a/33-shadow-mapping/src/scene.cpp +++ b/33-shadow-mapping/src/scene.cpp @@ -53,18 +53,6 @@ void Scene::render_scene(GLFWwindow* window, Shader& with_shader) { } void Scene::render_shadows(GLFWwindow* window) { - // temporarily use the config.json positioned even though this is doing a directional - auto& light_pos = light.positioned.at(0).position; - - glm::mat4 proj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, depth_near_plane, depth_far_plane); - glm::mat4 view = glm::lookAt(light_pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); - - light_space = proj * view; - - depth_shader.use(); - depth_shader.setMat4("lightSpaceMatrix", light_space); - depth_shader.setFloat("near_plane", depth_near_plane); - depth_shader.setFloat("far_plane", depth_far_plane); glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); @@ -73,7 +61,21 @@ void Scene::render_shadows(GLFWwindow* window) { glEnable(GL_DEPTH_TEST); glClear(GL_DEPTH_BUFFER_BIT); - render_scene(window, depth_shader); + // temporarily use the config.json positioned even though this is doing a directional + for(auto& dir_light : light.directional) { + auto& light_pos = dir_light.position; + glm::mat4 proj = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, depth_near_plane, depth_far_plane); + glm::mat4 view = glm::lookAt(light_pos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + + light_space = proj * view; + + depth_shader.use(); + depth_shader.setMat4("lightSpaceMatrix", light_space); + depth_shader.setFloat("near_plane", depth_near_plane); + depth_shader.setFloat("far_plane", depth_far_plane); + + render_scene(window, depth_shader); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_DEPTH_TEST); @@ -84,7 +86,10 @@ void Scene::render_shadows(GLFWwindow* window) { void Scene::render(GLFWwindow* window) { auto& with_shader = reflect_on ? reflect_shader : shader; - render_shadows(window); + if(!shadows_rendered) { + shadows_rendered = true; + render_shadows(window); + } // set depth_map on TEXTURE0 glActiveTexture(GL_TEXTURE0); @@ -94,7 +99,7 @@ void Scene::render(GLFWwindow* window) { with_shader.setInt("shadowMap", 0); // NOTE: in the shader is it viewPos or cameraPos? with_shader.setVec3("viewPos", camera.position); - with_shader.setVec3("lightPos", light.positioned.at(0).position); + with_shader.setVec3("lightPos", light.directional.at(0).position); with_shader.setMat4("lightSpaceMatrix", light_space); framebuffer.begin(); @@ -153,8 +158,11 @@ void Scene::init_shadows() { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 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); + // set to clamp border with a color of one to remove the frustrum culled part of the shadow + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + float border_color[4]{1.0f, 1.0f, 1.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_map, 0); glDrawBuffer(GL_NONE); diff --git a/33-shadow-mapping/src/scene.hpp b/33-shadow-mapping/src/scene.hpp index cc28cf1..5f936c0 100644 --- a/33-shadow-mapping/src/scene.hpp +++ b/33-shadow-mapping/src/scene.hpp @@ -52,7 +52,7 @@ struct Scene { Shader depth_dbg_shader{{"shaders/33-shadow_dbg.vert.glsl", "shaders/33-shadow_dbg.frag.glsl", ""}}; unsigned int depth_FBO = UINT_MAX; unsigned int depth_map = UINT_MAX; - const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; + const unsigned int SHADOW_WIDTH = 1024 * 8, SHADOW_HEIGHT = 1024 * 8; float near_plane = 1.0f; float far_plane = 100.0f; @@ -74,6 +74,8 @@ struct Scene { unsigned int quadVAO = UINT_MAX; unsigned int quadVBO = UINT_MAX; + bool shadows_rendered = false; + Scene(components::Scene& config): shader{config.shader}, reflect_shader{config.reflect_shader},