For examples mentioned in the lab notes click here
Download the lab instructor's lecture demo here.
OpenGL supports two color modes. The first is RGBA model, where you select the value of the red, green, blue and alpha(opacity) parameters. The second is color-index mode, whereby you fill a palette with the colors. We will focus on RGBA mode, because most of the interesting things you can do involve lighting and textures, which are difficult to do using a color palette. When you are using lighting or texture-mapping effects(lighting is turned on), the color of the vertex is the cumulative effect of the material color and the light that's shining on that vertex. When the light is turned off, the color of a vertex is the effect of the color setting.
Color in RGBA mode is set by specifying the red, green, blue and alpha intensities. The glColor*() comes in a variety of formats. You can specify a bright red triangle using the following commands:
glColor3f(1.0f, 0.0f, 0.0f); //no alpha value form glBegin(GL_TRIANGLES); glVertex3f(-1, 0, 0); glVertex3f(1, 0, 0); glVertex3f(0, 1, 0); glEnd();
Notice that the glColor*() function can be placed inside a glBegin()/glEnd() pair. Thus you can specify individual colors for each individual vertex if you desire. If the colors of two vertices are different, what is the color between the two vertices? For example, what is the color of the center of the triangle in the following code?
glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); //red glVertex3f(-1, 0, 0); glColor3f(0.0f, 1.0f, 0.0f); //green glVertex3f(1, 0, 0); glColor3f(0.0f, 0.0f, 1.0f); //blue glVertex3f(0, 1, 0); glEnd();
The answer is that it depends on the shading model specified. If smooth shading(default) is specified, the color values are interpolated between vertices. In this case the color at the center would be gray. If flat shading is specified, the one vertex is selected as being representative of all the vertices; thus the entire primitive is displayed using one single color. For a single polygon, the first vertex is used to specified to color; for all the other primitives it the last specified vertex in each polygon or line segment.
The following is a cube model that the top is left off and a small black ball is placed inside the cube.
BOOL CColorView::RenderScene( void ) { glColor3f( 0.0f, 0.0f, 0.0f ); auxSolidSphere( 0.3f ); // <- slight memory leak here //glShadeModel( GL_FLAT ); // to show flat shading // define the colors GLfloat color1[3] = { 1.0f, 0.0f, 0.0f }; // red GLfloat color2[3] = { 0.0f, 1.0f, 0.0f }; // green GLfloat color3[3] = { 0.0f, 0.0f, 1.0f }; // blue GLfloat color4[3] = { 1.0f, 1.0f, 1.0f }; // white GLfloat color5[3] = { 0.0f, 0.0f, 0.0f }; // black GLfloat color6[3] = { 1.0f, 0.0f, 1.0f }; // magenta GLfloat color7[3] = { 0.0f, 1.0f, 1.0f }; // cyan GLfloat color8[3] = { 1.0f, 1.0f, 0.0f }; // yellow // Connect the four sides glBegin(GL_QUAD_STRIP); glColor3fv( color6 ); glVertex3f(-1.0f, 1.0f, 1.0f); glColor3fv( color1 ); glVertex3f(-1.0f, -1.0f, 1.0f); glColor3fv( color4 ); glVertex3f(1.0f, 1.0f, 1.0f); glColor3fv( color8 ); glVertex3f(1.0f, -1.0f, 1.0f); glColor3fv( color7 ); glVertex3f(1.0f, 1.0f, -1.0f); glColor3fv( color2 ); glVertex3f(1.0f, -1.0f, -1.0f); glColor3fv( color3 ); glVertex3f(-1.0f, 1.0f, -1.0f); glColor3fv( color5 ); glVertex3f(-1.0f, -1.0f, -1.0f); glColor3fv( color6 ); glVertex3f(-1.0f, 1.0f, 1.0f); glColor3fv( color1 ); glVertex3f(-1.0f, -1.0f, 1.0f); glEnd(); // The Bottom glBegin(GL_QUADS); glColor3fv( color1 ); glVertex3f(-1.0f, -1.0f, 1.0f); glColor3fv( color8 ); glVertex3f(1.0f, -1.0f, 1.0f); glColor3fv( color2 ); glVertex3f(1.0f, -1.0f, -1.0f); glColor3fv( color5 ); glVertex3f(-1.0f, -1.0f, -1.0f); glEnd(); return TRUE; }
This model draws the color cube -- red, green and blue as one triplet; cyan, magenta and yellow as another triplet; Figure 1 shows the effect of smooth shading. With no lighting effects, it is very hard to distinguish between the faces of the polygons that makes up an object. Figure 2 shows the same scene with flat shading. The color of each face is entirely the result of the order in which the vertices were specified.
OpenGL's materials are descriptions of what things are made of -- or at least what they appear to be made of -- by describing how they reflect light.
OpenGL has five properties that describe how a surface dissipates light. These properties are typically described by RGBA values that stipulate the color of the dissipated light.
Specifying a material property is almost the same as specifying a color. Let's specify a gray material for both the ambient and diffuse properties.
GLfloat materialDiffuse[] = {0.2, 0.2, 0.2, 1}; GLfloat materialAmbient[] = {0.5, 0.5, 0.5, 1}; ::glMaterialfv(GL_FRONT, GL_DIFFUSE, materialDiffuse); ::glMaterialfv(GL_FRONT, GL_AMBIENT, materialAmbient);
glMaterial*() is used to specify the materials properties that make up the resultant color of a surface. The first parameter indicates which face of a polygon the property should be applied to.
Please refer to glMaterial*( ) Description.
The steps are as follows:
In LIGHTING 1 project, The program creates a 4X4X4 matrix of blue spheres that varies the ambient and diffuse properties along the y-axis, the specular along the x-axis, and the shininess along the z-axis. The matrices are in the following:
// set up arrays of various properties // placed here for convenience GLfloat materialSpecular[4][4] = { { 0.1f, 0.1f, 0.1f, 1.0f }, { 0.33f, 0.33f, 0.33f, 1.0f }, { 0.67f, 0.67f, 0.67f, 1.0f }, { 0.9f, 0.9f, 0.9f, 1.0f }, }; GLfloat materialAmbDiff[4][4] ={ { 0.0f, 0.0f, 0.12f, 1.0f }, { 0.0f, 0.0f, 0.25f, 1.0f }, { 0.0f, 0.0f, 0.50f, 1.0f }, { 0.0f, 0.0f, 1.00f, 1.0f }, }; GLfloat materialShininess[4][1] = { { 0.0f }, { 5.0f }, { 25.0f }, { 125.0f } };
These values were chosen because they give a relatively even increase in each property as the values change. Figure 3 presents the changes that these properties bring when combined. The color of the spheres are defined by the ambient and diffuse values, and you can see from both the array and the illustration that the colors start off as a very dark blue rise to a bright pure blue. The shininess effect can be observed as the highlight goes from being spread across the entire illuminated hemisphere to a point of light on the surface. If you rotate the matrix about the y-axis, you will see that the highlight disappears when the angles of the reflection no longer hits the viewpoint.
You can simplify the specification of material properties by enabling GL_COLOR_MATERIAL. This mode uses glColor*() calls to set one or more material properties. It is often easier and faster to use color material mode to switch properties than to specify the whole material.
By default the properties modified by glColor*() calls in color material mode are diffuse and ambient. These can be changed by using glColorMaterial().
Please refer to the glColorMaterial() description.
OpenGL has two types of lighting: global shading, or the ambient light and its associated parameters, and individual light sources, which have position and direction.
The glLightModel*() function is used for setting global lighting parameters. You can select the RGBA value for the global ambient light that's present in the scene. Next, you can alter the calculations for specular highlights:
An individual light source will bring into sharp detail the differences between differently illuminated sides. After enabling an individual light source, you may want to set the ambient and diffuse RGBA values for the light. The ambient part of the light's values is the glLight*() function. The parameters passed in are the particular light's enum value, the enum of the parameter you want to change, and the value of the parameter.
This function can be used to do the following:
The diffuse RGBA value of the color that the light contributes to the reflectance off an object and is what you can consider the "color" of the light. Shining a light with red diffuse RGBA settings on a white sphere would give a red coloring to that part of the sphere that the light illuminates. The specular component is the color of the highlights that reflect off a shiny surface. Typically you would set the specular value to be the same as the diffuse value, since the reflected highlight is usually the same as light. Figure 4 is a scene from the "LIGHTING 2" program. These are three white mildly reflective spheres. The sphere in the middle has a light with white diffuse and specular shining on it. The sphere on the left has a green diffuse and white specular light shining on it. The sphere on the right has a white diffuse and a green specular lighting on it.
Figure 4: Three identical spheres lit by different light components
The position is transformed by the modelview matrix when glLight*( ) is called (just as if it were a point), and it is stored in eye coordinates. If the w component of the position is 0.0, the light is treated as a directional source. Diffuse and specular lighting calculations take the light's direction, but not its actual position, into account, and attenuation is disabled. Otherwise, it is positional source. Diffuse and specular lighting calculations are based on the actual location of the light in eye coordinates, and attenuation is then enabled. The default position is (0,0,1,0); thus, the default light source is directional, parallel to, and in the direction of the -z axis.
Attenuation is the reduction in the intensity of the light as the distance increases. OpenGL has three parameter to calculate the attenuation factor. GL_CONSTANT_ATTENUATION is the constant, and by default its value is 1. The other parameters -- GL_LINEAR_ATTENUATION and GL_QUADRATIC_ATTENUATION -- are used in the calculation to reduce the light
Figure 5: Components of a spotlight
Please refer to glLight*() Description.
We'll use multiple lights to create a scene. The source code for this can be found in the "LIGHTING 3" subdirectory. Figure 6 shows a rendering of the scene.
Figure 6: 3D text demonstrating chrome text with colored lights
The following is the RenderScene( ) member function:
BOOL CLightingView::RenderScene( void ) { // Need to add a check for the font here before assuming it's there... static GLuint myFont = GenerateDisplayListForFont( "Impact", 0.2f ); GLfloat materialSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat materialShininess[1] = { 128.0f }; GLfloat materialAmbient[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLfloat materialDiffuse[4] = { 0.4f, 0.4f, 0.4f, 1.0f }; GLfloat local_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; ::glEnable(GL_DEPTH_TEST); ::glDepthFunc(GL_LESS); ::glLightModelfv(GL_LIGHT_MODEL_AMBIENT, local_ambient); GLfloat ambient0[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat diffuse0[] = { 1.0f, 0.0f, 0.0f, 1.0f }; GLfloat specular0[] = { 1.0f, 0.0f, 0.0f, 1.0f }; GLfloat position0[] = { 2.0f, -1.5f, -1.5f, 1.0f }; GLfloat ambient1[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat diffuse1[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat specular1[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat position1[] = { 2.0f, 1.0f, -1.0f, 0.0f }; GLfloat ambient2[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat diffuse2[] = { 0.0f, 0.0f, 1.0f, 1.0f }; GLfloat specular2[] = { 0.0f, 0.0f, 1.0f, 1.0f }; GLfloat position2[] = { -0.5f, -0.5f, -1.0f, 1.0f }; GLfloat ambient3[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat diffuse3[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat specular3[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat position3[] = { 2.0f, 0.5f, 0.5f, 0.0f }; // Disable lighting to draw some simple spheres that // represent the lights ::glDisable( GL_LIGHTING ); ::glPushMatrix(); ::glColor3fv( diffuse0 ); ::glTranslatef( position0[0], position0[1], position0[2] ); ::auxWireSphere( 0.15f ); ::glPopMatrix(); ::glPushMatrix(); ::glColor3fv( diffuse1 ); ::glTranslatef( position1[0], position1[1], position1[2] ); // ::auxWireSphere( 0.15f ); ::glPopMatrix(); ::glPushMatrix(); ::glColor3fv( diffuse2 ); ::glTranslatef( position2[0], position2[1], position2[2] ); ::auxWireSphere( 0.15f ); ::glPopMatrix(); ::glPushMatrix(); ::glColor3fv( diffuse3 ); ::glTranslatef( position3[0], position3[1], position3[2] ); // ::auxWireSphere( 0.15f ); ::glPopMatrix(); ::glEnable( GL_LIGHTING ); ::glEnable(GL_LIGHT0); ::glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0); ::glLightfv(GL_LIGHT0, GL_POSITION, position0); ::glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0); ::glLightfv(GL_LIGHT0, GL_SPECULAR, specular0); ::glEnable(GL_LIGHT1); ::glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1); ::glLightfv(GL_LIGHT1, GL_POSITION, position1); ::glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1); ::glLightfv(GL_LIGHT1, GL_SPECULAR, specular1); ::glEnable(GL_LIGHT2); ::glLightfv(GL_LIGHT2, GL_AMBIENT, ambient2); ::glLightfv(GL_LIGHT2, GL_POSITION, position2); ::glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2); ::glLightfv(GL_LIGHT2, GL_SPECULAR, specular2); ::glEnable(GL_LIGHT3); ::glLightfv(GL_LIGHT3, GL_AMBIENT, ambient3); ::glLightfv(GL_LIGHT3, GL_POSITION, position3); ::glLightfv(GL_LIGHT3, GL_DIFFUSE, diffuse3); ::glLightfv(GL_LIGHT3, GL_SPECULAR, specular3); ::glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular ); ::glMaterialfv( GL_FRONT, GL_SHININESS, materialShininess ); ::glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse ); ::glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient ); ::glPushMatrix(); ::glTranslatef( -3.0f, 0.0f, 0.0f ); GLTextOut( myFont, "OpenGL & Windows" ); ::glPopMatrix(); return TRUE; }
This exercise is broken into two parts:
Goals:
Instructions (Record answers for 4, 5, and 6):
Suffix Data Type b 1-byte integer s 2-byte integer i 4-byte integer ub unsigned 1-byte integer us unsigned 2-byte integer ui unsigned 4-byte integer
/4
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient)where lmodel_ambient has been set to an array with RGBA values.
Show the results and answers to your instructor.
Be prepared to comment out the glLightModelfv() function and ambient and diffuse light settings.
/6