JMU
Transformation in OpenGL
with Examples


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


A Review of Viewing
  1. ModelView Matrix:
    • From object coordinates to eye coordinates
    • glMatrixMode(GL_MODELVIEW);
  2. Projection Matrix
    • From eye coordinates to clip coordinates
    • glMatrixMode(GL_PROJECTION);
ModelView Matrix
The Projection
The Composition of Different Transformations
An Example

The Sun, Earth and Moon

openglexamples/transforms/solarsystem.c (Fragment: display)
        /**
 * The display callback
 */
void display() {
  glClear(GL_COLOR_BUFFER_BIT);

  glPushMatrix();

  // Draw the Sun at the origin with a radius of 2, 16 lines of latitude,
  // and 16 lines of longitude
  //
  // Use a wireframe so we can see the orientation
  glColor3f(1.0, 1.0, 0.0);
  glutWireSphere(1.0, 16, 16);

  // Rotate the local coordinate system
  // around the z-axis based on the day of the year
  //
  // Note: After drawing the sphere we are at the origin. So, we
  // are rotating around a ray from [0 0 0] to [0 0 1].
  glRotatef(((GLfloat) day) / 365.0f * 360.0f, 0.0, 0.0, 1.0);

  // Translate the local coordinate system along the x-axis the
  // radius of the Earth's orbit
  //
  // Note: The x-axis has already been rotated.
  glTranslatef(4.0, 0.0, 0.0);

  // To rotate the Moon around the center of the Earth we need
  // a different local coordinate system. Save the current
  // local coordinate system first
  glPushMatrix();

  // Rotate the new local coordinate system around the z-axis
  // based on the day of month
  glRotatef(((GLfloat) dom) / 28.0f * 360.0f, 0.0, 0.0, 1.0);

  // Translate the new local coordinate along the x-axis the
  // radius of the Moon's orbit
  glTranslatef(1.0, 0.0, 0.0);

  // Draw the Moon
  glColor3f(1.0, 1.0, 1.0);
  glutWireSphere(0.1, 4, 4);

  // Pop the previous local coordinate system
  glPopMatrix();

  // Rotate the local coordinate system around the z-axis based on
  // the hour of the day
  //
  // Note: The origin is now at the appropriate point on the orbit.
  glRotatef(((GLfloat) hour) / 24.0f * 360.0f, 0.0, 0.0, 1.0);

  // Draw the Earth
  //
  // Use a wireframe so we can see it revolve
  glColor3f(0.0, 0.0, 1.0);
  glutWireSphere(0.5, 16, 16);

  glPopMatrix();

  glFlush();
  glutSwapBuffers();
}
        
Another Example

Hinged Blocks

openglexamples/transforms/hinges.c (Fragment: display)
        /**
 * The display callback
 */
void display() {
  glClear(GL_COLOR_BUFFER_BIT);

  glPushMatrix();

  // Translate the local coordinate system to the hinge
  // of the first block
  glTranslatef(-1.0, 0.0, 0.0);

  // Rotate the local coordinate system around the z-axis
  //
  // Note: We are rotating around a ray to [0 0 1].
  glRotatef((GLfloat) alpha, 0.0, 0.0, 1.0);

  // Translate the local coordinate system back to the center
  glTranslatef(1.0, 0.0, 0.0);

  // Draw the first block
  glutWireCube(2.0);

  // Translate the local coordinate system to the hinge
  // of the second block
  glTranslatef(1.0, 0.0, 0.0);

  // Rotate the local coordinate system around the z-axis
  //
  // Note: We are rotating around a ray to [0 0 1].
  glRotatef((GLfloat) beta, 0.0, 0.0, 1.0);

  // Translate the local coordinate system to the center of the
  // second block
  glTranslatef(1.0, 0.0, 0.0);

  // Draw the second block
  glutWireCube(2.0);

  glPopMatrix();

  glFlush();
  glutSwapBuffers();
}
        
A Third Example

First-Person Viewing

openglexamples/transforms/firstperson.c
        #include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glut.h>

/**
 * \file
 * An application that displays a first person view of a simple world.
 *
 * On Linux, compile with:
 *   g++ -o firstperson -Wall firstperson.c -lglut -lGL -lGLU
 *
 * NOTE: The camera/viewer starts in the middle of the world. So, you should
 * probably move back several times to see everything.
 * 
 * @author  Prof. David Bernstein, James Madison University
 */

static GLfloat x = 0.0, z = 0.0, angle = 0.0;

/**
 * Convert degrees to radians.
 *
 * @param degrees   The angle in degrees
 * @return          The angle in radians
 */
inline GLfloat deg2rad(GLfloat degrees) {
  return degrees * M_PI / 180.0;
}

/**
 * Convert radians to degrees
 *
 * @param radians   The angle in radians
 * @return          The angle in degrees
 */
inline GLfloat rad2deg(GLfloat radians) {
  return radians * (180.0 / M_PI);
}

/**
 * Draw the objects in the world.
 */
void drawWorld() {
  glColor3f(1.0f, 1.0f, 1.0f);

  // The "near" side of the world
  glPushMatrix();
  glTranslatef(0.0, 0.0, 5.0);
  glRotatef(-90.0, 1.0, 0.0, 0.0);
  glutSolidCone(1.0, 1.0, 10, 10);
  glPopMatrix();

  // The "right" side of the world
  glPushMatrix();
  glTranslatef(5.0, 0.0, 0.0);
  glutSolidTorus(0.5, 1.0, 10, 10);
  glPopMatrix();

  // The "left" side of the world
  glPushMatrix();
  glTranslatef(-5.0, 0.0, 0.0);
  glutSolidSphere(1.0, 10, 10);
  glPopMatrix();

  // The "far" side of the world
  glPushMatrix();
  glTranslatef(0.0, 0.0, -5.0);
  glutSolidTeapot(1.0);
  glPopMatrix();
}

/**
 * The display callback.
 */
void display() {
  glMatrixMode(GL_MODELVIEW);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Reset the local coordinate system
  glLoadIdentity();

  // Rotate around the y-axis
  glRotatef(angle, 0.0, 1.0, 0.0);

  // Translate the local coordinate system "backwards" an
  // appropriate amount (based on the rotation angle)
  glTranslatef(-x, 0.0, -z);

  // Draw the world
  drawWorld();

  glFlush();
  glutSwapBuffers();
}

/**
 * Initialize GLUT and OpenGL.
 */
void init() {
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(500, 500);
  glutCreateWindow("First Person");
  glClearColor(0.0, 0.0, 0.0, 1.0);

  glShadeModel(GL_SMOOTH);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);  // Use the default light
}

/**
 * Handle keyboard events.
 */
void keyboard(unsigned char key, int xMouse, int yMouse) {
  GLfloat deltaX, deltaZ;

  // Move forward or backward
  if ((key == 'f') || (key == 'b')) {
    // Calculate the change in x and z necessary for a 1-unit
    // move in the direction I am facing
    deltaX = sin(deg2rad(angle));
    deltaZ = cos(deg2rad(angle));

    if (key == 'f') {
      x += deltaX;
      z -= deltaZ;
    } else if (key == 'b') {
      x -= deltaX;
      z += deltaZ;
    }
  }
  // Rotate right (clockwise) or left (counter-clockwise)
  else if (key == 'r') {
    angle += 10.0;
    if (angle > 360)
      angle -= 360;
  } else if (key == 'l') {
    angle -= 10.0;
    if (angle < 0)
      angle += 360;
  }
  // Reset
  else if (key == ' ') {
    angle = 0.0;
    x = 0.0;
    z = 0.0;
  }

  glutPostRedisplay();
}

/**
 * The reshape callback (i.e., the function that is called
 * each time the window is re-sized).
 *
 * @param width   The new width
 * @param height  The new height
 */
void reshape(int width, int height) {
  GLfloat aspect;

  glViewport(0, 0, (GLsizei) width, (GLsizei) height);

  // Setup the projection matrix
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  aspect = (GLfloat) width / (GLfloat) height;
  gluPerspective(60.0, aspect, 1.0, 1000.0);
}

/**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv) {
  // Initialize
  glutInit(&argc, argv);
  init();

  // Callbacks
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);

  // Start the event loop
  glutMainLoop();

  return 0;
}