openglopentkmouse-picking

How to do picking in modern OpenGL without gluUnProject?


How do you convert screen coordinates to world coordinates in modern OpenGL without the use of gluUnProject?


Solution

  • AFAIK - gluUnproject needs all the info supplied to it (modelview, projection, etc) and it only performs the matrix inversion calculation. So if you have those matrices, you could call gluUnproject or perform those calculations yourself.

    The code below is taken from here (copied over so that this answer still holds water if the link dies).

    int glhUnProjectf(float winx, float winy, float winz, float *modelview, float *projection, int *viewport, float *objectCoordinate)
      {
          // Transformation matrices
          float m[16], A[16];
          float in[4], out[4];
          // Calculation for inverting a matrix, compute projection x modelview
          // and store in A[16]
          MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview);
          // Now compute the inverse of matrix A
          if(glhInvertMatrixf2(A, m)==0)
             return 0;
          // Transformation of normalized coordinates between -1 and 1
          in[0]=(winx-(float)viewport[0])/(float)viewport[2]*2.0-1.0;
          in[1]=(winy-(float)viewport[1])/(float)viewport[3]*2.0-1.0;
          in[2]=2.0*winz-1.0;
          in[3]=1.0;
          // Objects coordinates
          MultiplyMatrixByVector4by4OpenGL_FLOAT(out, m, in);
          if(out[3]==0.0)
             return 0;
          out[3]=1.0/out[3];
          objectCoordinate[0]=out[0]*out[3];
          objectCoordinate[1]=out[1]*out[3];
          objectCoordinate[2]=out[2]*out[3];
          return 1;
      }
    
      void MultiplyMatrices4by4OpenGL_FLOAT(float *result, float *matrix1, float *matrix2)
      {
        result[0]=matrix1[0]*matrix2[0]+
          matrix1[4]*matrix2[1]+
          matrix1[8]*matrix2[2]+
          matrix1[12]*matrix2[3];
        result[4]=matrix1[0]*matrix2[4]+
          matrix1[4]*matrix2[5]+
          matrix1[8]*matrix2[6]+
          matrix1[12]*matrix2[7];
        result[8]=matrix1[0]*matrix2[8]+
          matrix1[4]*matrix2[9]+
          matrix1[8]*matrix2[10]+
          matrix1[12]*matrix2[11];
        result[12]=matrix1[0]*matrix2[12]+
          matrix1[4]*matrix2[13]+
          matrix1[8]*matrix2[14]+
          matrix1[12]*matrix2[15];
        result[1]=matrix1[1]*matrix2[0]+
          matrix1[5]*matrix2[1]+
          matrix1[9]*matrix2[2]+
          matrix1[13]*matrix2[3];
        result[5]=matrix1[1]*matrix2[4]+
          matrix1[5]*matrix2[5]+
          matrix1[9]*matrix2[6]+
          matrix1[13]*matrix2[7];
        result[9]=matrix1[1]*matrix2[8]+
          matrix1[5]*matrix2[9]+
          matrix1[9]*matrix2[10]+
          matrix1[13]*matrix2[11];
        result[13]=matrix1[1]*matrix2[12]+
          matrix1[5]*matrix2[13]+
          matrix1[9]*matrix2[14]+
          matrix1[13]*matrix2[15];
        result[2]=matrix1[2]*matrix2[0]+
          matrix1[6]*matrix2[1]+
          matrix1[10]*matrix2[2]+
          matrix1[14]*matrix2[3];
        result[6]=matrix1[2]*matrix2[4]+
          matrix1[6]*matrix2[5]+
          matrix1[10]*matrix2[6]+
          matrix1[14]*matrix2[7];
        result[10]=matrix1[2]*matrix2[8]+
          matrix1[6]*matrix2[9]+
          matrix1[10]*matrix2[10]+
          matrix1[14]*matrix2[11];
        result[14]=matrix1[2]*matrix2[12]+
          matrix1[6]*matrix2[13]+
          matrix1[10]*matrix2[14]+
          matrix1[14]*matrix2[15];
        result[3]=matrix1[3]*matrix2[0]+
          matrix1[7]*matrix2[1]+
          matrix1[11]*matrix2[2]+
          matrix1[15]*matrix2[3];
        result[7]=matrix1[3]*matrix2[4]+
          matrix1[7]*matrix2[5]+
          matrix1[11]*matrix2[6]+
          matrix1[15]*matrix2[7];
        result[11]=matrix1[3]*matrix2[8]+
          matrix1[7]*matrix2[9]+
          matrix1[11]*matrix2[10]+
          matrix1[15]*matrix2[11];
        result[15]=matrix1[3]*matrix2[12]+
          matrix1[7]*matrix2[13]+
          matrix1[11]*matrix2[14]+
          matrix1[15]*matrix2[15];
      }