#version 460 core in vec2 vert_texcoord; in vec4 vert_pos; out vec4 frag_color; uniform sampler2D tex; uniform sampler2D shadowmap; float ShadowCalculation(vec4 fragPosLightSpace) { // perform perspective divide vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; // transform to [0,1] range projCoords = projCoords * 0.5 + 0.5; // 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; // calculate bias (based on depth map resolution and slope) float bias = 0.005; // check whether current frag pos is in shadow // float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; // 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; } } shadow /= 9.0; // keep the shadow at 0.0 when outside the far_plane region of the light's frustum. if(projCoords.z > 1.0) shadow = 0.0; return shadow; } void main() { vec3 lightColor = vec3(1.0); vec3 ambient = 0.5 * lightColor; frag_color = texture(tex, vert_texcoord); float shadow = ShadowCalculation(vert_pos); if(frag_color.a < 0.1) discard; frag_color = vec4((ambient + (1.0 - shadow)) * frag_color.xyz, frag_color.a); }