32
OpenGL Lighting 13. OpenGL Lighting Overview of Lighting in OpenGL In order for lighting to have an effect in OpenGL, two things are required: A light An object to be lit Lights can be set to any color, and can have a wide variety of parameters which determine where they are located, in what direction they shine, and how they interact with objects in the world. Objects have a variety of parameters which determine how they reflect the light which hits them. The color(s) of an object is determined by the combining the parameters of the light(s) in the world with the object’s parameters. E.R. Bachmann & P.L. McDowell MV 4202 Page 1 of 32

13. OpenGL Lighting - MOVES Institutemovesinstitute.org/~mcdowell/mv4202/notes/lect13.pdf · OpenGL Lighting • Components of Lighting in OpenGL o OpenGL approximates light and lighting

Embed Size (px)

Citation preview

OpenGL Lighting

13. OpenGL Lighting • Overview of Lighting in OpenGL

In order for lighting to have an effect in OpenGL, two things are required:

A light

An object to be lit

Lights can be set to any color, and can have a wide variety of parameters which determine where they are located, in what direction they shine, and how they interact with objects in the world.

Objects have a variety of parameters which determine how they reflect the light which hits them.

The color(s) of an object is determined by the combining the parameters of the light(s) in the world with the object’s parameters.

E.R. Bachmann & P.L. McDowell MV 4202 Page 1 of 32

OpenGL Lighting

• Types of Light in OpenGL

The three types of lights used in OpenGL are defined as follows:

Ambient:

Bounced light which has been scattered so much that it is impossible to tell the direction to its source (disappears if the light is turned off)

Diffuse:

Directional light which is brighter on perpendicular surfaces. Its reflection is scattered evenly.

Specular:

Directional light which tends to reflect in a preferred direction (associated with shininess)

Each of these three components has an effect on the lighting of each object in the world – the actual light at a location is the sum of the three types of lights

Just as in space, light is not noticable until it hits an object, and then its effect depends upon the object

E.R. Bachmann & P.L. McDowell MV 4202 Page 2 of 32

OpenGL Lighting

• Components of Lighting in OpenGL

o OpenGL approximates light and lighting as if light could be broken into red, green and blue components

- Light sources are characterized by the amount of red, green, and blue they emit

o Each light emits one or more of the three separate

types of light:

- Ambient, diffuse and specular - Each of these types has a red, green, and blue

component

o In addition to the lights that can be placed in a scene, the entire scene can be lit by a global ambient light, which will affect the lighting of every object in the scene, regardless of location or position

o The lights in a scene can be attenuated

E.R. Bachmann & P.L. McDowell MV 4202 Page 3 of 32

OpenGL Lighting

• Material

o Each object is composed of a material which has four properties that determine how the lighting model treats the object:

- emissive, ambient, diffuse and specular • ambient, diffuse and specular interact with the

corresponding types of light and determine what percentage of the respective types of light are reflected

• emissive allows an object to be a certain color even if not illuminated by any lights in the world emissive is most often used to simulate lamps and other light sources in a scene

E.R. Bachmann & P.L. McDowell MV 4202 Page 4 of 32

OpenGL Lighting

• Using Lighting in OpenGL

There are four steps required to add lighting to scene:

- Define a normal vector for each vertex of all the objects

- Define material properties for all of the objects in the scene

- Create, position and enable one or more light sources

- Create and select a light model

• Setting Material Properties

An object’s material properties determine how it reflects the various types of light produced by light sources

The material properties of an object may also be set to make it appear to emit light

Material properties are set using

void glMaterial{if}( GLenum face, GLenum pname, TYPE param );

void glMaterial{if}v( GLenum face, GLenum pname, TYPE *param );

where

E.R. Bachmann & P.L. McDowell MV 4202 Page 5 of 32

OpenGL Lighting

- face may be GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK to indicate which face the property is being specified for

- pname identifies the property being set

- param specifies the value to which the property is being set

- The nonvector version works only for setting the shininess of an object (pname of GL_SHININESS)

E.R. Bachmann & P.L. McDowell MV 4202 Page 6 of 32

OpenGL Lighting

♦ Ambient Reflection (GL_AMBIENT)

Ambient reflection is most noticeable when an object receives no direct illumination

Ambient reflectance isn’t affected by the position of the viewpoint

The ambient RGB values of a material determine the proportion of the RGB components of ambient light which are reflected by the material

The ambient term is the ambient color of the light scaled by the material property

ambient term = ambientlight * ambientmaterial (13.2)

The ambient components of a material are set by calling glMaterial with GL_AMBIENT as the pname argument

Example 13.12

GLfloat mat_amb[] = { 0.1, 0.5, 0.8, 1.0 }; glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, mat_amb );

E.R. Bachmann & P.L. McDowell MV 4202 Page 7 of 32

OpenGL Lighting

♦ Diffuse Reflection (GL_DIFFUSE)

Diffuse reflection is most intense where the light direction is perpendicular to the object’s surface

It is affected by the angle of the incident light relative to the normal direction

Diffuse reflectance isn’t affected by the position of the viewpoint

The diffuse term takes into account the diffuse color of the light, whether the light falls directly on the vertex, and the diffuse color of the material

The diffuse term is given by

(max{L • n, 0}) * diffuselight * diffusematerial (13.3)

where

- L is a unit vector pointing from the vertex to the light position

- n is the unit normal vector at the vertex

The diffuse components of a material are set by calling glMaterial with GL_DIFFUSE as the pname argument

Example 13.13

GLfloat mat_dif[] = { 0.1, 0.5, 0.8, 1.0 }; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_dif );

E.R. Bachmann & P.L. McDowell MV 4202 Page 8 of 32

OpenGL Lighting

♦ Diffuse and Ambient Reflection

(GL_AMBIENT_AND _DIFFUSE)

The diffuse and ambient reflectance of an object are normally the same color and intensity

Using GL_AMBIENT_AND _DIFFUSE as the pname may be used to set them both

Example 13.14

GLfloat mat_amb_dif[] = {0.1, 0.5, 0.8, 1.0}; glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_amb_dif );

♦ Specular Reflection

Specular reflection produces highlights

Depends on both the angle from the viewpoint to the object and the angle from the light source to the object

It is brightest along the direct angle of reflection

Specular highlights are normally white or light gray in color

The specular term is given by

(max{s • n, 0})shininess * specularlight * specularmaterial (13.4)

where

E.R. Bachmann & P.L. McDowell MV 4202 Page 9 of 32

OpenGL Lighting

- s is the normalized sum of two unit vectors from

◊ the vertex to the light position (or the light direction)

◊ the vertex to the viewpoint (or (0, 0, 1) for non local view points)

- n is the unit vector at the vertex

- If s • n = 0, there is no specular term

Example 13.15 GLfloat mat_spec[] = {1.0, 1.0, 1.0, 1.0}; glMaterialfv( GL_FRONT, GL_SPECULAR, mat_spec );

The shininess term in 13.4 determines the size and brightness of the highlight

- The higher the value the smaller and brighter the highlight

- Smaller values will produce a larger less focused (dimmer) highlight

The shininess term is in the range [0.0, 128.0]

Shininess is set by calling glMaterial with GL_SHININESS as the pname argument

Example 13.16

glMaterialf(GL_FRONT, GL_SHININESS, 5.0 );

E.R. Bachmann & P.L. McDowell MV 4202 Page 10 of 32

OpenGL Lighting

♦ Emission (GL_EMISSION)

Specifying an RGBA color for GL_EMISSION will make an object appear to be giving off light of that color

Specifying an RGBA color for

GL_EMISSION does not turn the object into a light source

Objects with an emissive property will be visible even if there are no light sources

Example 13.17

GLfloat mat_emiss[] = {0.3, 0.2, 0.2, 0.0}; glMaterialfv(GL_FRONT, GL_EMISSION,mat_emiss );

E.R. Bachmann & P.L. McDowell MV 4202 Page 11 of 32

OpenGL Lighting

Example 13.18

Setting the material properties. 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 | G L_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 ); glutSolidSphere( 1.0, 16, 16 ); glPopMatrix(); . . .

E.R. Bachmann & P.L. McDowell MV 4202 Page 12 of 32

OpenGL Lighting

• Using glColorMaterial

Often it is desirable to use the current color specified using glColor*() as the ambient and diffuse color of the material

glColorMaterial allows the ambient, diffuse, or specular properties of a material to be set to the current color

Usage:

void glColorMaterial( GLenum face, GLenum mode );

where

- face specifies which polygon face the current color will be applied

Possible values for face:

◊ GL_FRONT

◊ GL_BACK

◊ GL_FRONT_AND_BACK

- mode specifies the property to be set to the current color

Possible values for mode:

◊ GL_AMBIENT

◊ GL_DIFFUSE

E.R. Bachmann & P.L. McDowell MV 4202 Page 13 of 32

OpenGL Lighting

◊ GL_AMBIENT_AND_DIFFUSE

◊ GL_SPECULAR

- The current color may only be applied in one mode at a time; i.e., it is not possible to set both the specular and either ambient or diffuse colors to the current color at the same time

♦ Enabling glColorMaterial

Before glColorMaterial can be used, it must be enabled with

glEnable( GL_COLOR_MATERIAL );

Example 13.19 GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; glEnable( GL_COLOR_MATERIAL ); glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); // Set the ambient and diffuse properties glColor3f( 0.2, 0.5, 0.8 ); // Set the specular color glMaterialfv( GL_FRONT, GL_SPECULAR, mat_specular ); glColor3f( 1.0, 1.0, 1.0 ); // Draw the object auxSolidSphere( 1.0 );

E.R. Bachmann & P.L. McDowell MV 4202 Page 14 of 32

OpenGL Lighting

• Creating, Positioning and Enabling Lights

OpenGL allows the inclusion of at least eight separate light sources

Each light source is given a predefined name as follows:

GL_LIGHT0 GL_LIGHT1 . . . GL_LIGHT7

Each must be individually turned on and off using glEnable and glDisable respectively:

glEnable( GL_LIGHT0 );

glDisable( GL_LIGHT0 );

Lighting as a whole is enabled and disabled similarly

glEnable( GL_LIGHTING );

E.R. Bachmann & P.L. McDowell MV 4202 Page 15 of 32

OpenGL Lighting

- If lighting is disabled, the current color is mapped onto the current vertex

- No calculations concerning normals, light sources, lighting model and material properties are performed

Each light source will have numerous characteristics or properties:

- Color and intensities of its ambient, diffuse and specular components

- Position - Direction - Constant, linear and quadratic attenuation factors - Spotlight exponent and cutoff factors

The properties of each light are set using:

void glLight{if}( GLenum light, GLenum pname, TYPE param );

void glLight{if}v( GLenum light, GLenum pname, TYPE *param );

where

E.R. Bachmann & P.L. McDowell MV 4202 Page 16 of 32

OpenGL Lighting

- light specifies the name of the light (e.g., GL_LIGHT0)

- pname specifies the property being set - param specifies the value to which the property is

being set - The nonvector version can only be used to set

single-value characteristics

Pname may be any of the following to set the respective properties:

- GL_AMBIENT Ambient RGBA intensity of the light

Example 13.1

GLFloat lt_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; glLightfv( GL_LIGHT0, GL_AMBIENT, lt_ambient );

- GL_DIFFUSE Diffuse RGBA intensity of the light

Example 13.2

GLFloat lt_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv( GL_LIGHT0, GL_DIFFUSE, lt_diffuse );

E.R. Bachmann & P.L. McDowell MV 4202 Page 17 of 32

OpenGL Lighting

- GL_SPECULAR Specular RGBA intensity of the light

Example 13.3

GLFloat lt_spec[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv( GL_LIGHT0, GL_SPECULAR, lt_spec );

- GL_POSITION

Sets either the position or direction of a light based upon the value of the fourth element of param

◊ 1.0 indicates that the first three elements give the xyz position of the light

◊ 0.0 indicates that the first three elements define a vector which points in the direction from which the light is coming

Example 13.4

A directional light

GLFloat lt_direct[] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv( GL_LIGHT0, GL_POSITION, lt_direct );

Example 13.5

A positional light

E.R. Bachmann & P.L. McDowell MV 4202 Page 18 of 32

OpenGL Lighting

GLFloat lt_posit[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv( GL_LIGHT0, GL_POSITION, lt_posit );

- GL_SPOT_DIRECTION xyz direction of a spot light

◊ vector indicates the direction the light is pointing

Example 13.6

GLFloat spot_direction[] = { -1.0, -1.0, 0.0 }; glLightfv( GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction );

- GL_SPOT_CUTOFF

Defines the spotlight cutoff angle in degrees

cutoff angle

spotlight

Default cutoff angle is 180 degrees

E.R. Bachmann & P.L. McDowell MV 4202 Page 19 of 32

OpenGL Lighting

Example 13.7

glLightf( GL_LIGHT0, GL_SPOT_CUTOFF, 45.0 );

- GL_SPOT_EXPONENT

Controls how concentrated the light is

Lower values cause the light to attenuate near the edges of the cone

◊ default exponent is 0

◊ higher values result in a more focused light source

- GL_CONSTANT_ATTENUATION GL_LINEAR_ATTENUATION GL_QUADRATIC_ATTENUATION

Set the constants of the attenuation factor used to attenuate positional lights

E.R. Bachmann & P.L. McDowell MV 4202 Page 20 of 32

OpenGL Lighting

2

1dkdkk

nfactorattenuatioqlc ++

= (13.1)

- 13.1 is multiplied by the contribution of the associated light source for each vertex

- kc, kl, and kq are the constant, linear and quadratic attenuation factors, respectively

- default values: kc = 1, kl = 0, and kq = 0 - d is the distance from the light source to the vertex - Using attenuated lighting slows performance

Example 13.8

glLightf(GL_LIGHT2,GL_CONSTANT_ATTENTUATION,2.0); glLightf( GL_LIGHT2, GL_LINEAR_ATTENTUATION, 1.0 ); glLightf(GL_LIGHT2, GL_QUADRATIC_ATTENTUATION,0.5);

E.R. Bachmann & P.L. McDowell MV 4202 Page 21 of 32

OpenGL Lighting

• Selecting a Lighting Model

The lighting model is concerned with three factors:

- The global ambient light intensity - Local or infinitely distance viewpoint - Differences between the lighting of the front and

the back polygon faces

The properties of the lighting model are set using

glLightModel{if}( GLenum pname, TYPE param );

glLightModel{if}v( GLenum pname, TYPE *param );

where

- pname is the property being set - param is the value to which the property is being

set - Possibilities for pname are

◊ GL_LIGHT_MODEL_AMBIENT

Set ambient RGBA intensity of the entire scene

◊ GL_LIGHT_MODEL_LOCAL_VIEWER

How specular reflections are computed

◊ GL_LIGHT_MODEL_TWO_SIDE

One-sided or two-sided lighting

E.R. Bachmann & P.L. McDowell MV 4202 Page 22 of 32

OpenGL Lighting

♦ Global Ambient Light

Global ambient light is not from any particular source

- It is present in the scene even if no lights are enabled

Example 13.9

Specify the global ambient RGBA intensity

glFloat lmodel_ambient[]={0.2, 0.2, 0.2, 1.0}; glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );

♦ Local or Infinite Viewpoint

The location of the viewpoint affects the calculations for the highlights produced by specular reflectance

The intensity of a highlight depends on

- the vertex normal - the direction from the vertex to the light source - the direction from the vertex to the viewpoint

With an infinite viewpoint, the direction from every vertex remains constant

With a local viewpoint, the direction is different for each vertex

E.R. Bachmann & P.L. McDowell MV 4202 Page 23 of 32

OpenGL Lighting

Example 13.10

Placing the viewpoint at the origin of the viewing (eye) coordinates:

glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE );

♦ Two-sided Lighting

By default, OpenGL only performs lighting calculations for the front side of polygons

Lighting may be enabled for both polygon faces

Example 13.11

Lighting both polygon faces:

glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );

E.R. Bachmann & P.L. McDowell MV 4202 Page 24 of 32

OpenGL Lighting

• The OpenGL Lighting Calculation

The lit color of a vertex in the RGBA mode is determined by

( )materialelmod lightmaterial ambientambientemissionrvertexcolo ×+=

( )i

n

t qfc

effect spotlightdkdkk

×

+++ ∑

=

1

02

1

[ materiallight ambientambient ××

{ }( )materiallighti diffusediffusenLi××⋅+ 0 ,max

{ }( )])materiallightshininess

i specularspecular nsmaxi××⋅+ 0, (13.5)

• Looking at this calculation, it is

• Efficiency Note

• Lighting is expensive -- all of the following increase the computational load:

E.R. Bachmann & P.L. McDowell MV 4202 Page 25 of 32

OpenGL Lighting

- Multiple Lights - Attenuation - Two-sided Lighting - Local Viewpoint

• Looking at equation 13.5, it is easy to see why lighting is expensive and why each of these increases the computational load.

• Shading in OpenGL

OpenGL provides two different shading models

♦ Flat Shading (GL_FLAT)

Lines or filled polygons are drawn in a single color

The color of one particular vertex determines the color for the entire primitive

- For a line segment, the color of the line is the current color when the last vertex is specified

- See text Table 4-2 to determine how OpenGL selects the color of a Flat shaded polygon

• Smooth or Gouraud Shading (GL_SMOOTH)

E.R. Bachmann & P.L. McDowell MV 4202 Page 26 of 32

OpenGL Lighting

The color of the interior points of primitives is interpolated between the colors of the vertices which define the primitive

The color of each vertex is treated individually

To specify a shade model use

void glShadeModel( GLenum mode );

where

- mode is either GL_SMOOTH (default) or GL_FLAT

• Positioning and Directing Lights

Light sources are subject to the same matrix transformations as a primitive object

E.R. Bachmann & P.L. McDowell MV 4202 Page 27 of 32

OpenGL Lighting

- Lights are positioned and directed relative to the current local coordinate system as described by the current modelview matrix

- The position and direction of a light can be manipulated by changing the contents of the modelview matrix stack

- The positioning of a light does not affect the modelview matrix stack (a translation matrix is not generated)

♦ Stationary Lights

To fix the position of a light, set it’s position after the projection matrices have been set and viewing transformations are on the stack

- Only the viewing transformations should be on the modelview stack when the light is positioned

- Do the viewing transformations, position the light then do the modeling transformations and draw the objects in the scene

♦ Moving Light

To move a light relative to an object, position it by translating and rotating it relative to the local coordinate system of the object

♦ Light tied to the Viewpoint

E.R. Bachmann & P.L. McDowell MV 4202 Page 28 of 32

OpenGL Lighting

To create a light which moves with the viewpoint, set the light position and position it when there are no viewing transformations on the stack

- Only the Identity matrix should be on the modelview stack

- Both the light and the view point will be affected in the same way

- IOW, position the light after the modelview stack has been cleared to the identity matrix, but before any viewing or modeling transformation are completed!

• Shadows

OpenGL does not directly support shadows

“Fake shadows” can be created by projecting three dimensional objects onto a two dimensional plane

The following function creates a shadow matrix:

E.R. Bachmann & P.L. McDowell MV 4202 Page 29 of 32

OpenGL Lighting

It takes as arguments

- Three points that lie in the plane onto which the shadow will be projected

- The position of the light source casting the shadow

- A pointer to the projection matrix which is being returned

Two utility functions reduceToUnit and calcNormal are also shown

♦ makeShadowMatrix // Creates a shadow projection matrix out of the plane equation // coefficients and the position of the light. The return value // is stored in destMat[][]

void MakeShadowMatrix( GLfloat points[3][3], GLfloat lightPos[4], GLfloat destMat[4][4] ) {

GLfloat planeCoeff[4]; GLfloat dot; // Find the plane equation coefficients. // Find the first three coefficients the same way we // find a normal. calcNormal( points, planeCoeff ); // Find the last coefficient by back substitutions planeCoeff[3] = - ((planeCoeff[0]*points[2][0]) +

(planeCoeff[1]*points[2][1]) + (planeCoeff[2]*points[2][2])); // Dot product of plane and light position dot = planeCoeff[0] * lightPos[0] + planeCoeff[1] * lightPos[1] +

E.R. Bachmann & P.L. McDowell MV 4202 Page 30 of 32

OpenGL Lighting

planeCoeff[2] * lightPos[2] + planeCoeff[3] * lightPos[3]; // Now make the projection matrix // First column destMat[0][0] = dot - lightPos[0] * planeCoeff[0]; destMat[1][0] = 0.0f - lightPos[0] * planeCoeff[1]; destMat[2][0] = 0.0f - lightPos[0] * planeCoeff[2]; destMat[3][0] = 0.0f - lightPos[0] * planeCoeff[3]; // Second column destMat[0][1] = 0.0f - lightPos[1] * planeCoeff[0]; destMat[1][1] = dot - lightPos[1] * planeCoeff[1]; destMat[2][1] = 0.0f - lightPos[1] * planeCoeff[2]; destMat[3][1] = 0.0f - lightPos[1] * planeCoeff[3]; // Third Column destMat[0][2] = 0.0f - lightPos[2] * planeCoeff[0]; destMat[1][2] = 0.0f - lightPos[2] * planeCoeff[1]; destMat[2][2] = dot - lightPos[2] * planeCoeff[2]; destMat[3][2] = 0.0f - lightPos[2] * planeCoeff[3]; // Fourth Column destMat[0][3] = 0.0f - lightPos[3] * planeCoeff[0]; destMat[1][3] = 0.0f - lightPos[3] * planeCoeff[1]; destMat[2][3] = 0.0f - lightPos[3] * planeCoeff[2]; destMat[3][3] = dot - lightPos[3] * planeCoeff[3];

} // end makeShadowMatrix

♦ calcNormal // Points p1, p2, & p3 specified in counter clock-wise order void calcNormal( float v[3][3], float out[3] ) { float v1[3],v2[3];

static const int x = 0; static const int y = 1; static const int z = 2; // Calculate two vectors from the three points v1[x] = v[0][x] - v[1][x]; v1[y] = v[0][y] - v[1][y]; v1[z] = v[0][z] - v[1][z]; v2[x] = v[1][x] - v[2][x];

E.R. Bachmann & P.L. McDowell MV 4202 Page 31 of 32

OpenGL Lighting

E.R. Bachmann & P.L. McDowell MV 4202 Page 32 of 32

v2[y] = v[1][y] - v[2][y]; v2[z] = v[1][z] - v[2][z]; // Take the cross product of the two vectors to get // the normal vector which will be stored in out out[x] = v1[y]*v2[z] - v1[z]*v2[y]; out[y] = v1[z]*v2[x] - v1[x]*v2[z]; out[z] = v1[x]*v2[y] - v1[y]*v2[x]; // Normalize the vector (shorten length to one) ReduceToUnit(out);

} // end calNormal

♦ ReduceToUnit // Reduces a normal vector specified as a set of // three coordinates, to a unit normal vector of length one. void ReduceToUnit( float vector[3] ) {

float length; // Calculate the length of the vector length = (float)sqrt( (vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2]) ); // Keep the program from blowing up by providing an // acceptable value for vectors that may evaluate // close to zero. if ( length > 0.0f ) { vector[0] /= length; vector[1] /= length; vector[2] /= length; } // end if

} // end ReduceToUnit