How lighting works
|Warning: This article describes legacy OpenGL APIs that have been removed from core OpenGL 3.1 and above (they are only deprecated in OpenGL 3.0). It is recommended that you not use this functionality in your
How lighting works
|Warning: This article describes legacy OpenGL APIs that have been removed from core OpenGL 3.1 and above (they are only deprecated in OpenGL 3.0). It is recommended that you not use this functionality in your programs.|
Many people starting out with OpenGL are confused by the way that OpenGL's built-in lighting works - and consequently how colour functions. This page aims clear up some of the confusion.
What is needed to explain this clearly is a flow chart:
Lighting ENABLED or DISABLED?
The first - and most basic - decision is whether to enable lighting or not.
glEnable ( GL_LIGHTING ) ;
glDisable ( GL_LIGHTING ) ;
If it's disabled then all polygons, lines and points will be coloured according to the setting of the various forms of the glColor command. Those colours will be carried forward without any change other than is imparted by texture or fog if those are also enabled. Hence:
glColor3f ( 1.0f, 0.0f, 0.0f ) ;
...gets you a pure red triangle no matter how it is positioned relative to the light source(s).
With GL_LIGHTING enabled, we need to specify more about the surface than just it's colour - we also need to know how shiney it is, whether it glows in the dark and whether it scatters light uniformly or in a more directional manner.
The idea is that OpenGL switches over to using the current settings of the current'material' instead of the simplistic idea of a polygon 'colour' that is sufficient when lighting is disabled. We shall soon see that this is an over-simplistic explanation - but keep it firmly in mind.
glMaterial and glLight
The OpenGL light model presumes that the light that reaches your eye from the polygon surface arrives by four different mechanisms:
- AMBIENT - light that comes from all directions equally and is scattered in all directions equally by the polygons in your scene. This isn't quite true of the real world - but it's a good first approximation for light that comes pretty much uniformly from the sky and arrives onto a surface by bouncing off so many other surfaces that it might as well be uniform.
- DIFFUSE - light that comes from a particular point source (like the Sun) and hits surfaces with an intensity that depends on whether they face towards the light or away from it. However, once the light radiates from the surface, it does so equally in all directions. It is diffuse lighting that best defines the shape of 3D objects.
- SPECULAR - as with diffuse lighting, the light comes from a point souce, but with specular lighting, it is reflected more in the manner of a mirror where most of the light bounces off in a particular direction defined by the surface shape. Specular lighting is what produces the shiney highlights and helps us to distinguish between flat, dull surfaces such as plaster and shiney surfaces like polished plastics and metals.
- EMISSION - in this case, the light is actually emitted by the polygon - equally in all directions.
So, there are three light colours for each light - Ambient, Diffuse and Specular (set with glLight) and four for each surface (set with glMaterial). All OpenGL implementations support at least eight light sources - and the glMaterial can be changed at will for each polygon (although there are typically large time penalties for doing that - so we'd like to minimise the number of changes).
The final polygon colour is the sum of all four light components, each of which is formed by multiplying the glMaterial colour by the glLight colour (modified by the directionality in the case of Diffuse and Specular). Since there is no Emission colour for the glLight, that is added to the final colour without modification.
A good set of settings for a light source would be to set the Diffuse and Specular components to the colour of the light source, and the Ambient to the same colour - but at MUCH reduced intensity, 10% to 40% seems reasonable in most cases.
For the glMaterial, it's usual to set the Ambient and Diffuse colours to the natural colour of the object and to put the Specular colour to white. The emission colour is generally black for objects that do not shine by their own light.
Before you can use an OpenGL light source, it must be positioned using the glLight command and enabled using glEnable(GL_LIGHTn) where 'n' is 0 through 7. There are additional commands to make light sources directional (like a spotlight or a flashlight) and to have it attenuate as a function of range from the light source.
This is without doubt the most confusing thing about OpenGL lighting - and the biggest cause of problems for beginners.
The problem with using glMaterial to change polygon colours is three-fold:
- It's slow. Well, the OpenGL manual says it's slow - but it's not certain that all implementations will have trouble with it.
- You frequently need to change glMaterial properties for both Ambient and Diffuse to identical values - this takes two OpenGL function calls which is annoying.
- You cannot change glMaterial settings with many of the more advanced polygon rendering techniques such as Vertex arrays and glDrawElements.
For these reasons, OpenGL has a feature that allows you do drive the glMaterial colours using the more flexible glColor command (which is not otherwise useful when lighting is enabled).
To drive (say) the Emission component of the glMaterial using glColor, you must say:
glColorMaterial ( GL_FRONT_AND_BACK, GL_EMISSION ) ; glEnable ( GL_COLOR_MATERIAL ) ;
From this point performing a glColor command (or setting the glColor via a vertex array or something) has the exact same effect as calling:
glMaterial ( GL_FRONT_AND_BACK, GL_EMISSION,...colours... ) ;
One especially useful option i