OpenGL shadow peter-panning

I add shadows to the scene in OpenGL, making two passes of passage, one to the depth map and one to the regular frame buffer.

Without using offset, when using a depth map, there are many shadow eels.

shadow without corners

This is fixed by adding an offset to the depth map check.

slanted shadow

However, this causes the shadow to "separate" from the object when the light moves at a different angle.

peter panning

I believe this effect is called peter panning and is caused by the large offset used for different angles.

The usual fix for this seems to be to drop backward triangles when drawing a shadow map, however, since the floor plane is a two-dimensional object, I don't believe that this will work properly.

The actual terrain I am using is procedurally generated, and therefore it is not as easy to create a 3D version as in this simple example.

How can I lock peter pan on a 2D object like this?


Vertex Shader

#version 400 layout(location = 0) in vec3 position; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 texture_coords; out VS_OUT { vec4 position; vec3 normal; vec2 texture_coords; vec4 shadow_position; } vs_out; uniform mat4 model; uniform mat4 model_view; uniform mat4 model_view_perspective; uniform mat3 normal_matrix; uniform mat4 depth_matrix; void main() { vec4 position_v4 = vec4(position, 1.0); vs_out.position = model_view * position_v4; vs_out.normal = normal_matrix * normal; vs_out.texture_coords = texture_coords; vs_out.shadow_position = depth_matrix * model * position_v4; gl_Position = model_view_perspective * position_v4; } 

Fragment shader

 #version 400 in VS_OUT { vec4 position; vec3 normal; vec2 texture_coords; vec4 shadow_position; } fs_in; out vec4 colour; uniform mat4 view; uniform mat4 model_view_perspective; uniform vec3 light_position; uniform vec3 emissive_light; uniform float shininess; uniform int textured; uniform sampler2D tex; uniform sampler2DShadow shadow_texture; void main() { const vec3 specular_albedo = vec3(1.0, 0.8, 0.6); colour = vec4(0.8, 0.8, 0.8, 0.8); if(textured != 0) { colour = texture(tex, fs_in.texture_coords); } vec3 light_direction = normalize(light_position); vec3 normal = normalize(fs_in.normal); float visibility = 1.0; if(fs_in.shadow_position.z <= 1.0) { float bias = max(0.05 * (1.0 - dot(normal, light_direction)), 0.005); if(fs_in.shadow_position.z > texture(shadow_texture, fs_in.shadow_position.xyz, 0.0) + bias){ visibility = 0.0; } } /* Ambient */ vec3 ambient = colour.xyz * 0.1; /* Diffuse */ vec3 diffuse = visibility * (clamp(dot(normal, light_direction), 0, 1) * colour.xyz); /* Specular */ vec3 specular = vec3(0.0); if(dot(normal, light_direction) > 0) { vec3 V = normalize(-fs_in.position.xyz); vec3 half_dir = normalize(light_direction + V); specular = visibility * (pow(max(dot(normal, half_dir), 0.0), shininess) * specular_albedo.xyz); } colour = vec4(((ambient + diffuse) * colour.xyz) + specular + emissive_light, 1.0); } 
+5
source share
1 answer

https://msdn.microsoft.com/en-us/library/windows/desktop/ee416324(v=vs.85).aspx

The calculation of dense near planes and far planes also helps to avoid Peter Paning.

Slope Departure

As mentioned earlier, self-shadowing can lead to shadow acne. Adding too much bias can lead to Peter Paning. Additionally, polygons with steep slopes (relative to light) suffer more from projective smoothing than polygons with shallow slopes (relatively light). Because of this, each value of the depth map may require a different offset depending on the slope of the polygon relative to the light.

Hardware Direct3D 10+ has the ability to offset the polygon based on its slope relative to the viewing direction. This leads to applying a large offset to the polygon, which is viewed by the edge of the light in the direction, but not applying any offset to the polygon facing the light directly. Figure 10 shows how two adjacent pixels can alternate between shaded and unshaded when tested for the same unbiased slope.

http://www.sunandblackcat.com/tipFullView.php?l=eng&topicid=35

The challenge is to determine the optimal offset for each depth in the shadow map. If you apply insufficient bias, the z-fight will still be present. If you apply a very large offset, then Peter Panning will be noticeable. The offset should depend on the accuracy of the shadow map and on the slope of the surface relative to the direction to the light source.

OpenGL can automatically calculate and add the offset to the values ​​that are stored in the Z-buffer. You can adjust the offset using the glPolygonOffset function. Two parameters are available: a factor for the offset, which depends on the slope of the surface, and a value that determines the number of additional smallest possible offsets (depends on the format of the map shadow):

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml

+2
source

Source: https://habr.com/ru/post/1259954/


All Articles