Site Overlay

How to Building Computer Graphics (C++ and Open GL)

Hits: 20

Scene Hierarchy-Rotating Objects

The aim of this exercise is to draw a stack of rotating shapes. These shapes are to be in an ascending order from: a cube, a smaller cube, and a cone to a sphere. Each shape should be rotating in the opposite direction to the shape immediately below it and should be of a different color. This program has the stack of objects aligned with one of the coordinate axes and rotating about the axis through the objects. It is also a full implementation where stack of objects can be at any orientation and can be rotated about an arbitrary axis.

This exercise involves creation of polyhedron using a winged data structure and a scene hierarchy. This report describes the step-by-step implementation of this graphical program.

This program is divided into four main parts namely, the Main method, Lighting and Material properties, Creation Rotation and displaying of shapes, and handling of Keyboard and Mouse events.

Lighting and material properties

This section of the program describes the lighting and the material properties of the shapes. Material properties give the shapes the look and feel texture and color.  To describe the lighting, light position, direction and color have been defined in the program as shown in the code example 1.0 below.

Example 1.0. Describing the lighting position, color and direction.

This program uses two light sources as shown in the example above so that the shapes could be viewed clearly in color without having to change the view the first time the program is running. The statements that enable these lighting properties and also calling the lighting properties follow the lighting description. An example of this is described in example 1.1.

Example 1.1. Enabling and setting up the lighting direction and position.

The material properties describe the surface quality of shapes in a scene that allows them to reflect light. Shiny surfaces reflect more light and appear shinny while some surfaces tend to diffuse or absorb the light that is projected onto them. This program uses two surface qualities to give color and texture to the shapes. The qualities are described as Shininess (ability to reflect light) and Diffuse (ability to absorb light). All the above properties are described in vector format as x, y and z planes and with lighting, a vector for light intensity may be included.

Creating Rotating and displaying of shapes

A simple rectangle can by created by specifying the four vertices that describe it. These vertexes are normally written in a form of a polygon structure. The Example 1.2 below describes a simple rectangle shown in Figure 1.0.

Example 1.2. Describing a four sided polygon

Figure 1.0. A Four sided polygon (a rectangle) described using the code in Example 1.2. Figure a) shows the rectangle formed using the code in example 1.2 and figure b) shows the same rectangle rotated to display its size and shape.

Creating a cube

A cube is composed of six sides. This can simply be created using the basic rectangle created using example 1.2 above.  The rectangle drawn in figure 1.0 is called six times and each time it is rotated either by 90 degrees, or 180 degrees, keeping in mind negative and positive directions of display. The following example shows the code for building a cube.

Example 1.3. Building up a cube

Note that in Example 1.2, each side of the cube has been translated and rotated so that it appears in its position as shown in Figure 1.1 below.

Building up a cube
Figure 1.2. A completed cube that is blue in color.

Creating a smaller cube

Creating another rectangle like the one described in Figure 1.0 and Example 1.2, but this time re scaling the size to half the normal size and using the approach described in the example 1.3 creates a smaller cube in this program.  The only major difference apart from the size of the cubes is the position. The smaller cube will have to be shifted to be at a position lower than the larger cube. The sides of the smaller cube are positioned at 1.0 as shown in the Example 1.5 as opposed to the large cube at position 2.5 (slightly above the smaller cube). The sides of the smaller cube are also half way closer (0.25) while the ones on the larger cube are at positions 0.5 from the center of the scene.

Example 1.4. Describing a smaller cube

Example 1.4 Building up a smaller cube


Figure 1.3. A completed cube that is gray in color.

Creating a cone

The cone is drawn by defining a number of triangular strips, placed at a central point and fanning out to a radius that is defined by the equation: –

In this equation the angle is defined as a function of the number of strips and using a for loop this creates the whole cone made up of several rectangular strips as shown in Example 1.5 below.

Figure 1.4.  A Composition of triangular strips used in the process of drawing a cone.

Example 1.5 Drawing a cone

Figure 1.5. A completed cone that is magenta in color.

Creating a sphere

Calling the glut Solid Sphere from the utility library see Example 1.6 below draws a solid sphere.

Example 1.6. Drawing a sphere

Figure 1.6. A solid sphere that is red in color

Handling Keyboard and Mouse events

 Mouse and keyboard events take place when either the keys on the keyboard are pressed or the mouse button is pressed. This allows the user of the program to change the orientation or alignment of the shapes in the program so that they can be viewed from almost any angle.  This works by changing the values of assigned variables r, v and f (see Example 1.7), when the keys are pressed. Example 1.8 shows the value of a variable ‘v’ changing to + 2.5 or – 2.5 when the mouse button is pressed or released respectively. Example 1.9 shows how variables (f, v and r) values are altered when keys are pressed on the keyboard. Section 2 describes how this change of variables affects the shapes drawn in the program.

Example 1.7. Variables r, v and f initialized to 0.0, pressing the keyboard keys or the mouse button can change this value.

Example 1.8. Mouse Events

Example 1.9.  Keyboard Events

The main function

This is the main part of the program that creates a window and gives a call back to all the other functions used in the program and runs them through a main loop. This function calls the display function, the reshape function, the rotate function and the main loop. Consider Example 1.8.

Example 2.0.  The main Function

Putting it all together in a scene hierarchy

In order to create a scene, all the functions that create the shapes need to be called and placed in the display function. This would function well if all the shapes were rotating in the same direction, or not rotating at all. Since alternating shapes must rotate in one direction to the next alternating pair in the opposite, the ‘Rotate’ function is used to do this. This is shown in the Example 1.9 below.

Example 2.1.  The Rotate Function

Changing the orientation of the shapes

Pressing the keys on the keyboard or pressing the mouse button can change the orientation of the shapes and allow the user to view from any angle. In the example 1.9 above, some of the variables in the rotation matrices have been replaced by letters a, b c, and d. These letters are responsible for the rotation of the objects about an axis as they are decremented or incremented to give a clockwise or an anti clockwise rotation. As the program goes into a loop, redisplaying the shapes each time the variables change and we see the shapes rotating. Consider the code in Example 1.9.

To change the orientation, the variables v, f and r in the rotation matrices in example 1.9, are controlled using the mouse button or the keyboard. See the section 1.3 on Handling Keyboard and Mouse events.

Figure 1.8 Changing the orientation of the shapes using the keyboard or mouse button
Example 2.2 shows a brief description of the keys to use in order to change the orientation of the shapes.

Example 2.2.  The keys to use when changing the orientation of the shapes

The left mouse button only changes the value of v and there for changes the orientation of the shapes to direction 1 or opposite if released according to Example 2.2. See also Example 1.8.

Conclusion

The aim of this exercise has been met by drawing the stack of rotating shapes. These shapes are in an ascending order as from: a cube, a smaller cube, a cone and a sphere. Each shape rotates in the opposite direction to the shape immediately below it and has a different color.

This program is a full implementation with all the requirements including the ability to change the orientation of the shapes and rotated them about an arbitrary axis.

References

Mel Slater, Anthony Steed ,Yiorgos Chrysanthou (2002) Computer Graphics and Virtual Environments.

http://www.sgi.com/software/opengl/examples/redbook/

The Code

/*
 THE PROGRAM:A COMPUTER GRAPHICS PROGRAM
 PROOGRAMING LANGUAGE:C
 EDITOR:KIZITO I IKAPEL
 STUDENT ID:319669
 DEPARTMENT: ELECTRONIC ELECTRICAL AND COMPUTER ENGINEERING
 THE UNIVERSITY OF BIRMINGHAM
 Date:26th March 2003
 ABOUT THE PROGRAM: DISPLAYS SHAPES; TWO CUBES OF DIFFERENT SIZES,
 A CONE AND A SPHERE ROTATING ABOUT THE Z AXIS.EACH SHAPE ROTATES IN 
 THE OPPOSITE DIRECTION TO THE ONE IMMEDIATELY BELOW IT.
 CHANGING THE AXIS OF ROTATION; KEYBOARD EVENTS: 
 'V' OR 'v'- ROTATE THE AXIS (DIRECTION 1)
 'B' OR 'b'- ROTATE THE AXIS IN OPPOSITE DIRECTION 
 'G' OR 'g'- ROTATE THE AXIS (DIRECTION 2)
 'H' OR 'h'- ROTATE THE AXIS IN OPPOSITE DIRECTION 
 'R' OR 'r'- STOP ROTATION AND SET AT THE CURRENT AXIS/REALIGN SHAPES
 'P' OR 'p'- CHANGE RADIUS OF ROTATION POSITIVE
 'O' OR 'o'- CHANGE RADIUS OF ROTATION NEGATIVE
 'A' OR 'a'- CHANGE ANGLE OF ROTATION OF EACH OBJECT POSITIVE
 'S' OR 's'- CHANGE ANGLE OF ROTATION OF EACH OBJECT NEGATIVE
 */
 include 
 include 
 include 
 include 
 include 
 define PI 3.14159
 define N 7
 static GLdouble r =0.0;//reset
 static GLdouble v =0.0;//rotation
 static GLdouble f =0.0;//change direction if set to 20
 int fullscreen = 0;
 int spindx, spindy;
 int startx, starty;
 GLboolean tracking = GL_FALSE;
 void button(int button, int state, int x, int y)
 {
   if (button != GLUT_LEFT_BUTTON)
     return;
   switch (state) 
   {
   case GLUT_DOWN:
   /* 
      * If user clicks the button on the mouse,start
      * spinning to change view
      */
   v +=2.5;
 break;
 case GLUT_UP:
     /* 
      * If user released the button on the mouse,stop
      * spinning.
      */
      v -=2.5;
 break;
 }
 }
 //HUNDLING KEYSTROKE EVENTS// NOTE:CASES ARE HUNDLED
 // FOR BOTH UPPERCASE AND LOWERCASE IE WHEN THE 'CAPS LOCK' IS ON OR 
 OFF
 void keyboard(int character)
 {
   switch (character) {
 //'V' OR 'v'- ROTATE THE AXIS (DIRECTION 1)
 //'B' OR 'b'- ROTATE THE AXIS IN OPPOSITE DIRECTION 
 case 'v': //hundle lowercase event
   v +=4.0;
   break;
 case 'V': //hundle uppercase event
   v +=4.0;
   break;
 case 'b':
   v -=4.0;
   break;
 case 'B':
   v -=4.0;
   break;
 //'G' OR 'g'- ROTATE THE AXIS (DIRECTION 2)
 //'H' OR 'h'- ROTATE THE AXIS IN OPPOSITE DIRECTION 
 case 'g':
   f =20.0;
   v +=4.0;  
   break;
 case 'G':
   f =20.0;
   v +=4.0;  
   break;
 case 'h':
   f = 0.0;
   v -=4.0;
   break;
 case 'H':
   f = 0.0;
   v -=4.0;
   break;
 //'P' OR 'p'- CHANGE RADIUS OF ROTATION POSITIVE
 //'O' OR 'o'- CHANGE RADIUS OF ROTATION NEGATIVE
 case 'p':
   r +=0.1;
   break;
 case 'P':
   r +=0.1;
   break;
 case 'o':
   r -=0.1;
   break;
 case 'O':
   r -=0.1;
   break;
 //'R' OR 'r'- STOP ROTATION AND SET AT THE CURRENT AXIS/REALIGN SHAPES
   case 'r':    
   r =0.0;//reset rotation values 
   v =0.0;
   f =0.0;
 break;
 case 'R':    
   r =0.0;
   v =0.0;
   f =0.0;
 break;
 //QUITING THE PROGRAM
    case 'q':  //hundle lowercase event
    exit(0);
    break;
 case 'Q':  //hundle uppercase event
    exit(0);
    break;
 }
 }
 void key(unsigned char key, int x, int y)
 {
   keyboard((int) key);
 }
 // one side of larger cube
 static void cubebase(void)
 //specify a side of a cube
 {
 //material properties
   GLfloat mat_diffuse[]={0.0,1.0,2.0,2.0};
   glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
   glBegin (GL_POLYGON);
   glVertex3d(-0.5,-0.5,0.0);
   glVertex3d(-0.5, 0.5,0.0);
   glVertex3d( 0.5, 0.5,0.0);
   glVertex3d( 0.5,-0.5,0.0);
   glEnd();
 }
 //one side of smaller cube
 static void cubebase2(void)
 //specify a side of a cube
 {
 //material properties
   GLfloat mat_diffuse[]={1.0,1.0,1.0,1.0}; 
   glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
 glScaled(0.5,0.5,0.5);// scale the smaller cube
   glBegin (GL_POLYGON);
 glVertex3d(-0.5,-0.5,0.0);
   glVertex3d(-0.5, 0.5,0.0);
   glVertex3d( 0.5, 0.5,0.0);
   glVertex3d( 0.5,-0.5,0.0);
 glEnd();
 }
 // CONE
 static void cone(void)
 //specify a side of a cube
 {
    int i;
    float numStrips;
    int angle;
  //material properties
   GLfloat mat_diffuse[]={1.1,0.0,1.0,1.0};
   glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
 numStrips=100;
 glBegin(GL_TRIANGLE_FAN);
   glVertex3f(0, 1.0, 0.); // the point of the cone
   for (i=0; i < numStrips; i++) {
   angle = 20. * (float)i * PI / (float)numStrips;
   glVertex3f(0.5cos(angle), 0.0, 0.5sin(angle));
 // code to calculate normals would go here
   }
 glEnd();
 } 
 static void cube (void) //larger cube
 //uses cube suide to construct a cube, making use of model view matrix
 {
  glMatrixMode(GL_MODELVIEW);// use model view matrix
  glPushMatrix();//push and duplicate current matrix     
  //construct side on +x axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.5,0.0,2.5);//x,y,z
  glRotated(90.0,0.0,1.0,0.0);
  cubebase();
  glPopMatrix();
 //construct side on -x axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(-0.5,0.0,2.5);
  glRotated(-90.0,0.0,1.0,0.0);
  cubebase();
  glPopMatrix();
 //construct side on +y axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.5,2.5);
  glRotated(-90.0,1.0,0.0,0.0);
  cubebase();
  glPopMatrix();
 //construct side on -y axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,-0.5,2.5);
  glRotated(90.0,1.0,0.0,0.0);
  cubebase();
  glPopMatrix();
 //construct top
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.0,3.0);
  glRotated(180.0,1.0,0.0,0.0);
  cubebase();
  glPopMatrix();
  //construct bottom
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.0,2.0);
  glRotated(180.0,1.0,0.0,0.0);
  cubebase();
  glPopMatrix();
  glPopMatrix();
 }
 static void cube2 (void)//smaller cube
 //uses cube suide to construct a cube, making use of model view matrix
 {
 glMatrixMode(GL_MODELVIEW);// use model view matrix
 glPushMatrix();//push and duplicate current matrix
 //construct side on +x axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.25,0.0,1.0);
  glRotated(90.0,0.0,1.0,0.0);
  cubebase2();
  glPopMatrix();
 //construct side on -x axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(-0.25,0.0,1.0);
  glRotated(-90.0,0.0,1.0,0.0);
  cubebase2();
  glPopMatrix();
 //construct side on +y axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.25,1.0);
  glRotated(-90.0,1.0,0.0,0.0);
  cubebase2();
  glPopMatrix();
 //construct side on -y axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,-0.25,1.0);
  glRotated(90.0,1.0,0.0,0.0);
  cubebase2();
  glPopMatrix();
 //construct top
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.0,1.25);
  glRotated(180.0,1.0,0.0,0.0);
  cubebase2();
  glPopMatrix();
 //construct bottom
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.0,0.75);
  glRotated(180.0,1.0,0.0,0.0);
  cubebase2();
  glPopMatrix();
  glPopMatrix();
 glPopMatrix();
 }
 static void Cone (void) //Cone
 //uses cube suide to construct a cube, making use of model view matrix
 {
  glMatrixMode(GL_MODELVIEW);// use model view matrix
 glPushMatrix();//push and duplicate current matrix
 //construct side on -y axis
  glPushMatrix();//push and duplicate current matrix
  glTranslated(0.0,0.0,-0.5);
  glRotated(130.0,1.0,0.0,0.0);
  cone();
  glPopMatrix();
 }
 static void Sphere (void) //sphere
 //uses cube suide to construct a cube, making use of model view matrix
 { //material properties
     GLfloat mat_diffuse[]={1.0,0.0,0.0,1.0};//red color 
     glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
 glMatrixMode(GL_MODELVIEW);   // use model view matrix
  glPushMatrix();               // push and duplicate current matrix
 glTranslated(0.0,0.0,-2.0);
     glutSolidSphere (0.8,10, 10); // radius,number of strips,smoothness
     glutSwapBuffers();            // apply buffering to all the images
 glPopMatrix();
 }
 static void display()
 {
 glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
  glutSwapBuffers();
 }
 static void rotate(void)
 {
 //rotates around z axis
  static GLdouble a =0.0;
  static GLdouble b =0.0;
  static GLdouble c =0.0;
  static GLdouble d =0.0;
  //clear previously drawn image before drawing the next
  glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
 if (!tracking && (spindx != 0 || spindy != 0))
     glutPostRedisplay();
  glRotatef(v, 1, f, 0);// orientation changer, if v changes
  glMatrixMode(GL_MODELVIEW);  // use model view matrix
  glPushMatrix();   //push and duplicate current matrix
  glRotated( a,0.0,r,1.0);          //rotation matrix
  cube();                 // call cube, the larger cube
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);   // use model view matrix
  glPushMatrix();    //push and duplicate current matrix
  glRotated( b,0.0,r,1.0);           //rotation matrix 
  cube2();                // call cube, the smaller cube
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);   // use model view matrix
  glPushMatrix();    //push and duplicate current matrix
  glRotated( c,0.0,r,1.0);           //rotation matrix
  Cone();                                   // call cone
  glPopMatrix();
 glMatrixMode(GL_MODELVIEW);// use model view matrix
  glPushMatrix();    //push and duplicate current matrix
  glRotated( d,0.0,r,1.0); //rotation matrix
  Sphere();     // call sphere
  glPopMatrix();
 //for large cube
  a += 5.0;       // the rotation direction is positive
   glPopMatrix();//and speed is decremented by 5.0 each time
 //for small cube
  b -= 5.0;
  glPopMatrix();
 //for the cone
  c += 5.0;      //  the rotation direction positive 
  glPopMatrix(); //and speed is incremented by 5.0 each time
 //for the sphere
     d -= 6.0;
     glPopMatrix();
     glutSwapBuffers();// apply buffering to all the images
 }
 static void reshape(GLsizei width,GLsizei height)
 {
 //define the view port- width and height of the display window
  glViewport(0,0,width ,height);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity();
  //define view frustrum
  gluPerspective(50.0,(GLdouble)width/(GLdouble)height,0.01,10.0);
 /50deg field opf view vertically, with aspect ratio, and  front and backclipping planes of -1.0 and 10.0/
 }
 static void initialize(void)
 {
 GLfloat lightOneDirection[] = {1, 0, 1};
 GLfloat lightOnePosition[] = {5, 5, 0, -2.5};//position at eye view
 GLfloat lightOneColor[] = {1.0, 1.0, 1.0, 1.0};//white
 //material properties
 GLfloat mat_diffuse[]={0.0,0.0,0.0,0.0};
 GLfloat mat_shininess[]= {1.0,1.0,1.0,1.0};
 //lighting properties
 GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};
 //light position
 GLfloat position[]={5.0,5.0,0.0,2.5};
 //flat shading
 glShadeModel (GL_FLAT);
 // create normals which are normalised automatically
 glEnable(GL_NORMALIZE);
 glEnable(GL_AUTO_NORMAL);
 // SET THE BACKGROUND (CLEAR) COLOR TO WHITE
 glClearColor(0.25,0.15,0.25,0.25);
 // enable lighting
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);
 // for 2d the middleview matrix is the identity
 glMatrixMode(GL_MODELVIEW);// use model view matrix
  glLoadIdentity();
 gluLookAt(5.0,7.0,1.0,/eye/
    0.0,0.0,0.0,/looking here///(center)
    0.0,0.0,1.0);/up vector///horizontal or vertical alignment
 //set the light position in eye(viewing) coordinates
  glLightfv(GL_LIGHT0,GL_POSITION,position);
  //actually this is direction sinse by default an infinite light source 
 is asseumed
  glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
     glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
     glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
     glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
     glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 100);//intesity of light(size 
 of light  spot)
     glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, lightOneDirection);
     glEnable(GL_LIGHT1);
  // enable the depth buffer
     glEnable(GL_DEPTH_TEST);
 // set the depth buffer for clearing
 glClearDepth(1.0);
 }
 int main( int argc, char *argv[] ){
 int window;
    // glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB );
    glutInitWindowSize(500,600);
    window = glutCreateWindow( "Ikapel" );
    glutSetWindow(window);
    glutKeyboardFunc(key);
    initialize();
 //register call backs
    glutDisplayFunc(display);//display function
    glutReshapeFunc(reshape);
    glutIdleFunc(rotate);
    glutMouseFunc(button);
 glutMainLoop();
    return 0;  // Never called!  glutMainLoop() never returns….
 }

Leave a Reply

Your email address will not be published. Required fields are marked *

Close
Please support the site
By clicking any of these buttons you help our site to get better
Social PopUP by Timersys