📄 chapter06.html
字号:
<P>In Figure J-21 , the first row of spheres has no ambient reflectance
(0.0, 0.0, 0.0, 0.0), and the second row has a significant amount of it
(0.7, 0.7, 0.7, 1.0).
<H3>
Specular Reflection</H3>
Specular reflection from an object produces highlights. Unlike ambient
and diffuse reflection, the amount of specular reflection seen by a viewer
does depend on the location of the viewpoint - it's brightest along the
direct angle of reflection. To see this, imagine looking at a metallic
ball outdoors in the sunlight. As you move your head, the highlight created
by the sunlight moves with you to some extent. However, if you move your
head too much, you lose the highlight entirely.
<P>OpenGL allows you to set the RGBA color of a specular highlight (with
GL_SPECULAR) and to control the size and brightness of the highlight (with
GL_SHININESS). You can assign a number in the range of [0.0, 128.0] to
GL_SHININESS - the higher the value, the smaller and brighter (more focused)
the highlight. See "The Mathematics of Lighting" for the details of how
specular highlights are calculated.
<P>In Figure J-21 , the spheres in the first column have no specular reflection.
In the second column, GL_SPECULAR and GL_SHININESS are assigned values
as follows:
<PRE>GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat low_shininess[] = { 5.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);</PRE>
In the third column, the GL_SHININESS parameter is increased to 100.0.
<H3>
Emission</H3>
By specifying an RGBA color for GL_EMISSION, you can make an object appear
to be giving off light of that color. Since most real-world objects (except
lights) don't emit light, you'll probably use this feature mostly to simulate
lamps and other light sources in a scene. In Figure J-21 , the spheres
in the fourth column have a greenish value for GL_EMISSION:
<PRE>GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);</PRE>
Notice that the spheres appear to be slightly glowing; however, they're
not actually acting as light sources. You would need to create a light
source and position it at the same location as the sphere to create that
effect.
<H3>
Changing Material Properties</H3>
Example 6-1 uses the same material properties for all vertices of the only
object in the scene (the sphere). In other situations, you might want to
assign different material properties for different vertices on the same
object. More likely, you have more than one object in the scene, and each
object has different material properties. For example, the code that produced
Figure J-21 has to draw eight different objects (all spheres), each with
different material properties. Example 6-3 shows some of the code in the
<B>display()</B>
routine.
<P><B>Example 6-3 : </B>Using Different Material Properties: material.c
<PRE>GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };
GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat no_shininess[] = { 0.0 };
GLfloat low_shininess[] = { 5.0 };
GLfloat high_shininess[] = { 100.0 };
GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* draw sphere in first row, first column
* diffuse reflection only; no ambient or specular
*/
glPushMatrix();
glTranslatef (-3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, second column
* diffuse and specular reflection; low shininess; no ambient
*/
glPushMatrix();
glTranslatef (-1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, third column
* diffuse and specular reflection; high shininess; no ambient
*/
glPushMatrix();
glTranslatef (1.25, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
auxSolidSphere();
glPopMatrix();
/* draw sphere in first row, fourth column
* diffuse refl.; emission; no ambient or specular reflection
*/
glPushMatrix();
glTranslatef (3.75, 3.0, 0.0);
glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
auxSolidSphere();
glPopMatrix();</PRE>
As you can see, <B>glMaterialfv()</B> is called repeatedly to set the desired
material property for each sphere. Note that it's called only to change
a property that needs to be changed. The second and third spheres use the
same ambient and diffuse properties as the first sphere, for example, so
these properties aren't reset. Since <B>glMaterial*()</B> has a performance
cost associated with its use, it's best to minimize material-property changes.
<P>Another technique for minimizing performance costs associated with changing
material properties is to use <B>glColorMaterial()</B>.void <B>glColorMaterial</B>(GLenum
<I>face</I>,
GLenum <I>mode</I>);
<P>Causes the material property (or properties) specified by <I>mode</I>
of the specified material face (or faces) specified by <I>face</I> to track
the value of the current color at all times. A change to the current color
(using <B>glColor*()</B>) immediately updates the specified material properties.
The <I>face</I> parameter can be GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK
(the default). The <I>mode</I> parameter can be GL_AMBIENT, GL_DIFFUSE,
GL_AMBIENT_AND_DIFFUSE (the default), GL_SPECULAR, or GL_EMISSION.
<P>Note that <B>glColorMaterial()</B> specifies two independent values:
the first specifies which face or faces are updated, and the second specifies
which material property or properties of those faces are updated. OpenGL
does <I>not</I> maintain separate <B>mode</B> variables for each face.
<P>After calling <B>glColorMaterial()</B>, you need to call <B>glEnable()</B>
with GL_COLOR_MATERIAL as the parameter. Then, you can change the current
color using <B>glColor*()</B> (or other material properties, using <B>glMaterial*()</B>)
as needed as you draw:
<PRE>glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.2, 0.5, 0.8);
/* draw some objects here */
glColor3f(0.9, 0.0, 0.2);
/* draw other objects here */
glDisable(GL_COLOR_MATERIAL);</PRE>
You should use <B>glColorMaterial()</B> whenever you need to change a single
material parameter for most vertices in your scene. If you need to change
more than one material parameter, as was the case for Figure J-21 , use
<B>glMaterial*()</B>.
When you don't need the capabilities of <B>glColorMaterial()</B> anymore,
be sure to disable it, so that you don't get undesired material properties
and so that you don't incur the performance cost associated with it. The
performance value in using <B>glColorMaterial()</B> varies, depending on
your OpenGL implementation. Some implementations may be able to optimize
the vertex routines so that they can quickly update material properties
based on the current color.
<P>Example 6-4 shows an interactive program that uses <B>glColorMaterial()</B>
to change material parameters. Pressing each of the three mouse buttons
changes the color of the diffuse reflection.
<P><B>Example 6-4 : </B>Using glColorMaterial(): colormat.c
<PRE>#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat diffuseMaterial[4] = { 0.5, 0.5, 0.5, 1.0 };
void myinit(void)
{
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseMaterial);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 25.0);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
void changeRedDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[0] += 0.1;
if (diffuseMaterial[0] > 1.0)
diffuseMaterial[0] = 0.0;
glColor4fv(diffuseMaterial);
}
void changeGreenDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[1] += 0.1;
if (diffuseMaterial[1] > 1.0)
diffuseMaterial[1] = 0.0;
glColor4fv(diffuseMaterial);
}
void changeBlueDiffuse (AUX_EVENTREC *event)
{
diffuseMaterial[2] += 0.1;
if (diffuseMaterial[2] > 1.0)
diffuseMaterial[2] = 0.0;
glColor4fv(diffuseMaterial);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
else
glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN,
changeRedDiffuse);
auxMouseFunc(AUX_MIDDLEBUTTON, AUX_MOUSEDOWN,
changeGreenDiffuse);
auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN,
changeBlueDiffuse);
auxReshapeFunc(myReshape);
auxMainLoop(display);
}</PRE>
<H4>
Try This</H4>
Try This
<P>Modify Example 6-3 :
<UL>Change the global ambient light in the scene. Hint: Alter the value
of the GL_LIGHT_MODEL_AMBIENT parameter.
<BR>
<P>Change the diffuse, ambient, and specular reflection parameters, the
shininess exponent, and the emission color. Hint: Use the <B>glMaterial*()</B>
command, but avoid making excessive calls.
<BR>
<P>Use two-sided materials and add an arbitrary clipping plane (see "Additional
Clipping Planes" ) so you can see the inside and outside of a row or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -