#version 330 core layout(location = 0) out vec4 f_color; in vec3 v_normal; in vec2 v_texCoord; in vec3 v_fragmentPosition; in vec3 v_fragmentPositionTangent; in vec4 v_fragmentPositionDirectionalLightSpace; in vec3 v_lightDirectionTangent; in vec3 v_lightPositionTangent0; //in vec3 v_lightPositionTangent1; //in vec3 v_lightPositionTangent2; //in vec3 v_lightPositionTangent3; in vec3 v_viewPositionTangent; struct Material { sampler2D texture_diffuse0; sampler2D texture_diffuse1; sampler2D texture_specular0; sampler2D texture_normal0; sampler2D texture_height0; sampler2D texture_gloss0; float shininess; }; uniform Material u_material; struct DirectionalLight { vec3 direction; bool isActive; vec3 color; }; uniform DirectionalLight u_directionalLight; struct PointLight { vec3 position; bool isActive; vec3 color; }; #define NUM_POINT_LIGHTS 1 uniform PointLight u_pointLight[NUM_POINT_LIGHTS]; /*struct SpotLight { bool isActive; vec3 position; vec3 direction; float innerCutOff; float outerCutOff; float K_q; vec3 ambient; vec3 diffuse; vec3 specular; }; uniform SpotLight u_spotLight;*/ uniform mat3 u_normalMatrix; uniform sampler2D u_texture_directionalShadowMap; uniform samplerCube u_texture_pointShadowMap0; //uniform samplerCube u_texture_pointShadowMap1; //uniform samplerCube u_texture_pointShadowMap2; //uniform samplerCube u_texture_pointShadowMap3; vec3 sampleOffsetDirections[20] = vec3[] ( vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) ); uniform bool b_drawShadows; uniform float pointShadowDepthMapFarPlane; vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir); vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); //vec3 spotLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir); void computeShading( vec3 light_ambient, vec3 light_diffuse, vec3 light_specular, vec3 lightDir, vec3 viewDir, vec3 normal, out vec3 ambient, out vec3 diffuse, out vec3 specular ); float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q); float computeDirectionalShadows(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir); float computePointShadows(vec3 fragPos, vec3 lightPos); void main() { vec3 fragmentColor = vec3(0.0f); vec3 normal = texture(u_material.texture_normal0, v_texCoord).rgb; normal = normalize(normal * 2.0 - 1.0); vec3 viewDir = normalize(v_viewPositionTangent - v_fragmentPositionTangent); fragmentColor += directionalLightContribution(u_directionalLight, normal, viewDir); for(int i = 0; i < NUM_POINT_LIGHTS; i++) { fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPositionTangent, viewDir); } // There are currently no spotlights //fragmentColor += spotLightContribution(u_spotLight, normal, v_fragmentPositionTangent, viewDir); f_color = vec4(fragmentColor, 1.0f); } vec3 directionalLightContribution(DirectionalLight light, vec3 normal, vec3 viewDir) { // Only compute if light source is active if(!light.isActive) return vec3(0.0f); //vec3 lightDir = normalize(-light.direction); vec3 lightDir = normalize(-v_lightDirectionTangent); vec3 diffuseColor = light.color; vec3 specularColor = light.color * 0.5f; vec3 ambientColor = light.color * 0.002f; vec3 ambient, diffuse, specular; computeShading(ambientColor, diffuseColor, specularColor, lightDir, viewDir, normal, ambient, diffuse, specular); float shadows = 0.0f; if(b_drawShadows) shadows = computeDirectionalShadows(v_fragmentPositionDirectionalLightSpace, normal, lightDir); return (ambient + (1.0f - shadows) * (diffuse + specular)); } vec3 pointLightContribution(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { // Only compute if light source is active if(!light.isActive) return vec3(0.0f); vec3 lightDir = normalize(v_lightPositionTangent0 - fragPos); vec3 diffuseColor = light.color; vec3 specularColor = light.color * 0.5f; vec3 ambientColor = light.color * 0.002f; vec3 ambient, diffuse, specular; computeShading(ambientColor, diffuseColor, specularColor, lightDir, viewDir, normal, ambient, diffuse, specular); float attenuation = computeAttenuation(v_lightPositionTangent0, fragPos, 0.032f); //ambient *= attenuation; //diffuse *= attenuation; //specular *= attenuation; float shadows = 0.0f; if(b_drawShadows) shadows = computePointShadows(v_fragmentPosition, light.position); return (ambient + (1.0f - shadows) * (diffuse + specular)); } /*vec3 spotLightContribution(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir) { // Only compute if light source is active if(!light.isActive) return vec3(0.0f); vec3 lightDir = normalize(light.position - fragPos); vec3 ambient, diffuse, specular; computeShading(light.ambient, light.diffuse, light.specular, lightDir, viewDir, normal, ambient, diffuse, specular); float attenuation = computeAttenuation(light.position, fragPos, light.K_q); ambient *= attenuation; diffuse *= attenuation; specular *= attenuation; float theta = dot(lightDir, normalize(-light.direction)); float epsilon = light.innerCutOff - light.outerCutOff; float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0f, 1.0f); diffuse *= intensity; specular *= intensity; return (ambient + diffuse + specular); }*/ void computeShading( vec3 light_ambient, vec3 light_diffuse, vec3 light_specular, vec3 lightDir, vec3 viewDir, vec3 normal, out vec3 ambient, out vec3 diffuse, out vec3 specular) { // Diffuse shading float diffuseShading = max(dot(normal, lightDir), 0.0f); // Specular shading vec3 halfwayDir = normalize(lightDir + viewDir); float specularShading = pow(max(dot(normal, halfwayDir), 0.0f), u_material.shininess); vec4 diffuseTex = texture(u_material.texture_diffuse0, v_texCoord); vec4 specularTex = texture(u_material.texture_specular0, v_texCoord); ambient = light_ambient * vec3(diffuseTex); diffuse = light_diffuse * diffuseShading * vec3(diffuseTex); specular = light_specular * specularShading * vec3(specularTex); } float computeAttenuation(vec3 lightPos, vec3 fragPos, float K_q) { float distanceLightFragment = length(lightPos - fragPos); return 1.0f / (K_q * distanceLightFragment * distanceLightFragment); } float computeDirectionalShadows(vec4 fragPosLightSpace, vec3 normal, vec3 lightDir) { // Perspective divide vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; // Transform from [-1,1] to [0,1] projCoords *= 0.5f; projCoords += 0.5f; if(projCoords.z > 1.0f) return 0.0f; float closestDepth = texture(u_texture_directionalShadowMap, projCoords.xy).r; float currentDepth = projCoords.z; float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); bias *= 0.25f; float shadow = 0.0; vec2 texelSize = 1.0 / textureSize(u_texture_directionalShadowMap, 0); for(int x = -1; x <= 1; x++) { for(int y = -1; y <= 1; y++) { float pcfDepth = texture(u_texture_directionalShadowMap, projCoords.xy + vec2(x, y) * texelSize).r; shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; } } shadow /= 9.0f; return shadow; } float computePointShadows(vec3 fragPos, vec3 lightPos) { // get vector between fragment position and light position vec3 fragToLight = fragPos - lightPos; // now get current linear depth as the length between the fragment and light position float currentDepth = length(fragToLight); float shadow = 0.0; float bias = 0.05; int samples = 20; float viewDistance = length(v_viewPositionTangent - fragPos); float diskRadius = 0.05; for(int i = 0; i < samples; ++i) { float closestDepth = texture(u_texture_pointShadowMap0, fragToLight + sampleOffsetDirections[i] * diskRadius).r; closestDepth *= pointShadowDepthMapFarPlane; if(currentDepth - bias > closestDepth) shadow += 1.0; } shadow /= float(samples); return shadow; }