#OPENGL#拾取三维点

#OPENGL#拾取三维点

很久很久以前,那还是大一下,苦逼的学习了openGL,也算踏进了图形学领域吧,如今在中科院的工作也和图形学的相关,一切的偶然加上本人也喜欢图形学的缘故,在这条路走的还那么算回事,基本的知识差不多还是掌握了,也对openGL比较熟悉。可是以后的工作却和图形学一点都不搭边,本来也确实想放弃在这个领域浪费时间了,可是不知道为何又舍不得,所以,心里也暗自说,不管怎样,还是坚持一点点的学习图形学吧,正如乔布斯所说,你学习的任何东西,抑或改变你的一身,原话貌似不是这样啦。结合项目要求,研究了三维点的拾取,其实老早就想写一篇类似的文章了,但是比较偷懒,没有做,也不想发一篇很水的文章。

接吻

在充满三维物体的游戏中,如何能够准确的拾取你指定的物体,对游戏体验很重要,所以今天就来介绍一下如何在三维场景中拾取三维点。并附上了代码。也来明白3维点,如果映射到二维屏幕上面的,本问特别适合初学者。

前戏

我们知道,所谓的3D,其实还是显示在二维屏幕上,只不过图像的呈现非常具有真实感。那么3维的点如何转换到屏幕上的二维坐标呢?

这里已openGL的流程图为例,其他的图形库如DirectX也差不多。

先明白几个图形学中的几个概念,所谓的世界坐标系就是全局坐标系,物体的点坐标就是依据这个坐标系给定的。点,物体的旋转,缩放以及平移都是在这个坐标系中进行的;观察坐标系也称摄像机坐标系,想想一下我们照相的时候,其实是以摄像机为原点建立了坐标系,然后将所拍的景色投影到胶片上,所以这个坐标系决定了点和物体如何映射到观察平面,我们一般有二种投影方式,正投影和透视投影。观察平面可以想象成以前老式相机的胶片,也可以想象成你的屏幕。

有了之前的知识,我们就能明白openGL中一些高级的东西。在openGL中,openGL本身维护了二套矩阵,模型视图矩阵和投影矩阵。我们本身看不到,诸如glTranslate, glRotatef,gluLookAt和glLoadIdentity都是在操作这二套矩阵,至于openGL当前状态下的是什么矩阵,由glMatrixMode决定,相应的参数有GL_MODELVIEW和GL_PROJECTION。

模型视图矩阵M0作用是,将P0点进过一些的动作转换到观察坐标系,这些动作包含旋转,缩放和平移。转换后的P0坐标是以摄像机为原点建立起来的坐标P1。P1 = M0 * P0

投影矩阵M1作用是,将P1坐标转换到屏幕坐标P2,注意这里的屏幕坐标已经正规化,也就是说,P2的坐标范围已经在【-1,1】里了。至于为什么要正规化,我也不知道,不过貌似很多数学知识都要正规化,可想而知,0,1这二个数字的神奇,哈哈,乱说的,意淫一下。P2 = M1 * P1

给一个二维的例子吧

在黑色坐标系中的P0,如果在x,y轴平移的话,就会达到P1,记住这里P1还是相对于黑色坐标系,在转换到红色坐标系中后,此刻的P1才有红色坐标系中的坐标,以上的所有动作就相当于模型视图矩阵的作用,即P1 = M0 * P0.

接下来在观察坐标系中的坐标P1,按照下图进行投影(以透视投影为例)

openGL中的观察平面就是上图中的近平面。所以在视野范围的内的点都将会投影到这个近平面上。视野范围就在近平面和远平面之间,其余空间的物体会被裁剪。

高潮

在计算机中,做的工作远比以上介绍的多,诸如裁剪,正规化和光栅化都没有提及,不过单独从编程的角度来看,以上的知识足以。

  1. void display(void)  
  2. {  
  3.    M3DMatrix44f mat_proj, mat_modelview;  
  4.   
  5.    int width = glutGet( GLUT_WINDOW_WIDTH ), height = glutGet( GLUT_WINDOW_HEIGHT );  
  6.    glViewport (0, 0, (GLsizei) width, (GLsizei) height);   
  7.   
  8.    glGetIntegerv(GL_VIEWPORT, viewport);  
  9.   
  10.    glClear (GL_COLOR_BUFFER_BIT);  
  11.   
  12.    glPushAttrib(GL_POLYGON_BIT);  
  13.    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);  
  14.   
  15.    glMatrixMode (GL_PROJECTION);  
  16.    glLoadIdentity ();  
  17.    gluPerspective(65.0, (GLfloat) width/(GLfloat) height, 1.0, 300);  
  18.   
  19.    // 获取投影矩阵  
  20.    glGetFloatv(GL_PROJECTION_MATRIX, mat_proj);  
  21.   
  22.    glMatrixMode(GL_MODELVIEW);  
  23.    glLoadIdentity();  
  24.    gluLookAt(0, 0, 70, 0, 0, 0, 0, 1, 0);  
  25.    glColor4f(0.1, 0.4, 0.6, 0.7);  
  26.    glPushMatrix();  
  27.   
  28.         // 获取模型视图矩阵  
  29.         glGetFloatv(GL_MODELVIEW_MATRIX, mat_modelview);  
  30.   
  31.                 /*** 画出你想要的模型 ,具体可以看代码,在后面的连接中***/  
  32.   
  33.    glPopMatrix();  
  34.    glPopAttrib();  
  35.   
  36.    // 配置  
  37.    selection.set_config( corners, 8, left_bottom, right_top, mat_modelview, mat_proj, viewport);  
  38.   
  39.    /************************************************************************/  
  40.    /* 构造一个新的环境                                                                     */  
  41.    /************************************************************************/  
  42.   
  43.    if( bool_select_area ){ // 如果在拾取的话,就显示出来  
  44.   
  45.        selection.draw_area();  
  46.        selection.highlight_selected_pts();  
  47.   
  48.    }  
  49. }  

注意看上面的工作主要是获取当前openGL状态,即得到模型视图矩阵,投影矩阵和视口参数。

既然我们知道得到正规化的坐标点是如下方式:

P2=M1*M0*P0,然后再通过视口参数转换成像素坐标,在判断P2点是否落在所选的区域中,即可判断是否选中三维点。

具体的代码请看后面的连接中 math3d.cpp中的函数m3dProjectXY。

睡觉

具体的代码全部放在我的github上了,具体的点击一下连接https://github.com/baiyang/opengl

在上几个图,

#OPENGL#拾取三维点

#OPENGL#拾取三维点

-----------------打造高质量的文章 更多关注 把酒泯恩仇---------------

为了打造高质量的文章,请  推荐  一下吧。。。。谢谢了,请关注我后续的文章,会更精彩哦

请关注sina微博:http://weibo.com/baiyang26

把酒泯恩仇官方博客:http://www.ibaiyang.org 【推荐用google reader订阅】

把酒泯恩仇官方豆瓣:http://www.douban.com/people/baiyang26/

如果您想转载本博客,请注明出处

如果您对本文有意见或者建议,欢迎留言

相关推荐