opengl环境下的射线选择
2015-06-13 13:11
190 查看
用过OpenGL的人,应该都知道,OpenGL是自带拾取功能的,但用过的人应该也知道,这功能确实不好用。
OpenGL自带的选择功能主要有两种,名字堆栈(拾取)和读深度值判断选择,但这两种方法在实际项目中,未必都好用。
方法一:名字堆栈的方法,需要切换渲染模式,操作命名堆栈,计算拣选矩阵,检查选中记录。当要渲染的数据量特别大或渲染的对象众多时,显然是不可取的。
方法二:glReadPixel方法,读深度值的方法,这种方法比前面一种方法在某些时候稍微好用些,但有一个致命的限制,你鼠标选择的时候,必须选择到绘有实体的地方,否则就得不到正确的深度值。例如你渲染一个三维地形图,地形以Tin的方式渲染,如果你想选择某个顶点,但鼠标落在空白区,你就无法得到正确的深度值,得不到正确的深度值,自然没法根据gluUnproject函数反算到真实的地形坐标点,而实际应用中应该是即使你没完全落在该顶点上,也应该可以根据一个缓冲,在所有缓冲区内部的点集中选择一个距离光标最近的点作为你选择的点。
本文介绍一种方法——射线选择,这种方法也是游戏界和三维地形编程普遍采用的选择方法。
首先介绍一个二维三维坐标转换函数: gluUnProject()
此函数的具体用途是将一个OpenGL视区内的二维点转换为与其对应的场景中的三维坐标。
转换过程如下图所示(由点P在窗口中的XY坐标得到其在三维空间中的世界坐标):
这个函数在glu.h中的原型定义如下:
其中前三个值表示窗口坐标,中间三个分别为模型视图矩阵(Model/View Matrix),投影矩阵(Projection Matrix)和视区(ViewPort),最后三个为输出的世界坐标值。
第二步,首先获得视图矩阵,投影矩阵,视区三个数组值。
获取这三个变量的代码,应该放在绘制发生前,三个矩阵定以后。否则glPopMatrix之类的函数,可能导致你无法得到真正的投影矩阵和视图矩阵。
第三步,获取射线。因为两点确定一条线,所以,先通过计算视图最近点和最远点,得到该射线。
第四步,计算待选择目标跟该的关系,将与射线距离最近的对象,作为选择对象。
第五步,本文绘制了分布在不同三维空间的5个点,用鼠标右键,可以进行点的选择,如果选中,点会变成***,鼠标左键可以随意对这些点进行旋转等。
![](http://images.cnblogs.com/cnblogs_com/yanhuiw/lineselect.JPG)
源代码
OpenGL自带的选择功能主要有两种,名字堆栈(拾取)和读深度值判断选择,但这两种方法在实际项目中,未必都好用。
方法一:名字堆栈的方法,需要切换渲染模式,操作命名堆栈,计算拣选矩阵,检查选中记录。当要渲染的数据量特别大或渲染的对象众多时,显然是不可取的。
方法二:glReadPixel方法,读深度值的方法,这种方法比前面一种方法在某些时候稍微好用些,但有一个致命的限制,你鼠标选择的时候,必须选择到绘有实体的地方,否则就得不到正确的深度值。例如你渲染一个三维地形图,地形以Tin的方式渲染,如果你想选择某个顶点,但鼠标落在空白区,你就无法得到正确的深度值,得不到正确的深度值,自然没法根据gluUnproject函数反算到真实的地形坐标点,而实际应用中应该是即使你没完全落在该顶点上,也应该可以根据一个缓冲,在所有缓冲区内部的点集中选择一个距离光标最近的点作为你选择的点。
本文介绍一种方法——射线选择,这种方法也是游戏界和三维地形编程普遍采用的选择方法。
首先介绍一个二维三维坐标转换函数: gluUnProject()
此函数的具体用途是将一个OpenGL视区内的二维点转换为与其对应的场景中的三维坐标。
转换过程如下图所示(由点P在窗口中的XY坐标得到其在三维空间中的世界坐标):
这个函数在glu.h中的原型定义如下:
[code]代码 //Code highlighting produced by Actipro //CodeHighlighter //(freeware)http://www.CodeHighlighter.com/ int APIENTRY gluUnProject ( GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz);
其中前三个值表示窗口坐标,中间三个分别为模型视图矩阵(Model/View Matrix),投影矩阵(Projection Matrix)和视区(ViewPort),最后三个为输出的世界坐标值。
第二步,首先获得视图矩阵,投影矩阵,视区三个数组值。
[code]代码 //Code highlighting produced by Actipro //CodeHighlighter //(freeware)http://www.CodeHighlighter.com/ GLint viewport[4]; GLdouble modelview[16]; GLdouble projection[16]; glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数 glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection);
获取这三个变量的代码,应该放在绘制发生前,三个矩阵定以后。否则glPopMatrix之类的函数,可能导致你无法得到真正的投影矩阵和视图矩阵。
第三步,获取射线。因为两点确定一条线,所以,先通过计算视图最近点和最远点,得到该射线。
[code]代码 //Code highlighting produced by Actipro //CodeHighlighter //(freeware)http://www.CodeHighlighter.com/ winX = point.x; winY = screenHeight - point.y; //获取像素对应的前裁剪面的点坐标 bool bResult = gluUnProject(winX, winY, 0.0, modelview, projection, viewport, &posX, &posY, &posZ); FPoint3 nearPoint; nearPoint.x = posX; nearPoint.y = posY; nearPoint.z = posZ; //获取像素对应的后裁剪面的点坐标 bResult = gluUnProject(winX, winY, 1.0, modelview, projection, viewport, &posX, &posY, &posZ); FPoint3 farPoint; farPoint.x = posX; farPoint.y = posY; farPoint.z = posZ;
第四步,计算待选择目标跟该的关系,将与射线距离最近的对象,作为选择对象。
第五步,本文绘制了分布在不同三维空间的5个点,用鼠标右键,可以进行点的选择,如果选中,点会变成***,鼠标左键可以随意对这些点进行旋转等。
源代码
相关文章推荐
- shell学习第十天----sed查找与替换
- 微软推出一个非常有趣的网站—— How-old.net 看照片猜年龄!
- 微软推出一个非常有趣的网站—— How-old.net 看照片猜年龄!
- 一个实际项目Java架构设计之ETL(Kettle)部分介绍
- mysql5.6 linux下安装笔记
- mysql5.6 linux下安装笔记
- 字典枚举某网站游戏地址
- hadoop常用linux命令与操作
- shell学习第九天----分组
- hadoop初级到资深
- Hadoop项目实战-用户行为分析之分析与设计
- Linux ld命令
- I.MX6 Linux Qt 启动流程跟踪
- linux下一些问题
- POJ 2391 Ombrophobic Bovines 二分最大流+拆点
- Beckoff的EtherCAT从站代码架构解析
- 用Apache的HTACCESS保护密码
- Linux系统软件
- OpenCL的框架
- 揭秘!如何快速提高网站权重-关键词百度指数叠加