2
\$\begingroup\$

I am experiencing some weird shadow artifacts.

I suspect it to be some sort of self shadowing/depth bias thing.

enter image description here

enter image description here

My shader for the shadow map is quite simple:

shadow_map.vert

#version 450

layout(location = 0) in vec3 in_position;

layout(binding = 0) uniform uniform_scene {
  mat4 light_space;
} scene;

layout(push_constant) uniform uniform_object {
  mat4 model;
} object;

void main() {
  gl_Position = scene.light_space * object.model * vec4(in_position, 1.0);
}

shadow_map.frag:


#version 450

// layout(location = 0) out float out_depth;

void main() {
  // out_depth = gl_FragCoord.z;
}


And for actually doing the depth test for shadows I followed along learnopengl.com since I thought the shader code should be the same for vulkan and opengl.

base.vert

#version 450

struct per_mesh_data {
  mat4 model;
  mat4 normal;
  vec4 tint;
}; // struct per_mesh_data

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(location = 4) out vec4 out_tint;

layout(binding = 0) uniform uniform_scene {
  mat4 view;
  mat4 projection;
  vec3 camera_position;
  mat4 light_space;
  vec3 light_direction;
  vec4 light_color;
} scene;

layout(binding = 1) buffer buffer_mesh_data {
  per_mesh_data data[];
} mesh_data;

const mat4 depth_bias = mat4( 
    0.5, 0.0, 0.0, 0.0,
    0.0, 0.5, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.5, 0.5, 0.0, 1.0
);

void main() {
  per_mesh_data data = mesh_data.data[gl_InstanceIndex]; 

  out_position = vec3(data.model * vec4(in_position, 1.0));
  out_normal = normalize(mat3(data.normal) * in_normal);
  out_uv = in_uv;
  out_light_space_position = (depth_bias * scene.light_space) * vec4(out_position, 1.0);
  out_tint = data.tint;

  gl_Position = scene.projection * scene.view * vec4(out_position, 1.0);
}

base.frag


#version 450

#include "../common/lighting.glsl"
#include "../common/material.glsl"

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 = 4) in vec4 in_tint;

layout(location = 0) out vec4 out_color;

layout(binding = 0) uniform uniform_scene {
  mat4 view;
  mat4 projection;
  vec3 camera_position;
  mat4 light_space;
  vec3 light_direction;
  vec4 light_color;
} scene;

layout(binding = 2) uniform sampler2D image;
layout(binding = 3) uniform sampler2D shadow_map;

layout(push_constant) uniform uniform_object {
  mat4 model;
  mat4 normal;
} object;

const material default_material = material(
  vec4(1.0, 1.0, 1.0, 1.0),
  vec4(1.0, 1.0, 1.0, 1.0),
  vec4(0.5, 0.5, 0.5, 1.0),
  16.0
);

vec4 phong_lighting(vec3 light_direction, vec3 view_direction, vec3 normal, material material) {
  // Ambient
  vec4 ambient_color = scene.light_color * material.ambient;

  // Diffuse
  float diffuse_factor = max(dot(light_direction, normal), 0.0);
  vec4 diffuse_color = diffuse_factor * scene.light_color * material.diffuse;

  // Specular
  vec3 halfway_direction = normalize(light_direction + view_direction);  
  float specular_factor = pow(max(dot(normal, halfway_direction), 0.0), material.shininess);
  vec4 specular_color = specular_factor * scene.light_color * material.specular; 

  return ambient_color + diffuse_color + specular_color;
}

float pcf_shadow(vec3 light_direction) {
  vec2 texture_size = textureSize(shadow_map, 0);
  vec2 texel_size = 1.0 / texture_size;

  vec3 coordinates = in_light_space_position.xyz / in_light_space_position.w;

  if (coordinates.z > 1.0 || coordinates.z < -1.0) {
    return 0.0;
  }

  float shadow = 0.0;

  float bias = max(0.001 * (1.0 - dot(in_normal, light_direction)), 0.0001);
  // float bias = 0.001;
  
  float current_depth = coordinates.z;
  
  int count = 0;
  int range = 2;

  for (int x = -range; x <= range; ++x) {
    for (int y = -range; y <= range; ++y) {
      float pcf_depth = texture(shadow_map, coordinates.xy + vec2(x, y) * texel_size).r;
      shadow += (current_depth - bias) > pcf_depth ? 1.0 : 0.0;
      ++count;
    }
  }

  return shadow / float(count);
}

void main() {
  vec3 light_direction = normalize(-scene.light_direction);
  vec3 view_direction = normalize(scene.camera_position - in_position);

  // Calculate lighting
  vec4 lighting = phong_lighting(light_direction, view_direction, in_normal, default_material);

  // Calculate shadow
  float shadow_factor = pcf_shadow(light_direction);

  // Sample texture
  vec4 sampled_color = texture(image, in_uv);

  vec4 shaded_lighting = mix(lighting * (1.0 - shadow_factor), lighting * 0.2, shadow_factor);

  out_color = shaded_lighting * sampled_color * in_tint;
}


The included files here just define structs like material and directional_light

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If you give the "float bias" variable large constant values? Does it go away? First make sure that bias variable has any effect. If so, then you have two places where you can adjust bias. You can adjust in shader with your existing code which tries to deal with the steep angled surface bias (thats your problem based on the screenshots). Or you can set it in the VkPipelineRasterizationStateCreateInfo, where you can set slope variable as well: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPipelineRasterizationStateCreateInfo.html

The latter is equivalent to the glPolygonOffset but with slope factor which shifts the polygons a bit which helps to eliminate the self shadow issues.

All in all, self shadow elimination is a parameter tuning game, between shadow acne or peter panning artifacts. Variance shadow map technique can help this, which will both solve the hard edges, shimmering, and shadow acne issues.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.