Improved C++ Light Class
Next, let's develop a C++ class to encapsulate OpenGL's lighting features. In our implementation, we will encapsulate some of OpenGL's lighting functionality. For now we will only talk about the individual lights.
Before we get to any coding, I want to explain some of OpenGL's lighting algorithms so that you know how to use the functions. When I first learned about OpenGL's lighting functions, I had a hard time learning how to use them.
First, OpenGL requires that the light have either a position or direction vector. If you want the light to be located at a certain position, be sure that the w coordinate is set to one. If w is zero then the light will be located at infinity pointing in the direction you gave. Most people want the light located at infinity if they want a directional light. If you want a point light then specify 1 for w.
Next, OpenGL has a few color parameters that can be set to adjust how the light affects primitives. A primitive can be a triangle, quad, or other basic shape that is defined for the creation of objects. There are three colors that can be set. The first of those is the ambient color which is used to define the lowest possible color that will be visible even if there is no light. For example, if you have no lights on whatsoever, you'll notice it's pitch dark and you can't see anything. When there is ambient light, everything will be lit at constant intensity. That is what this is used for.
The next color is diffuse color which is used for determining what color will light the primitive. If you've ever had a colored light, like a flashlight with a tinted cover, say red, you'll notice that when you shine it one something it will look red. This is the same in OpenGL.
The final color is specular color. Specular color is the "shiny" color that highlights will have. Take metal, for example, when you shine light at it, it will have a very bright highlight. OpenGL supports this and can even specify a different color for specular highlights.
As for the rest of OpenGL's lighting features, I know little about how to use them. I am investigating them however. For now, knowing about colors and directional lights will get you going in the right direction.
Now, we'll implement the individual light class.
class CGL_Light3D {
public:
CGL_Light3D ( );
~CGL_Light3D ( );
void Init ( int light ); // Resets all light information and sets
// current light to a OpenGL light GL_LIGHT0,
// GL_LIGHT1, etc. specified by the user
void SetLight ( int light ); // Similar to Init (light) except that current
// light settings in the class are set to defaults.
void SetValues ( ); // Completely Sets Light Up. Must be called if
// any changes are made to the light.
void TurnOn ( ); // Turns on light
void TurnOff ( ); // Turns off light
void Toggle ( ); // Toggles light on or off
void GetOnOffState ( ); // Returns current on/off state
void SetAmbientColor ( float r, float g, float b, float a );
void GetAmbientColor ( float *r, float *g, float *b, float *a );
void SetAmbientColor ( float c[4] );
void GetAmbientColor ( float *c[4] );
void SetDiffuseColor ( float r, float g, float b, float a );
void GetDiffuseColor ( float *r, float *g, float *b, float *a );
void SetDiffuseColor ( float c[4] );
void GetDiffuseColor ( float *c[4] );
void SetPosition ( float x, float y, float z, float w );
void GetPosition ( float *x, float *y, float *z, float *w );
void SetPosition ( float p[4] );
void GetPosition ( float *p[4] );
void SetSpecular ( float r, float g, float b, float a );
void GetSpecular ( float *r, float *g, float *b, float *a );
void SetSpecular ( float s[4] );
void GetSpecular ( float *s[4] );
/* Spot Light Functions */
void SetSpotDirection ( float x, float y, float z );
void GetSpotDirection ( float *x, float *y, float *z );
void SetSpotDirection ( float s[3] );
void GetSpotDirection ( float *s[3] );
void SetSpotExponent ( float exponent );
float GetSpotExponent ( );
void SetSpotCutoff ( float cutoff );
float GetSpotCutoff ( );
/* Attenuation factors */
void SetConstantAtt ( float constant );
float GetConstantAtt ( );
void SetLinearAtt ( float linear );
float GetLinearAtt ( );
void SetQuadraticAtt ( float quadratic );
float GetQuadraticAtt ( );
private:
int LIGHT;
float ambient[4];
float diffuse[4];
float specular[4];
float position[4];
float spot_direction[3];
float spot_exponent;
float spot_cutoff;
float constant_attenuation;
float linear_attenuation;
float quadratic_attenuation;
int on_off_state;
};
Since most of the function only set values in the class, we'll leave those alone. However, we'll take a look at the Init() and SetValues() functions. Init() simply sets the default values and is compliant with the OpenGL 1.2.1 specification. That means that the default light values are the same as OpenGL's. Init() takes one parameter and that is the same as the corresponding OpenGL ID for the light. So to use the first OpenGL light, GL_LIGHT0, you pass GL_LIGHT0.
void CGL_Light3D::Init ( int light ) {
LIGHT = light;
// set all members to OpenGL defaults
// all values comply with the OpenGL 1.2.1 Specification
ambient[0] = 0.0f;
ambient[1] = 0.0f;
ambient[2] = 0.0f;
ambient[3] = 1.0f;
if ( light == GL_LIGHT0 ) {
diffuse[0] = 1.0f;
diffuse[1] = 1.0f;
diffuse[2] = 1.0f;
diffuse[3] = 1.0f;
} else {
diffuse[0] = 0.0f;
diffuse[1] = 0.0f;
diffuse[2] = 0.0f;
diffuse[3] = 1.0f;
}
if ( light == GL_LIGHT0 ) {
specular[0] = 1.0f;
specular[1] = 1.0f;
specular[2] = 1.0f;
specular[3] = 1.0f;
} else {
specular[0] = 0.0f;
specular[1] = 0.0f;
specular[2] = 0.0f;
specular[3] = 1.0f;
}
position[0] = 0.0f;
position[1] = 1.0f;
position[2] = 0.0f;
position[3] = 0.0f;
spot_direction[0] = 0.0f;
spot_direction[1] = 0.0f;
spot_direction[2] = -1.0f;
spot_exponent = 0.0f;
spot_cutoff = 180.0f;
constant_attenuation = 1.0f;
linear_attenuation = 0.0f;
quadratic_attenuation = 0.0f;
}
SetValues() calls OpenGL and sets all the light parameters that the class is storing. This function must be called after changing any values in the class because it needs to notify OpenGL of the change.
void CGL_Light3D::SetValues ( ) {
glLightfv ( LIGHT, GL_AMBIENT, ambient );
glLightfv ( LIGHT, GL_DIFFUSE, diffuse );
glLightfv ( LIGHT, GL_SPECULAR, specular );
glLightfv ( LIGHT, GL_POSITION, position );
glLightfv ( LIGHT, GL_SPOT_DIRECTION, spot_direction );
glLightfv ( LIGHT, GL_SPOT_EXPONENT, &spot_exponent );
glLightfv ( LIGHT, GL_CONSTANT_ATTENUATION, &constant_attenuation );
glLightfv ( LIGHT, GL_LINEAR_ATTENUATION, &linear_attenuation );
glLightfv ( LIGHT, GL_QUADRATIC_ATTENUATION, &quadratic_attenuation );
}
As you can see, these are pretty straightforward functions. Included in the source is a 2D image library that I hacked so I could make some noise bitmaps for the SuperQuadrics.
|