轻轻松松做OpenGL拾取.doc_第1页
轻轻松松做OpenGL拾取.doc_第2页
轻轻松松做OpenGL拾取.doc_第3页
轻轻松松做OpenGL拾取.doc_第4页
轻轻松松做OpenGL拾取.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

轻轻松松做OpenGL拾取概述在科学和工程的3维可视化应用当中,用户在屏幕上点击就可以让应用程序知道用户点击的是什么对象。我们将这一过程,称之为拾取。想象一下,这一过程在软件中由自己编程来实现,将如何进行的。你得为此做各种变换,并找出各个对象最终在屏幕上的位置,然后判断究竟哪一下与鼠标最近。当然这样做是可行的,但没有人会真正去做这个事,因为过程实在是太繁琐了。幸运的是,OpenGL让硬件提供了对拾取的支持。基本思路如下:1. 让硬件处于拾取(或“选择”)模式;2. 让硬件在拾取模式下,重新绘制场景,只不过不加入颜色;3. 绘制场景时,为需要做拾取的对象命名;4. 根据鼠标位置加上一定的误差范围,硬件返回选择的结果;5. 让硬件重新回到绘图(“渲染”)模式。设置首先是进行设置,从一组#define和变量声明开始。PICK_TOL来定义拾取误差(按像素计),PICK_BUFFER_SIZE是拾取对象命名数组PickBuffer的大小。RenderMode记录绘图的模式。/* picking tolerance in pixels: */#define PICK_TOL 10./* how big to make the pick buffer: */#define PICK_BUFFER_SIZE 256unsigned int PickBufferPICK_BUFFER_SIZE; /* picking buffer */int RenderMode; /* GL_RENDER or GL_SELECT */InitGraphics()在这个函数中,告诉硬件使用哪个数组作拾取名字数组,这个数组多大。它必须在创建窗口后完成。/* open the window and set its title: */glutInitWindowSize( INIT_WINDOW_SIZE, INIT_WINDOW_SIZE );glutInitWindowPosition( WIN_LEFT, WIN_BOTTOM );GrWindow = glutCreateWindow( WINDOWTITLE );glutSetWindowTitle( WINDOWTITLE );. . ./* setup the picking buffer: */glSelectBuffer( PICK_BUFFER_SIZE, PickBuffer );拾取对象命名为需要做拾取的对象进行命名,名字实际上是32位无符号整数。glLoadName( 0 );glutWireSphere( 1.0, 15, 15 );glLoadName( 1 );glutWireCube( 1.5 );glLoadName( 2 );glutWireCone( 1.0, 1.5, 20, 20 );glLoadName( 3 );glutWireTorus( 0.5, 0.75, 20, 20 );有一点,需要注意,函数glLoadName()不可置于glBegin()与glEnd()之间。下面的代码就是犯了这种错误:glBegin( GL_TRIANGLES );for( i = 0; i NTRIS; i+ )glLoadName( i );glVertex3f( Trisi.x0, Trisi,y0, Trisi.z0 );glVertex3f( Trisi.x1, Trisi,y1, Trisi.z1 );glVertex3f( Trisi.x2, Trisi,y2, Trisi.z2 );glEnd();应改作:for( i = 0; i NTRIS; i+ )glLoadName( i );glBegin( GL_TRIANGLES );glVertex3f( Trisi.x0, Trisi,y0, Trisi.z0 );glVertex3f( Trisi.x1, Trisi,y1, Trisi.z1 );glVertex3f( Trisi.x2, Trisi,y2, Trisi.z2 );glEnd();拾取名字的构成可以不是线性的,可形成层次结构的多重名字。因为拾取名字实际上是存放在栈中,多重名字结构可用如下形式生成:glLoadName( JAGUAR );glPushName( BODY );glCallList( JagBodyList );glPopName();glPushName( FRONT_LEFT_TIRE );glPushMatrix();glTranslatef( ?, ?, ? );glCallList( TireList );glPopMatrix();glPopName();glPushName( FRONT_RIGHT_TIRE );glPushMatrix();glTranslatef( ?, ?, ? );glCallList( TireList );glPopMatrix();glPopName();glLoadName( YUGO );glPushName( BODY );glCallList( YugoBodyList );拾取上面的对象将会返回两个名字,告诉你拾取了哪辆车,以及该辆车的哪个部件。如果要对象End()()e()()进行绘图,需要将绘图模式从拾取模式转成渲染模式。因此在,函数Reset()中:RenderMode = GL_RENDER;一量鼠标按钮触发了拾取,则进行如下一系列动作:1. 设置拾取模式(GL_SELECT);2. 调用Display()函数进行重绘;3. 设置回渲染模式(GL_RENDER);4. 检视拾取名字数组。MouseButton该函数执行前述的过程。if( ( ActiveButton & LEFT ) & ( status = GLUT_DOWN ) )RenderMode = GL_SELECT;glRenderMode( GL_SELECT );Display();RenderMode = GL_RENDER;Nhits = glRenderMode( GL_RENDER );#ifdef BUG_KLUDGE/针对TNT2图形卡的拾取bug,需拾取两次if( Nhits = 0 )RenderMode = GL_SELECT;glRenderMode( GL_SELECT );Display();RenderMode = GL_RENDER;Nhits = glRenderMode( GL_RENDER );#endifif( Debug )fprintf( stderr, # pick hits = %dn, Nhits );for( i = 0, index = 0; i Nhits; i+ )nitems = PickBufferindex+;zmin = PickBufferindex+;zmax = PickBufferindex+;if( Debug )fprintf( stderr,Hit # %2d: found %2d items on the name stackn,i, nitems );fprintf( stderr, tZmin = 0x%0x, Zmax = 0x%0xn,zmin, zmax );for( j = 0; j nitems; j+ )item = PickBufferindex+;if( Debug )fprintf( stderr, t%2d: %6dn, j, item );ActiveButton &= LEFT;glutSetWindow( GrWindow );glutPostRedisplay();if( Nhits = 0 )/* didnt pick anything */* use the left mouse for rotation or scaling: */. . .拾取发生生,拾取数组有什么变化?拾取数组以下图形式组织:zmin和zmax为internal无符号整数,表示哪个对象最近。zmin或zmax的较小值对应的对象要近于较大值对应的对象。Display()在Display()函数中,需要根据拾取和渲染的需要来要调整:int viewport4; /* place to retrieve the viewport numbers */ dx = glutGet( GLUT_WINDOW_WIDTH );dy = glutGet( GLUT_WINDOW_HEIGHT ); glMatrixMode( GL_PROJECTION );glLoadIdentity();if( RenderMode = GL_SELECT )viewport0 = xl;viewport1 = yb;viewport2 = d;viewport3 = d;gluPickMatrix( (double)Xmouse, (double)(dy - Ymouse),PICK_TOL, PICK_TOL, viewport ); /* init the picking buffer: */if( RenderMode = GL_SELECT )glInitNames();glPushName( 0xffffffff ); /* a strange value */* draw the objects: */* possibly draw the axes: */if( AxesOnOff = ON & RenderMode = GL_RENDER )glCallList( AxesList );/* swap the double-buffered framebuffers: */if( RenderMode = GL_RENDER )glutSwapBuffers();这一段唯一需要额外注意的地方是蓝色字体的部分。它检视拾取的视区大小和位置,拾取误差,调整投影矩阵使拾取盒所在区域占据整个窗口(原文如此,费解)。硬件接下来判断是否有对象穿过拾取盒空间(利用clip算法),如果有则拾取成功。注意:gluPickMatrix()一行在程序中所有变换之前,这是因为我们希望它所定义的变换在所有变换完成之后进行。拾取技巧1. 不要将拾取时间浪费在你不会做拾取的对象上,例如if( AxesOnOff = ON & RenderMode = GL_RENDER )glCallList( AxesList );因为轴不会用于拾取,就不必要在拾取模式下绘制。2. 不要对光栅化字符作拾取,不会起作用的。因此在绘制场景时,建议这样写:if( RenderMode = GL_RENDER )glDisable( GL_DEPTH_TEST );glMatrixMode( GL_PROJECTION );glLoadIdentity();gluOrtho2D( 0., 100., 0., 100. );glMatrixMode( GL_MODELVIEW );glLoadIdentity();glColor3f( 1., 1., 1. );sprintf( str, Nhots = %d, Nhits );DoRasterString( 1., 1., 0., str );3. 你在拾取模式

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论