#version 330 core out vec4 FragColor; in vec3 FragPos; in vec3 Normal; in vec2 TexCoords; in vec4 FragPosLightSpace; uniform vec3 lightPos; uniform vec3 viewPos; uniform sampler2D shadowMap; uniform sampler2D texture_diffuse1; uniform sampler2D texture_specular1; float ShadowCalculation(vec4 fragPosLightSpace, float bias) { // perform perspective divide vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; // transform to [0,1] range projCoords = projCoords * 0.5 + 0.5; // avoid the frustrum if(projCoords.z > 1.0) return 0.0; // 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; // check whether current frag pos is in shadow // 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; } } return shadow / 9.0; } void main() { vec3 color = texture(texture_diffuse1, TexCoords).rgb; vec3 normal = normalize(Normal); vec3 lightColor = vec3(0.7); // ambient vec3 ambient = 0.3 * lightColor; // diffuse vec3 lightDir = normalize(lightPos - FragPos); float diff = max(dot(lightDir, normal), 0.0); vec3 diffuse = diff * lightColor; // specular vec3 viewDir = normalize(viewPos - FragPos); vec3 reflectDir = reflect(-lightDir, normal); float spec = 0.0; vec3 halfwayDir = normalize(lightDir + viewDir); spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0); vec3 specular = spec * lightColor; // calculate shadow float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); float shadow = ShadowCalculation(FragPosLightSpace, bias); vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color; FragColor = vec4(lighting, 1.0); }