Although I do not understand this entirely, I think I found the bug: I needed to transform the coordinates to NDC space and THEN multiply the matrices. My shadow coordinate computation now looks like this:
mat4 biasMatrix = mat4(
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f
);
vec4 shadowCoord0 = biasMatrix * light * vec4(vertexPosition, 1.0f);
shadowCoord = shadowCoord0.xyz / shadowCoord0.w;
where
light = projectionMatrix * inverseLightTransformationMatrix
* modelTransformationMatrix
Now the fragment shader's shadow factor computation is rather simple:
float shadowFactor = 1.0f;
if (texture(shadowMapSampler, shadowCoord.xy).z < shadowCoord.z - 0.0001f)
shadowFactor = 0.0f;