Light

types of light sources

Ambient light - light comes from everywhere in the space and illuminates all the objects in the same way.

Point light - a light source emits uniformly from a point in space in all directions.

Spot light - a light source emits uniformly from a point in space in restricted cone.

Directional light - parallel ray lights comes from a specific direction.

ambient lighting

Ambient lighting is produced by ambient light. This is general lighting that usually always exists. The level of ambient lighting will dictate brightness of object.

When there are no other light sources, the color of the object can be calculated as follows:

color = objColor * lightAmbient;

diffuse lighting

Diffuse lighting simulates the directional impact of light source on an object.

diffuse color

When angle between normal (perpendicular to the surface) and the light ray is 0 the light has the greatest impact. When angle between normal and the light ray is 90 the light has no impact. So we can use this angle as factor to calculate actual diffuse color.

For this we need normal vector, that has direction from surface. Also we need vector from the light source to the lighted point, let's call it as light direction vector (yeah, actually it is opposite vector to the light direction). If these vectors are unit, then angle between them can be calculated as dot product.

float f = dot(normalize(normal), normalize(lightDirection));
color = objColor * (lightAmbient + lightDiffuse*f);

All calcs must be in same space.

// Lambert's cosine law
// correct
float lambert = dot(worldNormal, worldLightDirection); 
float lambert = dot(viewNormal, viewLightDirection);   

// not correct
float lambert = dot(worldNormal, viewLightDirection); 
float lambert = dot(viewNormal, worldLightDirection); 

If dot product is less than zero, then we set the value to zero - light cannot be negative.

float lambert = max(dot(normal, lightDirection), 0.0);

Usually normal is passed to the shader in model space. Light direction can be given in view space. In this case we must transform normal to the view space with the normal matrix. To get the normal matrix you must invert model view matrix, then transpose it.

Although you can calculate normal matrix in the shader it is not recommended, because shader is executed for each vertex. And the matrix inversion is not cheap operation.

simple light example

In the vertex shader:

...
vec4 transformedNormal = normalMatrix*vec4(vNormal,1.0);
float f = max(dot(transformedNormal.xyz, lightDirectional), 0.0);
exLighting =  lightAmbient + (lightDiffuse * f);

In the fragment shader, the result color can be calculated as follows:

in vec3 exLighting; // will be passed from the vertex shader
...
// get color from texture
vec4 texelColor = texture(sampler, exTexCoord);
// calc result color
gl_FragColor = vec4(texelColor.rgb * exLighting, texelColor.a);

You can download full sources of textured cube with the ambient and directional light on GitHub.