I am encountering some weird artefacts when rendering shadows using a shadow map.
I am using C++ with Vulkan and GLSL shaders.
This is the vertex shader that calculates the light_space_position
:
#version 450
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_uv;
layout(location = 0) out vec3 out_position;
layout(location = 1) out vec3 out_normal;
layout(location = 2) out vec2 out_uv;
layout(location = 3) out vec4 out_light_space_position;
layout(binding = 0) uniform uniform_scene {
mat4 view;
mat4 projection;
vec3 camera_position;
mat4 light_space;
} scene;
void main() {
out_position = vec3(object.model * vec4(in_position, 1.0));
out_normal = normalize(mat3(object.normal) * in_normal);
out_uv = in_uv;
out_light_space_position = scene.light_space * vec4(out_position, 1.0);
gl_Position = scene.projection * scene.view * vec4(out_position, 1.0);
}
This is the fragment shader code:
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_uv;
layout(location = 3) in vec4 in_light_space_position;
layout(location = 0) out vec4 out_color;
layout(binding = 0) uniform uniform_scene {
mat4 view;
mat4 projection;
vec3 camera_position;
mat4 light_space;
} scene;
layout(binding = 2) uniform sampler2D image;
layout(binding = 3) uniform sampler2D shadow_map;
const vec3 light_position = vec3(2.0, 5.0, 2.0);
float calculate_shadow(vec4 light_space_position, vec3 light_dir) {
vec3 projection_coords = light_space_position.xyz / light_space_position.w;
projection_coords = projection_coords * 0.5 + 0.5;
float current_depth = projection_coords.z;
float closest_depth = texture(shadow_map, projection_coords.xy).r;
float bias = max(0.05 * (1.0 - dot(in_normal, light_dir)), 0.005);
return (current_depth - bias) > closest_depth ? 1.0 : 0.0;
}
void main() {
vec4 color = texture(image, in_uv);
vec4 light_color = vec4(1.0, 1.0, 1.0, 1.0);
// ambient
vec4 ambient = 0.15 * light_color;
// diffuse
vec3 light_dir = normalize(light_position - in_position);
float diff = max(dot(light_dir, in_normal), 0.0);
vec4 diffuse = diff * light_color;
// specular
vec3 view_dir = normalize(scene.camera_position - in_position);
float spec = 0.0;
vec3 halfway_dir = normalize(light_dir + view_dir);
spec = pow(max(dot(in_normal, halfway_dir), 0.0), 64.0);
vec4 specular = spec * light_color;
// calculate shadow
float shadow = calculate_shadow(in_light_space_position, light_dir);
out_color = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
}