【OpenGL】鼠标点击获取世界坐标

编程入门 行业动态 更新时间:2024-10-20 07:40:59

【OpenGL】鼠标点击获取世界<a href=https://www.elefans.com/category/jswz/34/1771040.html style=坐标"/>

【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系统的基为UVN

T= ⎡⎣⎢⎢⎢100001000010TxTyTz1⎤⎦⎥⎥⎥(1) (1) T = [ 1 0 0 T x 0 1 0 T y 0 0 1 T z 0 0 0 1 ]

R= ⎡⎣⎢⎢⎢UxUyUz0VxVyVz0NxNyNz00001⎤⎦⎥⎥⎥(2) (2) R = [ U x V x N x 0 U y V y N y 0 U z V z N z 0 0 0 0 1 ]

M=T×R= ⎡⎣⎢⎢⎢UxUyUz0VxVyVz0NxNyNz0TxTyTz1⎤⎦⎥⎥⎥(4) (4) M = T × R = [ U x V x N x T x U y V y N y T y U z V z N z T z 0 0 0 1 ]

所以,上述代码中求出的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】鼠标点击获取世界坐标

本文发布于:2024-02-16 20:11:25,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1691341.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:坐标   鼠标点击   世界   OpenGL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!