EZwgl (12.9 Lighting)

## 12.9 Lighting

Lighting is controled by three items: light sources, light model and material properties. The color of a vertex is calculated based on the following factors: (a) the position of the vertex, the current normal vector and the current material properties. (b) the position and properties of the light sources and (c) the light model properties.

For a complete description of lighting calculations, please see

      AUTHOR: Neider, Jackie
      TITLE: OpenGL programming guide : the official guide to learning
            OpenGL, release 1 /OpenGL Architecture Review Board, Jackie
                             Neider, Tom Davis, Mason Woo.
      PUBLISHED:      Reading, Mass. : Addison-Wesley, c1993.
      DESCRIPTION:    xxxiii, 516 p., (16) p. of plates : ill. (some col.) ; 24 cm.
      NOTES:          Includes index.
      SUBJECTS:       OpenGL
                      Computer graphics
      OTHER AUTHORS:  Davis, Tom
                      Woo, Mason
                      OpenGL Architecture Review Board
      ISBN:           0201632748
      OCLC NUMBER:    27679041

To use lighting, follow the following steps.

- Call `EZ_Enable(EZ_LIGHTING)` to enable lighting calculations.

- Call `EZ_Enable(EZ_LIGHT#)` to turn on light sources, where `#` is an integer between 0 and 7. One can turn on multiple light sources.

- Call `EZ_Lightfv`, `EZ_LightModelfv` and `EZ_Materialfv` to set light source properties, light model properties and material properties.

- When define a geometric object, make sure you set the normal vectors by using `EZ_Normal3fv`. If needed, one may enable color material and use `EZ_Color3fv` to set vertex colors.

### 12.9.1 Example G4, Lighting

Here is a short example that uses lighting calculations. In this example, we turn on one light source, set its positon but use its default color. We set the local viewer property of the light model. Then we render a yellow dodecahedron and a red sphere.

    /********************* Example G4 **********************************************/
    #include "EZ.h"

    static void event_handle(EZ_Widget *, void *,int,XEvent *); /* event handle   */
    static void draw(EZ_Widget *canvas);                        /* repaint func   */
    static float light_position[] = {0.5, 0.5, 0.0, 1.0};       /* light position */
    static float white[] = {1.0,1.0,1.0,1.0};
    static float shininess[] = {8.0};

    main(int argc, char **argv)
    {
      EZ_Widget *frame, *canvas;

      /* create a canvas */
      EZ_Initialize(argc, argv, 1);

      frame = EZ_CreateWidget(EZ_WIDGET_FRAME, NULL,
                             EZ_FILL_MODE, EZ_FILL_BOTH,
                             0);
      canvas = EZ_CreateWidget(EZ_WIDGET_3D_CANVAS, frame,
                               EZ_ORIENTATION,   EZ_VERTICAL_BOTTOM,
                               EZ_WIDTH_HINT,    320,
                               EZ_HEIGHT_HINT,   320,
                               EZ_EVENT_HANDLER, event_handle, NULL,
                               0);

      EZ_DisplayWidget(canvas);

      /* setup GL modes */
      EZ_AutoSelectBackBuffer();                          /* select a back  buffer */
      EZ_RGBMode();                                       /* select color  mode    */
      EZ_ShadeModel(EZ_SMOOTH);                           /* select  shading model */
      EZ_DrawBuffer(EZ_BACK);                             /* draw into the  backbuf*/
      EZ_Enable(EZ_CULL_FACE);                            /* enable  backface cull */
      EZ_Enable(EZ_DEPTH_TEST);                           /* enable  zbuffer       */

      /* lighting related attributes. One should be aware
       * that where to invoke EZ_Lightfv or EZ_Materialfv
       * matters a lot. The corresponding properties are
       * computed based on the current model view matrix.
       */
      EZ_Enable(EZ_LIGHTING);                             /* enable lighting      */
      EZ_Enable(EZ_LIGHT0);                               /* enable one light src */
      /* set light src pos, this light src has a fixed position, i.e.
       * the position will not be affected by the model view matrux */
      EZ_Lightfv(EZ_LIGHT0, EZ_POSITION, light_position);
      EZ_Materialfv(EZ_FRONT,EZ_SPECULAR,white);   /* set material for front face */
      EZ_Materialfv(EZ_FRONT,EZ_SHININESS,shininess);
      EZ_LightModelfv(EZ_LIGHT_MODEL_LOCAL_VIEWER, white);

      EZ_MatrixMode(EZ_PROJECTION);           /* setup a fixed projection matrix */
      EZ_Perspective(60.0, 1.0, 2.0, 30.0);   /* a perspective view, ...         */
      EZ_MatrixMode(EZ_MODELVIEW);            /* set matrix mode to model view   */
      EZ_LookAt(0.0,0.0,15.0, 0.0,0.0,0.0,    /* and set up a look at view       */
                0.0,1.0, 0.0);                /* view up vector        */

      EZ_EventMainLoop();                     /* turn control to EZWGL           */
    }

    static float rotX = 0.0, rotY = 0.0, rotZ = 0.0;      /* rotation angles      */
    static float scale = 1.0;                             /* zooming factor       */
    static float yellow[] = {0.8, 0.8, 0.0, 0.0};         /* material color       */
    static float red[] = {0.8, 0.1, 0.0, 0.0};            /* material color       */

    static void draw(EZ_Widget *canvas)
    {
      /*
       * since we only have one 3DCanvas, which is always
       * active, we actually don't need the argument.
       */
      EZ_Clear(EZ_COLOR_BUFFER_BIT |                    /* clear the frame buffer */
               EZ_DEPTH_BUFFER_BIT);                    /* and the zbuffer        */
      EZ_PushMatrix();
      EZ_Scale(scale,scale,scale);                      /* a uniform scale        */
      EZ_Rotate(rotX, 1.0, 0.0, 0.0 );                  /* rotate about X, Y & Z  */
      EZ_Rotate(rotY, 0.0, 1.0, 0.0 );
      EZ_Rotate(rotZ, 0.0, 0.0, 1.0 );
      EZ_PushMatrix();
      EZ_Translate( -3.0, 0.0, 0.0 );
      EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE, yellow);      /* a yellow material */
      EZ_Dodecahedron(0.0,0.0,0.0,2.4);
      EZ_PopMatrix();
      EZ_PushMatrix();
      EZ_Translate(3.0,0.0,0.0);
      EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE, red);         /* a red material  */
      EZ_Sphere(EZ_SPHERE_TRIANGLE, 4,0.0,0.0,0.0,2.0);
      EZ_PopMatrix();
      EZ_PopMatrix();
      EZ_SwapBuffers();
    }

    static void event_handle(EZ_Widget *canvas, void *data, int eventType, XEvent *xev)
    {
      switch(eventType) {
      case EZ_REDRAW:
      case EZ_RESIZE:
        draw(canvas);
        break;
      case EZ_KEY_PRESS:
        switch(EZ_PressedKey) {
        case EZ_DOWN_KEY:   rotX += 5.0; draw(canvas); break;
        case EZ_UP_KEY:     rotX -= 5.0; draw(canvas); break;
        case EZ_RIGHT_KEY:  rotY += 5.0; draw(canvas); break;
        case EZ_LEFT_KEY:   rotY -= 5.0; draw(canvas); break;
        case 'e':           scale *= 1.1;draw(canvas); break;
        case 'r':           scale *= 0.9;draw(canvas); break;
        case EZ_ESCAPE_KEY:
          EZ_DestroyWidget(canvas);
          EZ_Shutdown();
          exit(0);
          break;
        default:
          break;
        }
        EZ_GLResetEvents(NULL); /* clear the event queue, too many keypresses */
        break;
      default:
        break;
      }
    }
    /********************* Example G4 **********************************************/

### 12.9.2 Setting Light Source Properties

A light source has the following properties.

- `EZ_AMBIENT` ambient color.

- `EZ_DIFFUSE` diffuse color.

- `EZ_SPECULAR` specular color.

- `EZ_POSITION` position.

- `EZ_SPOT_DIRECTION` spot direction for spot light source.

- `EZ_SPOT_EXPONENT` spot exponent.

- `EZ_SPOT_CUTOFF` spot cutoff angle.

- `EZ_CONSTANT_ATTENUATION` constant attenuation factor.

- `EZ_LINEAR_ATTENUATION` linear attenuation coefficient.

- `EZ_QUADRATIC_ATTENUATION` quadratic attenuation coefficient.

All these properties are set by the function

`void EZ_Lightfv(int lightNum, int propName, float *prop)`

The default light sources properties are list below.

ambient color | (0.0, 0.0, 0.0)
diffuse color for `LIGHT0` | (1.0,1.0,1.0)
diffuse color for other lig srcs | (0.0,0.0,0.0) specular color for `LIGHT0` | (1.0,1.0,1.0)
specular color for other lig srcs | (0.0,0.0,0.0) position | (0.0,0.0,1.0,0.0)
spot direction | (0.0,0.0,-1.0)
spot exponent | 0.0
spot cutoff angle | 180.0
constant attenuation factor | 1.0
linear attenuation coefficient | 0.0
quadratic attenuation coefficient | 0.0

### 12.9.3 Setting Light Model Properties

Each graphics context has a unique light model. A light model has the following properties.

- `EZ_LIGHT_MODEL_AMBIENT`

- `EZ_LIGHT_LOCAL_VIEWER`

- `EZ_LIGHT_TWO_SIDE`

These properties are set by

`void EZ_LightModelfv(int propName, float *prop);`

Here are the default light model properties.

ambient color | (0.2, 0.2, 0.2)
local viewer | 0.0
tow side mode | 0.0

### 12.9.4 Setting Material Properties

Each material has the following properties.

- `EZ_EMISSION` emissive color.

- `EZ_AMBIENT` ambient color.

- `EZ_DIFFUSE` diffuse color.

- `EZ_SPECULAR` specular color.

- `EZ_SHININESS` specular exponent.

- `EZ_COLOR_INDICES` indices for lighting on color map mode.

These properties are set by

`void EZ_Materialfv(int face, int propName, float *prop);`

Here are the default material properties.

emissive color | (0.0, 0.0, 0.0)
ambient color | (0.2, 0.2, 0.2)
diffuse color | (0.8, 0.8, 0.8)
specular color | (0.0, 0.0, 0.0)
shininess | 0.0
color indices | 0.0 1.0 1.0

### 12.9.5 Convinence Routines

The EZwgl provides a few handy routines for packing lighting properties together. They can be used to save a few `EZ_***fv` calls.

`EZ_Material *EZ_DefineMaterial(float *definitions)`

This function define a material from the given defintion and return a pointer to the allocated material structure.

`void EZ_BindMaterial(int face, EZ_Material *mat);`

This function bind the defined material `mat` to `face`.

Here is an example.

    static float mat[] = {
      EZ_SPECULAR_F,   1.0,1.0,1.0,1.0,
      EZ_DIFFUSE_F, 0.8, 0.0, 0.8, 0.0
      EZ_NULL_F,
    };

    EZ_Material material = EZ_DefineMaterial(mat);
    ... ...
    EZ_BindMaterial(EZ_FRONT_AND_BACK, material);
    ... ...

Predefined Materials The EZwgl includes a few predefined materials. They can be retrieved via

`EZ_Material *EZ_GetDefaultMaterial(int which);` Here is a list of the predefined materials.

Symbolic Name | property values
`EZ_SILVER` | emission (0.0,0.0,0.0,1.0)
| ambient (0.19125, 0.0735, 0.0225, 1.0) | diffuse (0.7038, 0.27048, 0.0828, 1.0) | specular ( 0.256777, 0.137622, 0.086014, 1.0) | shininess 1.0 | color indices 0.0, 0.0, 1.0 `EZ_SILVER_S` | emission (0.0,0.0,0.0,1.0)
| ambient (0.23125, 0.23125, 0.23125, 1.0) | diffuse (0.2775, 0.2775, 0.2775, 1.0) | specular ( 0.773911, 0.773911, 0.773911, 1.0) | shininess 7.0 | color indices 0.0, 0.0, 1.0 `EZ_GOLD` | emission (0.0,0.0,0.0,1.0)
| ambient (0.24725, 0.1995, 0.0745, 1.0) | diffuse (0.75164, 0.60648, 0.22648, 1.0) | specular (0.628281, 0.555802, 0.366065, 1.0) | shininess 4.0 | color indices 0.0, 0.0, 1.0 `EZ_GOLD_S` | emission (0.0,0.0,0.0,1.0)
| ambient (0.24725, 0.2245, 0.0645, 1.0) | diffuse (0.34615, 0.3143, 0.0903, 1.0) | specular (0.797357, 0.723991, 0.208006, 1.0) | shininess 6.5 | color indices 0.0, 0.0, 1.0 `EZ_BRASS` | emission (0.0,0.0,0.0,1.0)
| ambient (0.329412, 0.223529, 0.027451, 1.0) | diffuse (0.780392, 0.568627, 0.113725, 1.0) | specular (0.992157, 0.941176, 0.807843, 1.0) | shininess 2.2 | color indices 0.0, 0.0, 1.0 `EZ_COPPER` | emission (0.0,0.0,0.0,1.0)
| ambient (0.19125, 0.0735, 0.0225, 1.0) | diffuse (0.7038, 0.27048, 0.0828, 1.0) | specular (0.256777, 0.137622, 0.086014, 1.0) | shininess 1.0 | color indices 0.0, 0.0, 1.0 `EZ_COPPER_S` | emission (0.0,0.0,0.0,1.0)
| ambient (0.2295, 0.08825, 0.0275, 1.0) | diffuse (0.5508, 0.2118, 0.066, 1.0) | specular (0.580594, 0.223257, 0.0695701, 1.0) | shininess 4.1 | color indices 0.0, 0.0, 1.0

Symbolic Name | property values
`EZ_BRONZE` | emission (0.0,0.0,0.0,1.0)
| ambient (0.2125, 0.1275, 0.054, 1.0) | diffuse (0.714, 0.4284, 0.18144, 1.0) | specular ( 0.393548, 0.271906, 0.166721, 1.0) | shininess 2.2 | color indices 0.0, 0.0, 1.0 `EZ_RUBY` | emission (0.0,0.0,0.0,1.0)
| ambient (0.1745, 0.01175, 0.01175, 1.0) | diffuse (0.61424, 0.04136, 0.04136, 1.0) | specular (0.727811, 0.626959, 0.626959, 1.0) | shininess 6.5 | color indices 0.0, 0.0, 1.0 `EZ_TURQUOISE` | emission (0.0,0.0,0.0,1.0)
| ambient (0.1, 0.18725, 0.1745, 1.0) | diffuse ( 0.396, 0.74151, 0.69102, 1.0) | specular ( 0.297254, 0.30829, 0.306678, 1.0) | shininess 1.0 | color indices 0.0, 0.0, 1.0 `EZ_JADE` | emission (0.0,0.0,0.0,1.0)
| ambient ( 0.135, 0.2225, 0.1575, 1.0) | diffuse ( 0.54, 0.89, 0.63, 1.0) | specular ( 0.316228, 0.316228, 0.316228, 1.0) | shininess 1.2 | color indices 0.0, 0.0, 1.0 `EZ_EMERALD` | emission (0.0,0.0,0.0,1.0)
| ambient ( 0.0215, 0.1745, 0.0215, 1.0) | diffuse ( 0.07568, 0.61424, 0.07568, 1.0) | specular ( 0.633, 0.727811, 0.633, 1.0) | shininess 6.4 | color indices 0.0, 0.0, 1.0 `EZ_PERAL` | emission (0.0,0.0,0.0,1.0)
| ambient ( 0.25, 0.20725, 0.20725, 1.0) | diffuse ( 1.0, 0.829, 0.829, 1.0) | specular ( 0.296648, 0.296648, 0.296648, 1.0) | shininess 1.0 | color indices 0.0, 0.0, 1.0

`EZ_LightSrc *EZ_DefineLight(float *definitions)`

This function define a light source from the given defintion and return a pointer to the allocated light source structure.

`void EZ_BindLight(int lightNum, EZ_LightSrc *lsrc)` This function bind the packed light source definition `lsrc` to light number `lightNum`.

Here is an example.

    static float  light2[] =
    {
      EZ_POSITION_F,   0.0,5.0,10.0,1.0,
      EZ_SPECULAR_F,   1.0,1.0,1.0,1.0,
      EZ_SPOT_DIRECTION_F, 0.0,0.0,-1.0,0.0,
      EZ_SPOT_CUTOFF_F,  30.0,
      EZ_SPOT_EXPONENT_F, 10.0,
      EZ_NULL_F,
    };
    EZ_LightSrc *lsrc2 = EZ_DefineLight(light2);
    ... ...
    EZ_BindLight(EZ_LIGHT4, lsrc2);
    ... ...

`EZ_LightModel *EZ_DefineLightModel(float *definitions)` This function define a packed light model from the given defintion and return a pointer to the allocated light model structure.

`void EZ_BindLightModel(EZ_LightModel *lmodel)`

This function replace the current light model by the packed light model `lmodel`.

Here is an example.

    static float  lmodelDef[] =
    {
      EZ_AMBIENT_F,   0.0,0.4,0.4,0.0,
      EZ_LIGHT_MODEL_LOCAL_VIEWER, 1.0,
      EZ_LIGHT_MODEL_TWO_SIDE, 1.0,
      EZ_NULL_F,
    };
    EZ_LightModel *lmodel = EZ_DefineLightModel(lmdelDef);
    ... ...
    EZ_BindLightModel(lmodel);
    ... ...

HTML Documentation Maintainance:`Arturo Espinosa <arturo@nuclecu.unam.mx>`