Now that our surface has normals we can light it with the afore-mentioned Phong illumination model. This model breaks lighting into 3 components: ambient, diffuse and specular.

**Ambient** light is that light which is everywhere due to light reflecting of other surfaces. If you look at the underside of your chair you will notice that there is some light, despite there not being a light shining directly on it. Ideally one would use a global illumination method to calculate this properly. Under Phong this is just a constant

**Diffuse** light is that which results from being in direct illumination from a light source. The defining characteristic of diffuse light is that it is strongest when the light is pointing directly at the surface and less when it is at an angle. Of course when the angle between the 2 hits 90 degrees there is no diffuse light at all (or if it is on the underside of an object). Under phong this is calculated using the angle between the surface normal and the direction to the light source.

Here the angle between the direction to the Light (L) and surface is calculated using the dot product between the normal (N) and light direction. This has the property that when they are in the same direction they will be 1 and when they are 90 degrees apart they will be 0.

**Specular** light is that which comes from the light source itself reflecting off the surface and into the camera. This allows us to model shiny (although not reflective) surfaces. Under Phong we now add the direction to the camera and compare the angle between this vector and the reflected vector from the light source. If they match up we have a reflection and if they don’t, neither do we.

The alpha in this equation determines how wide the spot of light will be. A small alpha equates to a larger spotlight.

But we can get the same results from a slightly different formula that is a little more efficient.

Instead of having to reflect the light vector to get the vector to compare against the view we can use what is known as the ‘Half Vector’. If we add the Light Vector and View Vector we will get something which should point directly away from the surface if they are reflected exactly around the normal (i.e there should be a specular reflection) and will point elsewhere if it they aren’t. As such we can compare this half vector with the normal for the same effect. Making the equation to use:

The wikipedia article has more if you are interested and is where I got the following demonstrative picture which clearly shows how each of these three components are used to create the final lighting of a strange object:

That is all well and good but we need to convert this into code. We can do this using the GLSL shaders introduced last time. As such the Vertex shader looks like this:

varying vec3 normal; varying vec3 eyeDir; varying vec3 lightDir; void main() { gl_Position = ftransform(); normal = normalize(gl_NormalMatrix * gl_Normal); vec3 vertex = vec3(gl_ModelViewMatrix * gl_Vertex); lightDir = normalize(gl_LightSource[0].position.xyz - vertex); eyeDir = normalize(-vertex); gl_FrontColor = gl_Color; } \n\

Here we calculate all the vectors we need for computing the lighting. These will then be interpolated between each vertex to be correct on the per-pixel level. This is far more efficient than computing them at each pixel. This approach can have problems for very large surfaces where the interpolation may not be done correctly / may be undefined. Our glass is fairly high resolution so this isn’t an issue here.

The Fragment shader then looks like this:

varying vec3 normal; varying vec3 eyeDir; varying vec3 lightDir; void main() { vec3 ambient = vec3(0.2,0.2,0.2); vec3 diffuse = vec3(0.8,0.8,0.8)*( max(dot(normal,lightDir), 0.0); vec3 specular = pow(max(dot(normal,normalize(lightDir+eyeDir)),0.0),30.0)); vec3 lightCol = diffuse + specular + ambient; gl_FragColor = vec4(gl_Color.rgb * lightCol,1.0); }

Here we calculate the 3 components (ambient, diffuse and specular) to create the intensity of the light at that point. This is then multiplied with the colour of the surface to get the final colour of the pixel.

This then gives us this image for our glass: