最近接触一个关于OpenGL的项目,使用VC++,由于自己从来没有接触过OpenGL,也只能且学且做了。遇到一个关于坐标转换的问题,在网上搜索了许多资料,搜索引擎的前100个结果页面中的回答和代码都是千篇一律,基本都是错的或者不完整。哎,估计都是抄来抄去,自己想都不想就写篇文章发出去,或者在论坛上随便百度个答案回复一下。
原创,原创,多么渴望多一点原创的内容啊。闲话少说,希望搜索到我这篇文章的人,对你有用。
功能很简单:鼠标点击屏幕中的某点,然后获取该点屏幕坐标对应的OpenGL坐标。鼠标点的坐标很容易获得,直接从鼠标点击消息中获取就可以,但是OpenGL坐标却需要做一定计算转换。需要用到的核心OpenGL函数是gluUnProject()
。
对于这个问题,在网上流传着如下类似的代码:
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
winX = (float)x;
winY = viewport[3] - (float)y;
glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
注:(x, y)
是屏幕坐标,(winX, winY, winZ)
是视景体坐标及深度坐标,(posX, posY, posZ)
是OpenGL坐标。
上述代码几乎占了搜索引擎前99%的结果,基本没有人说出其中的问题,估计可能也是出自某个教科书。上面的代码其实只能针对一种特殊情况才有效,即glViewport(0, 0, screenWidth, screenHeight)
,screenWidth、screenHeight分别是客户区的宽和高,视口左下角坐标恰好是(0, 0),并且未经过任何模型变换。
从屏幕坐标向OpenGL坐标转换需要经过两步:第一步是屏幕坐标向视景体坐标转换,第二步是视景体坐标向OpenGL坐标转换。上述代码中winX = (float)x; winY = viewport[3] - (float)y;反映第一步,gluUnProject()是第二步。一般说来,gluUnProject()的转换是不会出问题的。
如何进行正确的转换呢?
首先,在glGetIntegerv()之前必须添上模型变换的代码,即和绘图时使用的模型变换代码一样;其次,必须保证平移、缩放、旋转的顺序和绘图时的一致;另外,屏幕坐标向视景体坐标转换要正确。
还有非常重要的一点,就是在多视口情况下,活动视口必须最后绘制,使它作为当前的视口,这样才能保证glGetIntegerv()等取值函数能够得到正确的值。
好了,现在给出完整的代码,如下:
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glPushMatrix();
//缩放、平移、旋转等变换
glScalef(......);
glRotatef(......);
glTranslatef(......);
//变换要绘图函数里的顺序一样,否则坐标转换会产生错误
glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glPopMatrix();
winX = x;
winY = viewport[3] - (float)y;
glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
本文原创,希望看到我这篇文章的人,对你有用。
谢谢 是可以直接转换 然后当作顶点的几何坐标来用 我是昨天才弄出来的 但是在坐标转换前 一定要记得加上模型转换的语句 要不然转换出来的坐标会有问题 我就是犯了这个错误
Good,祝你好运~
能否 叫我 QQ:1294653048,请教一些问题,谢谢了
有问题请给我留言或发邮件,我很少用QQ。。
能否加下我的QQ:417336321 到时候有些问题要和你交流下!
QQ我很少用,直接在这里留言即可,我每天都会看。
好的 我想问下 就是OpenGL的纹理贴图的显示只能在OpenGL创建的窗口上还是可以像显示在MFC的控件上(例如 static text)?
你好,我用glortho,发现不行,不知道为什么?
能不能给出具体的代码呢
我是初学者
不错!赞一个
楼主想请教一个问题,三维坐标转换为二维坐标需呀注意哪些问题
最主要的是把几个坐标转换的矩阵弄清楚