#version 330 core /* @note: an explanation of why the light direction vector is taken from fragment to the light source. Basic LA really, we need to calculate the angle between the direction of the 2 vectors: a. The direction at which light incidents with the fragment b. The normal vector The reason the light direction is taken from the fragment to the light source, is precisely so we can calculate the angle between the normal and the direction at which light would hit. This if taken as starting from the light source would actually be incorrect, since we would be calculating the angle between the light source in the direction of the fragment and the normal. Consider what happens when it is directly above. The angle becomes 180, not 0. This is because the normal moves in the direction opposite to the lights direction if taken this way, which is not what we expect or want. Reversing this, allows us to consider the angle at the point in which light hits the fragment, and the normal vector of the fragment. */ struct Material { sampler2D diffuse; sampler2D specular; float shininess; }; struct Light { vec3 ambient; vec3 diffuse; vec3 specular; vec3 position; }; struct DirectionalLight { vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; }; struct PointLight { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; // attentuation factors float kC; float kL; float kQ; }; struct SpotLight { vec3 position; vec3 ambient; vec3 diffuse; vec3 specular; // attenuation factors float kC; float kL; float kQ; // vector for the direction directly in front of the spotlight vec3 front; // spot radius float radius_inner; float radius_outer; // to smooth out the light }; // this is the result of a light creation. This contains the multipliers for each kind of a light we want // to have. struct LightFactor { vec3 ambient; vec3 diffuse; vec3 specular; }; in vec2 texCoords; in vec3 fragNormal; in vec3 worldPosition; uniform Material material; uniform Light light; uniform DirectionalLight dirLight; uniform PointLight pointLight; uniform PointLight multiPointLight[4]; uniform SpotLight spotLight; uniform vec3 cameraPosition; uniform vec3 lightColor; out vec4 FragColor; LightFactor make_directional_light(DirectionalLight light, vec3 CONST_viewDir) { LightFactor res; vec3 DL_lightDir = normalize(-light.direction); res.ambient = light.ambient; float DL_diffuseStrength = max(dot(DL_lightDir, fragNormal), 0.0); res.diffuse = light.diffuse * DL_diffuseStrength; vec3 DL_reflectDir = reflect(-DL_lightDir, fragNormal); float DL_specularity = max(dot(CONST_viewDir, DL_reflectDir), 0.0); float DL_shinePower = pow(DL_specularity, material.shininess); res.specular = light.specular * DL_shinePower; return res; }; LightFactor make_point_light(PointLight light, vec3 CONST_viewDir) { LightFactor res; float PL_lightDistance = length(light.position - worldPosition); float PL_attenuationFactor = 1.0 / (light.kC + (light.kL * PL_lightDistance) + (light.kQ * PL_lightDistance * PL_lightDistance)); res.ambient = PL_attenuationFactor * light.ambient; vec3 PL_lightDir = normalize(light.position - worldPosition); float PL_diffuseStrength = max(dot(PL_lightDir, fragNormal), 0.0); res.diffuse = PL_attenuationFactor * light.diffuse * PL_diffuseStrength; vec3 PL_reflectDir = reflect(-PL_lightDir, fragNormal); float PL_specularity = max(dot(CONST_viewDir, PL_reflectDir), 0.0); float PL_shinePower = pow(PL_specularity, material.shininess); res.specular = PL_attenuationFactor * PL_shinePower * light.specular; return res; } LightFactor make_spot_light(SpotLight light, vec3 CONST_viewDir) { LightFactor res; float SL_lightDistance = length(light.position - worldPosition); float SL_attenuationFactor = 1.0 / (light.kC + (light.kL * SL_lightDistance) + (light.kQ * SL_lightDistance * SL_lightDistance)); vec3 SL_lightDir = normalize(light.position - worldPosition); res.ambient = SL_attenuationFactor * light.ambient; float SL_diffAmount = dot(SL_lightDir, normalize(-light.front)); float SL_spotLightFadeFactor = clamp((SL_diffAmount - light.radius_outer)/(light.radius_inner - light.radius_outer), 0.0f, 1.0f); float SL_diffuseStrength = max(dot(SL_lightDir, fragNormal), 0.0); res.diffuse = SL_spotLightFadeFactor * SL_attenuationFactor * light.diffuse * SL_diffuseStrength; vec3 SL_reflectDir = reflect(-SL_lightDir, fragNormal); float SL_specularity = max(dot(CONST_viewDir, SL_reflectDir), 0.0); float SL_shinePower = pow(SL_specularity, material.shininess); res.specular = SL_spotLightFadeFactor * SL_attenuationFactor * SL_shinePower * light.specular; return res; } void main() { vec3 CONST_viewDir = normalize(cameraPosition - worldPosition); vec3 combinedAmbience = vec3(0.0); vec3 combinedDiffuse = vec3(0.0); vec3 combinedSpecular = vec3(0.0); // directional light calculations and stuff //LightFactor DL_factors = make_directional_light(dirLight, CONST_viewDir); //combinedAmbience += DL_factors.ambient; //combinedDiffuse += DL_factors.diffuse; //combinedSpecular += DL_factors.specular; // pointlight calculations and stuff //LightFactor PL_factors = make_point_light(pointLight, CONST_viewDir); //combinedAmbience += PL_factors.ambient; //combinedDiffuse += PL_factors.diffuse; //combinedSpecular += PL_factors.specular; // multiple point lights for (int i=0; i<4; i++) { PointLight pl = multiPointLight[i]; LightFactor MPL_factors = make_point_light(pl, CONST_viewDir); combinedAmbience += MPL_factors.ambient; combinedDiffuse += MPL_factors.diffuse; combinedSpecular += MPL_factors.specular; } // spotlight calculations LightFactor SL_factors = make_spot_light(spotLight, CONST_viewDir); combinedAmbience += SL_factors.ambient; combinedDiffuse += SL_factors.diffuse; combinedSpecular += SL_factors.specular; vec3 ambientLight = combinedAmbience * vec3(texture(material.diffuse, texCoords)); vec3 diffuseLight = combinedDiffuse * vec3(texture(material.diffuse, texCoords)); vec3 specularLight = combinedSpecular * vec3(texture(material.specular, texCoords)); vec3 color = ambientLight + diffuseLight + specularLight; FragColor = vec4(color, 1.0); }