OpenGL:屏幕二维坐标转化为三维模型坐标

我们把OpenGL里模型的三维坐标往二维坐标的转化称为投影,则屏幕上的二维坐标往三维坐标转化则可以称为反投影,下面我们来介绍一下反投影的方法。

主要是gluUnProject函数的使用,下面是代码:

[cpp]  view plain copy
  1. void screen2GLPoint()  
  2. {  
  3.  int x = xCord;    /* 屏幕坐标 */  
  4.  int y = yCord;  
  5.  GLint viewport[4];  
  6.  GLdouble mvmatrix[16], projmatrix[16];  
  7.  GLfloat winx, winy, winz;  
  8.  GLdouble posx, posy, posz;  
  9.   
  10.  glPushMatrix();  
  11.   
  12.  //glScalef(0.1, 0.1, 0.1);  
  13.  glGetIntegerv(GL_VIEWPORT, viewport);   /* 获取三个矩阵 */  
  14.  glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);  
  15.  glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);  
  16.   
  17.  glPopMatrix();  
  18.   
  19.  winx = x;  
  20.  winy = HEIGHT - y;  
  21.   
  22.  glReadPixels((int)winx, (int)winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz);   /* 获取深度 */  
  23.  gluUnProject(winx, winy, winz, mvmatrix, projmatrix, viewport, &posx, &posy, &posz); /* 获取三维坐标 */  
  24.  cout << posx << ' ' << posy << ' ' << posz << endl;  
  25. }   

     注:(x, y )是屏幕坐标,(winX,,winY,winZ)是视景体坐标和深度坐标,(posx,posy,posz)是openGL坐标

      网上有的文章说还要考虑模型的旋转、平移与缩放,即反投影的时候也要进行反旋转、反平移与反缩放,但是经过我的实验,这个是不用考虑的,因为反投影的时候导出的三个矩阵就包含旋转、平移与缩放的矩阵信息。

但是,glReadPixels((int)winx, (int)winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz); 经常会出现winZ值为1.0的情况。就像我所做的,功能是移动物体,如果winZ的值为1.0之后,物体就跑的没影了。

我们可以使用TRACE("point:%f, %f, %f  \t", winX, winY, winZ);

                     TRACE("pos  :%f, %f, %f \n", posX, posY, posZ);
跟踪一下,居然发现如下的输出:

 point:633.000000, 301.000000, 0.963236
 pos  :0.318562, -9.291403, 0.769923
 point:633.000000, 298.000000, 1.000000
 pos  :39.343056, -1186.848810, -9917.619793

注意这里:当winZ的值变成1.0的时候就出现错误了

 

经过多方查找资料,发现了一个重大的问题:

glRealPixels的定义是什么?

——The glReadPixels function reads a block of pixels from the framebuffer.

问题就出现在这里。如果framebuffer里面没有东西,当然就读取不出来了啊。所以就会出现上面的错误。

经验证,果不然,如果鼠标点在空白的位置   point:439.000000, 356.000000, 1.000000   pos  :-2504.841247, -426.216424, -9799.354916


    其实上述代码并不保险,只针对一种特殊情况才好使,即glViewport(0, 0, screenWidth, screenHeight),screenWidth、screenHeight分别是客户区的宽和高,视口左下角坐标恰好是(0,0),并且未经过任何模型变换。

    从屏幕坐标向OpenGL坐标要经过两步,第一步是屏幕坐标向视景体坐标转换,第二步是视景体坐标向OpenGL坐标转换。上述代码中winX = (float)x;  winY = viewport[3] - (float)y;反映第一步,gluUnProject是第二步。一般说来,gluUnProject的转换是不会出问题的。



更多OpenGL章,请参考该博客: http://blog.csdn.net/augusdi/article/details/38596253

你可能感兴趣的:(OpenGL:屏幕二维坐标转化为三维模型坐标)