鼠标点击选择三维图形中一个点
2014-04-02 17:15
127 查看
这些天在学习OpenGL,做一个绘制机器人轨迹的mfc软件,遇到了一系列问题。最棘手之一就是点击屏幕选择三维图形中的点了。查阅资料找到一种解决办法:绘制一条垂直屏幕的直线,与三维图形的第一个交点就是要选择的点了。也叫着拣选射线法:代码如下:
但是这种方法存在着一个弊端:
就是图形如果发生了旋转,平移,或者缩放,就不可用了,解决方案是:对屏幕坐标模型进行完全一致的转换,比如旋转平移缩放等,修改后的代码如下:
注:mouse_x mouse_y是鼠标点击的坐标,world_x,world_y,world_z是OpenGL坐标,返回值是一个贯穿视境的直线。screenHeight是窗口高度,因为OpenGL中原点和mfc中的原点位置不同,一个在左下角,一个左上角,所以需要进行转换。
获得了直线以后,还要判断图像上面的点哪个在这条直线上,就要运用立体几何知识,主要有以下几种方法:
1、三角形两边之和大于第三边,可以用我们获得的直线两端点分别与之做差求长度,两个长度相加如果和直线的长度差别不大,则说明点在线上;AC+BC=AB或者AC+AB=BC 或者AB+BC=AC
2、利用向量的方法,在同一条直线上的点,矢量平行,AC//BC, (Ax-Cx)/(Bx-Cx)=(Ay-Cy)/(By-Cy)=(Az-Cz)/(Bz-Cz)
3、使用线段的方程,求出AB的方程,搜索满足方程的点,
4、……
第二种方法的代码如下,
在Linesegment中增加函数bool ifHasPoint(float x,float y,float z,float delta);//delta是允许的误差,delta越小越精确
在调用时遍历所有点找到返回true的点;
class Point3f; class LineSegment; LineSegment GetSelectionRay(int mouse_x, int mouse_y) { // 获取 Model-View,Projection 矩阵 & 获取Viewport 视区 GLdouble modelview[16]; GLdouble projection[16]; GLint viewport[4]; glGetDoublev (GL_MODELVIEW_MATRIX, modelview); glGetDoublev (GL_PROJECTION_MATRIX, projection); glGetIntegerv (GL_VIEWPORT, viewport); GLdouble world_x, world_y, world_z; // 获取近裁剪面上的交点 gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 0.0, modelview, projection, viewport, &world_x, &world_y, &world_z); Point3f near_point(world_x, world_y, world_z); // 获取远裁剪面上的交点 gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 1.0, modelview, projection, viewport, &world_x, &world_y, &world_z); Point3f far_point(world_x, world_y, world_z); return LineSegment(near_point, far_point); }
但是这种方法存在着一个弊端:
就是图形如果发生了旋转,平移,或者缩放,就不可用了,解决方案是:对屏幕坐标模型进行完全一致的转换,比如旋转平移缩放等,修改后的代码如下:
LineSegment COpenGL::GetSelectionRay(int mouse_x, int mouse_y) { // 获取 Model-View,Projection 矩阵 & 获取Viewport 视区 GLint viewport[4]; GLdouble modelview[16]; GLdouble projection[16]; mouse_y=screenHeight-mouse_y;//屏幕高度减鼠标位置就是viewport中的y glPushMatrix(); // 变换要绘图函数里的顺序一样,否则坐标转换会产生错误 glTranslatef(xtran,ytran,ztran); // Move Left 1.5 Units And Into The Screen 6.0 glScalef(m_zoom,m_zoom,m_zoom); glRotatef(xrot,1.0f,0.0f,0.0f); glRotatef(yrot,0.0f,1.0f,0.0f); glRotatef(zrot,0.0f,0.0f,1.0f); glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数 glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); glPopMatrix(); GLdouble world_x, world_y, world_z; // 获取近裁剪面上的交点 gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 0.0, modelview, projection, viewport, &world_x, &world_y, &world_z); Point3f near_point(world_x, world_y, world_z); // 获取远裁剪面上的交点 gluUnProject( (GLdouble) mouse_x, (GLdouble) mouse_y, 1.0, modelview, projection, viewport, &world_x, &world_y, &world_z); Point3f far_point(world_x, world_y, world_z); return LineSegment(near_point, far_point); }
注:mouse_x mouse_y是鼠标点击的坐标,world_x,world_y,world_z是OpenGL坐标,返回值是一个贯穿视境的直线。screenHeight是窗口高度,因为OpenGL中原点和mfc中的原点位置不同,一个在左下角,一个左上角,所以需要进行转换。
获得了直线以后,还要判断图像上面的点哪个在这条直线上,就要运用立体几何知识,主要有以下几种方法:
1、三角形两边之和大于第三边,可以用我们获得的直线两端点分别与之做差求长度,两个长度相加如果和直线的长度差别不大,则说明点在线上;AC+BC=AB或者AC+AB=BC 或者AB+BC=AC
2、利用向量的方法,在同一条直线上的点,矢量平行,AC//BC, (Ax-Cx)/(Bx-Cx)=(Ay-Cy)/(By-Cy)=(Az-Cz)/(Bz-Cz)
3、使用线段的方程,求出AB的方程,搜索满足方程的点,
4、……
第二种方法的代码如下,
在Linesegment中增加函数bool ifHasPoint(float x,float y,float z,float delta);//delta是允许的误差,delta越小越精确
bool LineSegment::ifHasPoint(float x,float y,float z,float delta) { if( ((aPoint->x-x)/(bPoint->x-x)-(aPoint->y-y)/(bPoint->y-y)<delta) &&((aPoint->x-x)/(bPoint->x-x)-(aPoint->z-z)/(bPoint->z-z)<delta) ) return true; return false; }
在调用时遍历所有点找到返回true的点;
相关文章推荐
- Three.js获取鼠标点击的三维坐标示例代码
- 一个仿dota,点击鼠标让人物行走的简易demo
- 点击弹出一个div并显示在鼠标右下方
- input radio按钮点击选择,点击另外一个,前一个不被选择
- Python3 Tkinter基础 Canvas bind 绑定左键 鼠标左键点击时,在当前位置画出一个椭圆形
- 回到顶部,当页面下拉到一定高度时,就会出现回到顶部的按钮,点击回到顶部之后,会有一个速度的变化回滚到顶部,如果正在回到顶部时,鼠标的滚轮转动了就会停止回到顶部
- CSS属性选择器_鼠标点击出现列表
- asp.net 点击一个按钮弹出对话框选择文件然后选择文件完成之后就自动上传文件 input(file)
- 设计一个鼠标点击速度比赛游戏
- 设计一个鼠标点击速度比赛游戏。 *(1)显示一个按钮和文本框。 *(2)文本框显示鼠标点击次数
- 设计一个鼠标点击速度比赛游戏。 *(1)显示一个按钮和文本框。 *(2)文本框显示鼠标点击次数
- Extjs 中实现combox多选,已经解决了原有的bug 【选择多条记录后,鼠标点击其他空白处,选择的数据丢失,】
- 计划:写一个统计鼠标点击次数,滑动距离,键盘按键次数的软件
- GDI画图,判断鼠标点击点在某一画好的多边形、矩形、图形里
- 一个鼠标点击水波纹理shader
- ArcGIS api for javascript——图形-选择一个范围内的点
- 求助:程序如何模拟鼠标点击一个TreeView节点?
- wo 想做一个根据鼠标效果,平行的边选择,加线,根据鼠标移动分布位置,
- /*设计一个鼠标点击速度比赛游戏。 *(1)显示一个按钮和文本框。 *(2)文本框显示鼠标点击次数*/ import javax.swing.*;//引用 import java.awt.*; i
- 点击JButton 跳出一个文件选择框 获得文件的属性