本文主要是介绍【OpenGL】鼠标点击获取世界坐标,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
【OpenGL】鼠标点击获取世界坐标
标签(空格分隔): OpenGL
起因
因为最近在做图形学相关毕设,需要时间鼠标交互获取三维坐标(世界坐标系)。于是在网上查了一些博客与资料,放进自己代码中,效果怎么都不对。于是才自己静下心来,好好研究。
OpenGL中的坐标系
OpenGL总共有5个坐标系,它们分别是:
- 局部空间或称物体空间
- 世界空间
- 观察空间或称视觉空间
- 裁剪空间
- 屏幕空间
下面我按照我自己的理解简单说明一下这5个空间。
局部空间:即所有的物体在创建时,都会处在坐标原点的位置。
世界空间:我们需要在将不同的物体指定到各自的位置,这时就是需要运用到平移,缩放,旋转等矩阵操作,就是为了将物体从局部空间变化到世界空间。
观察空间:世界空间中不仅有物体,还有观察点(视点),物体以视点为原点所得到的坐标就是物体在观察空间中的坐标。
裁剪空间:将投影范围通过插值转化为CVV(Clip Coordinate System)以便于裁剪
屏幕空间:裁剪后的物体通过插值,计算出在窗口中的坐标,从而绘制出来。
下图是坐标系的变换流程图:
从一个空间变换为另一个空间(即从一个基变化为另一个基)是由矩阵来实现的。
局部空间到世界空间的变化矩阵称为模型矩阵
世界空间到观察空间的变化矩阵称为观察矩阵,具体矩阵推导请看:【转载】推导相机变换矩阵
观察空间到裁剪空间的变化矩阵称为投影矩阵,具体矩阵推导请看:【转载】深入探索透视投影变换
通过鼠标点击获取三维坐标
网上百度的代码基本都是这样:
void Get3Dpos(int x, int y, fVector3* pp) {GLint viewport[4];GLdouble modelview[16];GLdouble projection[16];GLfloat winX, winY, winZ;GLdouble object_x, object_y, object_z;int mouse_x = x;int mouse_y = y;glGetDoublev(GL_MODELVIEW_MATRIX, modelview);glGetDoublev(GL_PROJECTION_MATRIX, projection);glGetIntegerv(GL_VIEWPORT, viewport);winX = (float)mouse_x;winY = (float)viewport[3] - (float)mouse_y - 1.0f;glReadBuffer(GL_BACK);glReadPixels(mouse_x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ, modelview, projection, viewport, &object_x, &object_y, &object_z);*pp.x = object_x;*pp.y = object_y;*pp.z = object_z;
}
经过我在程序中测试,得到的坐标应该是视点坐标。而我想实现的是获得世界坐标系。这里就需要用矩阵对坐标系进行变化,由视点坐标系变为世界坐标系。
根据博客推导相机变换矩阵,观察矩阵的表示形式为(TR)-1,因此,从视点坐标变为世界坐标需要进行的变换为(TR)。
设视点的是世界坐标为(Tx,Ty,Tz),视点的UVN系统的基为U、V、N。
则
所以,上述代码中求出的pp(pp.x, pp.y, pp.z, 1),最后左乘上矩阵M,即可得到三维世界坐标。
//根据屏幕坐标得到视点空间坐标
void Get3Dpos(int x, int y, fVector3* pp) {GLint viewport[4];GLdouble modelview[16];GLdouble projection[16];GLfloat winX, winY, winZ;GLdouble object_x, object_y, object_z;int mouse_x = x;int mouse_y = y;glGetDoublev(GL_MODELVIEW_MATRIX, modelview);glGetDoublev(GL_PROJECTION_MATRIX, projection);glGetIntegerv(GL_VIEWPORT, viewport);winX = (float)mouse_x;winY = (float)viewport[3] - (float)mouse_y - 1.0f;glReadBuffer(GL_BACK);glReadPixels(mouse_x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);gluUnProject((GLdouble)winX, (GLdouble)winY, (GLdouble)winZ, modelview, projection, viewport, &object_x, &object_y, &object_z);*pp.x = object_x;*pp.y = object_y;*pp.z = object_z;
}//根据视点空间坐标得到世界空间坐标
GetWorldPos(int x,int y){//得到观察空间的坐标fVector3 pp;Pick(x, y, &pp);//求视点的UVN系统fVector3 U, V, N; //fVector3为自定义向量类fVector3 up = {0.0,1.0,0.0};fVector3 eye, direction; //视点坐标与观察点坐标N = eye - direction //矢量减法U = N.cross(up); //矢量叉乘V = N.cross(U);N.normalize(); //矢量归一化U.normalize();V.normalize();//求世界坐标fVector3 worldpos = { 0.0f,0.0f,0.0f };worldpos.x = U.x * pp.x + V.x * pp.y + N.x * pp.z + eye.x;worldpos.x = U.y * pp.x + V.y * pp.y + N.y * pp.z + eye.y;worldpos.z = U.z * pp.x + V.z * pp.y + N.z * pp.z + eye.z;
}
效果
这篇关于【OpenGL】鼠标点击获取世界坐标的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!