Upcoming Events


Quick Stats
4262 people currently visiting GDNet.
2236 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!



Link to us

  search:   

OpenGLŪ Programming Guide: The Official Guide to Learning OpenGLŪ, Version 2.1, 6th Edition
Excerpt from Chapter 3: Viewing


Reversing or Mimicking Transformations

The geometric processing pipeline is very good at using viewing and projection matrices and a viewport for clipping to transform the world (or object) coordinates of a vertex into window (or screen) coordinates. However, there are situations in which you want to reverse that process. A common situation is when an application user utilizes the mouse to choose a location in three dimensions. The mouse returns only a two-dimensional value, which is the screen location of the cursor. Therefore, the application will have to reverse the transformation process to determine where in three-dimensional space this screen location originated.

The Utility Library routines gluUnProject() and gluUnProject4() perform this reversal of the transformations. Given the three-dimensional window coordinates for a transformed vertex and all the transformations that affected it, gluUnProject() returns the original world coordinates of that vertex. (Use gluUnProject4() if the depth range is other than the default [0, 1].)

int gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz);

Maps the specified window coordinates (winx, winy, winz) into object coordinates, using transformations defined by a modelview matrix (modelMatrix), projection matrix (projMatrix), and viewport (viewport). The resulting object coordinates are returned in objx, objy, and objz. The function returns GL_TRUE, indicating success, or GL_FALSE, indicating failure (such as a noninvertible matrix). This operation does not attempt to clip the coordinates to the viewport or eliminate depth values that fall outside of glDepthRange().

There are inherent difficulties in trying to reverse the transformation process. A two-dimensional screen location could have originated from anywhere on an entire line in three-dimensional space. To disambiguate the result, gluUnProject() requires that a window depth coordinate (winz) be provided, specified in terms of glDepthRange(). (For more about depth range, see "The Transformed Depth Coordinate.") For the default values of glDepthRange(), winz at 0.0 will request the world coordinates of the transformed point at the near clipping plane, while winz at 1.0 will request the point at the far clipping plane.

Example 3-8 demonstrates gluUnProject() by reading the mouse position and determining the three-dimensional points at the near and far clipping planes from which the mouse position was transformed. The computed world coordinates are printed to standard output, but the rendered window itself is just black.

Example 3-8 Reversing the Geometric Processing Pipeline: unproject.c

void display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glFlush();
}

void reshape(int w, int h)
{
  glViewport(0, 0, (GLsizei) w, (GLsizei) h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void mouse(int button, int state, int x, int y) 
{
  GLint viewport[4];
  GLdouble mvmatrix[16], projmatrix[16];
  GLint realy; /* OpenGL y coordinate position */
  GLdouble wx, wy, wz; /* returned world x, y, z coords */

  switch (button) {
   case GLUT_LEFT_BUTTON:
     if (state == GLUT_DOWN) {
      glGetIntegerv(GL_VIEWPORT, viewport);
      glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
      glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
/* note viewport[3] is height of window in pixels */
      realy = viewport[3] - (GLint) y - 1;
      printf("Coordinates at cursor are (%4d, %4d)\n", 
        x, realy);
      gluUnProject((GLdouble) x, (GLdouble) realy, 0.0,
        mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
      printf("World coords at z=0.0 are (%f, %f, %f)\n",
        wx, wy, wz);
      gluUnProject((GLdouble) x, (GLdouble) realy, 1.0,
        mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
      printf("World coords at z=1.0 are (%f, %f, %f)\n",   
        wx, wy, wz);
     }
     break;
   case GLUT_RIGHT_BUTTON:
     if (state == GLUT_DOWN)
      exit(0);
     break;
   default:
     break;
  }
}

int main(int argc, char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize(500, 500); 
  glutInitWindowPosition(100, 100);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display); 
  glutReshapeFunc(reshape); 
  glutMouseFunc(mouse);
  glutMainLoop();
  return 0;
}

GLU 1.3 introduces a modified version of gluUnProject(). gluUnProject4() can handle nonstandard glDepthRange() values and also w-coordinate values other than 1.

int gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLclampd zNear, GLclampd zFar, GLdouble *objx, GLdouble *objy, GLdouble *objz, GLdouble *objw);

Overall, the operation is similar to gluUnProject(). Maps the specified window coordinates (winx, winy, winz, clipw) into object coordinates, using transformations defined by a modelview matrix (modelMatrix), projection matrix (projMatrix), viewport (viewport), and the depth range values zNear and zFar. The resulting object coordinates are returned in objx, objy, objz, and objw.

gluProject() is another Utility Library routine, which is related to gluUnProject(). gluProject() mimics the actions of the transformation pipeline. Given three-dimensional world coordinates and all the transformations that affect them, gluProject() returns the transformed window coordinates.

int gluProject(GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *winx, GLdouble *winy, GLdouble *winz);

Maps the specified object coordinates (objx, objy, objz) into window coordinates, using transformations defined by a modelview matrix (modelMatrix), projection matrix (projMatrix), and viewport (viewport). The resulting window coordinates are returned in winx, winy, and winz. The function returns GL_TRUE, indicating success, or GL_FALSE, indicating failure.


Note - Note: The matrices passed to gluUnProject(), gluUnProject4(), and gluProject() are in the OpenGL-standard column-major order. You might use glGetDoublev() and glGetIntegerv() to obtain the current GL_MODELVIEW_MATRIX, GL_PROJECTION_MATRIX, and GL_VIEWPORT values for use with gluUnProject(), gluUnProject4(), or gluProject().






Contents
  Introduction
  Page 1
  Page 2
  Page 3
  Page 4
  Page 5
  Page 6
  Page 7
  Page 8
  Page 9

  Printable version
  Discuss this article