title: Translating mouse coordinates to model coordinates in OpenGL when rotations are involved
body: <p>In the Qt Forums I found <a href="http://qt-project.org/forums/viewthread/49236/" rel="nofollow noreferrer">this question</a> and sparkled my curiosity.</p>
  
  <p>I found a very simple example in Qt to display a cube and modified the cube logic to create a cube with a side length of 1 unit. </p>
  
  <p>Then I tried to click on the model and show the coordinates of the area where I clicked.</p>
  
  <p>When there are no rotations involved, it seems that the picking works fine. But! If I un-comment the rotations (or one of them) in <code>paintGL</code> I end up with "wrong" values.</p>
  
  <p>For example:</p>
  
  <ul>
  <li>No rotations and click almost on the leftmost border of the cube: the <code>gluUnProject</code> method says that I clicked on the point <code>{ -0.49075, 0.234, 0.5 }</code>, which seems ok.</li>
  </ul>
  
  <p><img src="https://i.stack.imgur.com/rsZrK.png" alt="Cube without rotations"></p>
  
  <ul>
  <li>Rotations enabled and click almost on the leftmost border of the cube: I receive the point <code>{ -0.501456, 0.157555, -0.482942 }</code>, which seems wrong. The <code>x</code> coordinate is off its range of <code>-0.5, 0.5</code>.</li>
  </ul>
  
  <p><img src="https://i.stack.imgur.com/tOOqG.png" alt="Cube with the two rotations enabled"></p>
  
  <p>I think the <em>coordinates transformation</em> is okay. I've been researching through Google and the people always use the same piece of code. Moreover, the color information of the pixel matches the color of the face where I clicked.</p>
  
  <p>So, can anyone tell me why when a rotation is involved I get wrong coordinates? I think I'm failing in some basic 3D understanding, but I'm not able to realize where it is.</p>
  
  <p>Here's the code:</p>
  
  <p><strong>main.cpp:</strong></p>
  
  <pre><code>#include &lt;QApplication&gt;
  #include "GLCube.h"
  
  int main(int argc, char *argv[])
  {
      QApplication a(argc, argv);
  
      GLCube w;
      w.resize(800,600);
      w.show();
  
      return a.exec();
  }
  </code></pre>
  
  <p><strong>GLCube.h</strong></p>
  
  <pre><code>#ifndef GLCUBE_H
  #define GLCUBE_H
  
  #include &lt;QtOpenGL&gt;
  #include &lt;QGLWidget&gt;
  
  class GLCube : public QGLWidget{
    Q_OBJECT // must include this if you use Qt signals/slots
  public:
      GLCube(QWidget *parent = NULL)
          : QGLWidget(parent) {
      }
  protected:
      // Set up the rendering context, define display lists etc.:
     void initializeGL();
     // draw the scene:
     void paintGL();
     // setup viewport, projection etc.:
     void resizeGL (int width, int height);
     virtual void mousePressEvent(QMouseEvent *pme);
  };
  
  #endif
  </code></pre>
  
  <p><strong>GLCube.cpp:</strong></p>
  
  <pre><code>#include "GLCube.h"
  
  #include &lt;cmath&gt;
  #include &lt;iostream&gt;
  #include &lt;iomanip&gt;
  
  #include "GL/glu.h"
  
  namespace {
      float ver[8][3] =
      {
          { 0.5, -0.5, 0.5 },
          { -0.5, -0.5, 0.5 },
          { -0.5, -0.5, -0.5 },
          { 0.5, -0.5, -0.5 },
          { 0.5, 0.5, 0.5 },
          { -0.5, 0.5, 0.5 },
          { -0.5, 0.5, -0.5 },
          { +0.5, 0.5, -0.5 }
      };
      GLfloat color[8][4] =
      {
          {0.0,0.0,0.0, 1.0},
          {1.0,0.0,0.0, 1.0 },
          {1.0,1.0,0.0, 1.0 },
          {0.0,1.0,0.0, 1.0 },
          {0.0,0.0,1.0, 1.0 },
          {1.0,0.0,1.0, 1.0 },
          {1.0,1.0,1.0, 1.0 },
          {0.0,1.0,1.0, 1.0 },
      };
  
      void quad(int a,int b,int c,int d, int col)
      {
          glPointSize( 5 );
          glBegin(GL_POINTS);
              glColor4fv(color[1]);
              glVertex3fv(ver[a]);
  
              glColor4fv(color[2]);
              glVertex3fv(ver[b]);
  
              glColor4fv(color[3]);
              glVertex3fv(ver[c]);
  
              glColor4fv(color[4]);
              glVertex3fv(ver[d]);
          glEnd();
  
          glBegin(GL_LINES);
              glColor4fv(color[1]);
              glVertex3fv(ver[a]);
              glVertex3fv(ver[b]);
  
              glColor4fv(color[1]);
              glVertex3fv(ver[b]);
              glVertex3fv(ver[c]);
  
              glColor4fv(color[1]);
              glVertex3fv(ver[c]);
              glVertex3fv(ver[d]);
  
              glColor4fv(color[1]);
              glVertex3fv(ver[d]);
              glVertex3fv(ver[a]);
          glEnd();
  
          glBegin(GL_QUADS);
          glColor4fv(/*color[a]*/ color[col] );
          glVertex3fv(ver[a]);
  
      //    glColor3fv(color[b]);
          glVertex3fv(ver[b]);
  
      //    glColor3fv(color[c]);
          glVertex3fv(ver[c]);
  
      //    glColor3fv(color[d]);
          glVertex3fv(ver[d]);
          glEnd();
      }
  
      void colorcube()
      {
  //        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
          quad( 3, 2, 1, 0, 1 ); // bottom
          quad( 7, 6, 5, 4, 2); // top
          quad( 6, 2, 1, 5, 3 ); // front
          quad( 7, 3, 0, 4, 5 ); // back
          quad( 7, 6, 2, 3, 6 ); // left
          quad( 4, 5, 1, 0, 7); // right
      }
  }
  /*
   * Sets up the OpenGL rendering context, defines display lists, etc.
   * Gets called once before the first time resizeGL() or paintGL() is called.
   */
  void GLCube::initializeGL(){
      //activate the depth buffer
      glEnable(GL_DEPTH_TEST);
      qglClearColor(Qt::black);
      glEnable(GL_CULL_FACE);
  }
  
  
  /*
   *  Sets up the OpenGL viewport, projection, etc. Gets called whenever the widget has been resized
   *  (and also when it is shown for the first time because all newly created widgets get a resize event automatically).
   */
  void GLCube::resizeGL (int width, int height){
      glViewport( 0, 0, (GLint)width, (GLint)height );
      /* create viewing cone with near and far clipping planes */
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glFrustum( -1.0, 1.0, -1.0, 1.0, 15.0, 30.0);
  
      glMatrixMode( GL_MODELVIEW );
  }
  
  /*
   * Renders the OpenGL scene. Gets called whenever the widget needs to be updated.
   */
  void GLCube::paintGL(){
  
      //delete color and depth buffer
      glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  
      glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();
          glTranslatef(0.0f,0.0f,-20.0f); //move along z-axis
          glRotatef(30.0,0.0,1.0,0.0); //rotate 30 degress around y-axis
          glRotatef(15.0,1.0,0.0,0.0); //rotate 15 degress around x-axis
  
      colorcube();
  //    originalcube();
  }
  
  void GLCube::mousePressEvent(QMouseEvent *pme) {
      GLint viewport[4];
      GLdouble modelview[16];
      GLdouble projection[16];
      glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
      glGetDoublev( GL_PROJECTION_MATRIX, projection );
      glGetIntegerv( GL_VIEWPORT, viewport );
  
      const int x = pme-&gt;x();
      const int y = viewport[3] - pme-&gt;y();
  
      qDebug() &lt;&lt; "HERE: " &lt;&lt; x &lt;&lt; y;
  
      GLfloat color[4];
      glReadPixels( x, y, 1, 1, GL_RGBA, GL_FLOAT, color);
      GLenum error = glGetError();
      std::cout &lt;&lt; "RETRIEVED COLOR:" &lt;&lt; color[0] &lt;&lt; ", " &lt;&lt; color[1] &lt;&lt; ", " &lt;&lt; color[2] &lt;&lt; ", " &lt;&lt; color[3] &lt;&lt; std::endl;
      printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
      if(GL_NO_ERROR != error) throw;
  
      GLdouble depthScale;
      glGetDoublev( GL_DEPTH_SCALE, &amp;depthScale );
      std::cout &lt;&lt; "DEPTH SCALE: " &lt;&lt; depthScale &lt;&lt; std::endl;
      GLfloat z;
      glReadPixels( x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &amp;z );
      error = glGetError();
      std::cout &lt;&lt; "X: " &lt;&lt; x &lt;&lt; ", Y: " &lt;&lt; y  &lt;&lt; ", RETRIEVED Z: " &lt;&lt; z &lt;&lt; std::endl;
      printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
      if(GL_NO_ERROR != error) throw;
      std::cout &lt;&lt; std::endl &lt;&lt; std::endl;
  
      GLdouble posX, posY, posZ;
      GLint result;
      result = gluUnProject( x, y, z, modelview, projection, viewport, &amp;posX, &amp;posY, &amp;posZ);
      error = glGetError();
      std::cout &lt;&lt; "3D point with POS: " &lt;&lt; posX &lt;&lt; " " &lt;&lt; posY &lt;&lt; " " &lt;&lt; posZ &lt;&lt; std::endl;
      printf( "\tERROR: %s (Code: %u)\n", gluErrorString(error), error );
      std::cout &lt;&lt; "\tglUnProject: " &lt;&lt; (( GL_FALSE == result ) ? "FALSE" : "TRUE") &lt;&lt; std::endl;
      if(GL_NO_ERROR != error) throw;
  }
  </code></pre>
  
  <p><strong>NOTE:</strong></p>
  
  <p>I'm running this in Windows 8.1 64 bit, Qt 4.8 and MinGW.</p>
  
  <p>Also, both <code>glReadPixels</code> and <code>gluUnProject</code> exit without errors (ERROR CODE = <code>GL_NO_ERROR</code> )</p>
  
  <p>And <code>glut</code> is not available. Only what <code>OpenGL</code>, <code>QtOpenGL</code> and/or <code>glu</code> offer.</p>