Material parameters specify how a surface reflects light. Applications change OpenGL material parameters to emulate different colored materials, shiny and flat materials, high-gloss materials such as a pool ball, or broad-gloss materials such as brass. See Plate 1 and the Materials example code at the OpenGL® Distilled Web site for examples of different material effects.
As mentioned in Chapter 2, "Drawing Primitives," glColor3f() sets the current primary color. It's important to note that OpenGL lighting doesn't use the current primary color; instead, it uses the current material colors. By default, calling glColor3f() has no effect when lighting is enabled, but applications often change this default behavior. See "Changing Material Parameters with glColor*()" later in this chapter for more information.
Use glMaterial*v() to specify the ambient, diffuse, and specular material colors, and use glMaterial*() to specify the specular exponent parameter. face specifies a change to front- or back-facing parameters, or both. pname is the material parameter, and param is the new value for the parameter.
OpenGL keeps a set of material parameters for both front- and back-facing primitives, and the face parameter specifies which set the function call affects. Specify GL_FRONT unless using two-sided lighting. Valid pname values for glMaterial*v() include GL_AMBIENT, GL_DIFFUSE, and GL_SPECULAR, and for glMaterial*(), pname must be GL_SHININESS.
Note
By default, two-sided lighting is disabled, and OpenGL uses front material parameters to light all primitives. Therefore, using a face value of GL_FRONT affects parameters for all primitives.
When two-sided lighting is enabled, OpenGL uses front material parameters to light front faces and back material parameters to light back faces.
OpenGL also reverses normals for back-facing primitives before calculating lighting values. Though uncommon, two-sided lighting is useful in some rendering situations. Consider CAD applications that allow the user to slice into a model with clipping planes. The application could enable two-sided lighting to highlight interior and exterior surfaces.
For more information, see "glLightModel" in OpenGL® Reference Manual and Chapter 5, "Lighting," of OpenGL® Programming Guide.
To change the ambient, diffuse, or specular material parameters, call glMaterialfv() with GL_AMBIENT, GL_DIFFUSE, or GL_SPECULAR, and pass in a four-element array of GLfloats representing the RGBA color value. The following calls create a material that reflects mostly blue diffuse light and white specular light:
Call glMaterialf() with a pname of GL_SHININESS to set the specular exponent. As in the Phong lighting model (Phong 1975), OpenGL takes the dot product of the reflected light vector and a vector to the eye,[2] and raises the result to the GL_SHININESS exponent. The value must be in the range 0.0 to 128.0. The default value of 0.0 results in a broad specular highlight (anything raised to the 0.0 power is 1.0 or full intensity), whereas increasingly higher values result in tighter highlights. Use values less than 10.0, for example, to simulate broad-gloss surfaces, such as brass or bronze. Use higher values to simulate high-gloss surfaces, such as pool balls.
[2] By default, OpenGL uses (0,0,1) for a vector to the eye in eye coordinates, which is adequate for most applications.
To create a tight specular highlight on a shiny pool ball, as shown in Figure 4-2, call
Figure 4-2. This image demonstrates the effects of different GL_SPECULAR material colors and GL_SHININESS specular exponent values. Left: Zero-intensity (0., 0., 0., 1.) specular material color; specular exponent is irrelevant. Center: Low-intensity (.3, .3, .3, 1.) specular material color with a specular exponent of 10.0. Right: Full-intensity (1., 1., 1., 1.) specular material color with a specular exponent of 128.0.
glMaterialf( GL_FRONT, GL_SHININESS, 128.f );
4.4.1. Changing Material Parameters with glColor*()
Earlier in this chapter, you learned that OpenGL uses the current material color (set with glMaterialfv()) when lighting is enabled but uses the current primary color (set with glColor3f()) when lighting is disabled. This is inconvenient for applications that alternate between displaying models lit and unlit. Also, glMaterial*v() is considerably more expensive for OpenGL to process than glColor3f().
Color material mode addresses these issues. When you enable color material mode, certain current material colors track the current primary color. Enable this mode by calling
glEnable( GL_COLOR_MATERIAL );
By default, this causes glColor3f() calls to change not only the current primary color, but also the current ambient and diffuse material colors. You can change which material parameters track the primary color by calling glColorMaterial().
void glColorMaterial( GLenum face, GLenum mode );
Specifies which material parameters track the current primary color. face determines whether the call affects front- or back-face material parameters, or both. mode specifies the material parameters that should track the current primary color.
Applications typically specify GL_FRONT_AND_BACK for face (unless using two-sided lighting). Initially, mode is GL_AMBIENT_AND_DIFFUSE. Other valid values include GL_AMBIENT, GL_DIFFUSE, and GL_SPECULAR, which cause the ambient, diffuse, or specular material colors, respectively, to track the current primary color.
For more information on glColorMaterial(), see Section 2.14.3, "Color-Material," of The OpenGL Graphics System and "glColorMaterial" in OpenGL® Reference Manual.
4.4.2. Typical Usage
Applications most often use glColorMaterial() with its default mode of GL_AMBIENT_AND_DIFFUSE. This setting allows applications to change the current ambient and diffuse material colors efficiently with a single call to glColor3f().
Applications generally either emulate a flat, nonglossy surface with a specular material color near zero intensity, such as (0.1, 0.1, 0.1, 1.), or a shiny surface with a specular material color of (1., 1., 1., 1.). Some applications, however, have a large library of materials such as brass, plastic, and rubber, which require different specular colors.
Applications vary the GL_SHININESS specular exponent to simulate different material reflection properties. Applications rarely use the default GL_SHININESS value of 0.0. Try a value of 10.0 as a good starting value and then tweak it to obtain an appropriate result for the material you're rendering. To simulate some high-gloss surfaces, your application might need to set GL_SHININESS to the maximum value of 128.0.
As an example, to simulate a hard, shiny blue-plastic material, use the following code:
// Enable lighting, one light source, and color material glEnable( GL_LIGHTING ); glEnable( GL_COLOR_MATERIAL ); glEnable( GL_LIGHT0 ); // Specify a white specular highlight const GLfloat white[4] = { 1.f, 1.f, 1.f, 1.f }; glMaterialfv( GL_FRONT, GL_SPECULAR, white ); glMaterialf( GL_FRONT, GL_SHININESS, 20.f ); // By default, color material modifies ambient and diffuse // material colors. Set both ambient and diffuse material // colors to blue. glColor3f( 0.1f, 0.1f, 1.f ); // Specify geometry with unit length normals // ...
This snippet was taken from the Materials example code at the OpenGL® Distilled Web site, which also simulates other material types.
4.4.3. More Information
It's important to remember that your application can only simulate real-world materials by using OpenGL lighting. Although OpenGL lighting is adequate for nonphotorealistic rendering, applications that require accurate and realistic rendering of materials should consider using OpenGL vertex and fragment shaders. For further information, see the following sections of OpenGL® Shading Language: Section 9.3, "Material Properties and Lighting"; Section 10.5, "Polynomial Texture Mapping with BRDF Data"; Section 11.4, "Bump Mapping"; and Chapter 12, "Noise." In this book, appendix A, "Other Features," briefly discusses the OpenGL Shading Language.