Exercise 4:  Appearance

This exercise covers OpenGL functionality to control model appearance including surface properties
such as colour and reflectance, scene illumination and shading.

Copy the exercise programs from /vol/www/ee/Teaching/Courses/CGI/exercise4



1. Colour Tetrahedra

This example demonstrates the use of OpenGL flat and smooth shading models on
surface colour.

(i) Look at the example color_tetra.c. Two arrays are used to specify the vertices and their colour for
    a tetrahedra.

    Compile and run the program.

    This shows the wireframe outline of the polygon with each polygon having a single colour.

    There are two shading models for OpenGL  'flat' and 'smooth' for flat shading the colour of
    each vertex is treated independently for smooth shading the colour is interpolated.

    For a polygon with flat shading the colour for the entire polgon is taken as the colour of the
    first vertex.

    Change the shade model specified by glShadeModel() to smooth shading GL_SMOOTH.
    The colours are now interpolated along the tetrahedra edges.

(ii) Now revert to flat shading GL_FLAT and fill in the polygons with
      glPolygonMode(GL_FRONT,GL_FILL);

    This should give a single colour for each polygon corresponding to the first vertex.

    Change the smoothing model to GL_SMOOTH colours are now interpolated between
    vertices so that the polygons are filled.

(iii) Extend the program to rotate the tetrahedra and the viewpoint.
 



2. Teapot

This example demonstrates the use of lighting together with surface reflectance properties.
Four steps are required for OpenGL to light a scene:
(1) Define normal vectors for each vertex
(2) Setup the lights (location, direction, type)
(3) Select a lighting model
(4) Enable hidden surface removal.
(5) Define material properties for objects
Having done this OpenGL can render the illuminated scene based on the surface appearance
under the illumination conditions.

(i) Compile and run the program teapot.c

    This shows a smooth shaded teapot without any scene illumination which appears as
    a coloured silhouette against the white background.

(ii)  OpenGL lights are specified using glLight*() which specifies the light source type and
    corresponding properties such as position, colour direction. The command is specified as
    follows:
         glLight*(light, type, param);
              light - is the light number GL_LIGHT0-8
              type - is the type of lighting ambient, diffuse, specular, position, spot, .....
              param - set of associated parameters for a particular type of light

    Add a single positional light and enable lighting as follows in the function initgl():

    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    and define the light position as a global static variable:

    static GLfloat light0_position[] = {1.0,1.0,1.0,0.0};

    Compile and run the program shows the effect of the illumination on the shaded mat surface
    of the teapot model.   However, the model is not shaded directly as the shading does not
    take into account the ordering of surfaces relative to hte viewer. For instance the rim of the
    teapot is incorrectly shaded such that you see the lid which is hidden from view.

(iii) Hidden surface removal renders the scene such that the surface closest to the surface which
      appears in the image is the one closest to the viewer ie the visible surface. In OpenGL this
      is achieved using a 'depth buffer', for each rendered pixel the depth buffer stores the distance
      to the surface. If a new surface is closer to the viewer then the value of the pixel is replace otherwise
      it is discarded.

      To enable depth buffering in OpenGL and GLUT we must initialise the depth buffer with the
      following command in main():
         glutInitDisplayMode(... | ...| GLUT_DEPTH);

      this initialises a depth buffer along with the other buffer ie GLUT_RGB, GLUT_SINGLE/DOUBLE

      The use of depth buffering must then be enabled in OpenGL in initgl() by:
       glEnable(GL_DEPTH_TEST);

      Finally, when we clear the screen for each display the depth buffer must also be cleared:
      glClear(GL_COLOUR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      Implement depth buffering, compile and run the program.

      The teapot should now appear correctly shaded with a mat surface finish.

(iv) To change the apperance of the teapot surface we can adjust the surface properties such
      as shininess. Add the following surface properties and redisplay the teapot.

    static GLfloat mat_specular[] = {1.0,1.0,1.0,1.0};
    static GLfloat mat_shininess[] = {50.0};

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

    This should now produce a much more realistic teapot.

    Try rotating the teapot about the y-axis.

(v) Change the surface colour to see the combined effect of illumination, colour and reflectance.
     To do this you must not only set the object colour as before but also enable material colour

    In initgl() enable material colour:
       glEnable(GL_COLOR_MATERIAL);

    Now specify the teapot colour as before using glColor3f()

    Using the function glColorMaterial() you can efficiently apply material properties.
    To apply colour just to the front facing polygons illuminated for the  ambient reflectance component
    specify:
    glColorMaterial(GL_FRONT, GL_DIFFUSE);

    Note: This specifies the mode for applying teh material colour - only one mode can be specified
    at one time. Repeated calls are required to set different colours for front/back faces if
    back faces are visible.

(vi) Extend the program to dynamically control the light position, view direction, and surface
      properties using key-board input. Note transformation of light sources is treated as with other
      geometric primitives using the modelview matrix.

(vii) Experiment with other surface material properties ambient, diffuse. specular, emission....