《基于MFC的OpenGL编程》Part 14 Selection

来源:互联网 发布:怎么在淘宝搜岛国片 编辑:程序博客网 时间:2024/05/22 03:50

《基于MFC的OpenGL编程》Part 14 Selection

    原文链接

     资源链接:

Selection

Selection is a powerful feature of OpenGL that allows you click at some position of the OpenGL window using the mouse and determine which of your objects lie beneath it. The act of selecting a specific object is called Picking. With OpenGL's selection feature, we can specify a viewing volume and determine which objects fall within that viewing volume. A powerful utility function, gluPickMatrix, produces a matrix which can be used to create a smaller viewing volume placed beneath the mouse cursor. Then we use selection to test this viewing volume to see which objects are contained by it.

Selection is actually a rendering mode, but in this mode no pisels are actually copied onto the frame buffer. Instead, primitives drawn within the viewing volume produce hit records in a selection buffer. We must set up this selection buffer in advance and name the primitives or groups of primitives so that they can be identified in the selection buffer.We can then parse the buffer to determine which objects intersected the viewing volume.

Naming Primitives

We have to name a group of primitives such as one describing a cube or a cylinder etc in order to identify them. These names are nothing but integers such as for display list names. The names list is maintained on the named stack. After we initialize the name stack we can push names on the stack or simply replace the name currently on the top of the stack. When a hit occurs during selection, all the names on the stack are copied onto the selection buffer.

1、CMy2OpenGLView类中加入一个变量,用来表示宽高比:

GLdouble m_aspectRatio;//width/height ratio

2OnSize函数修改如下,主要将aspect_ratio换成了成员变量m_aspectRatio:

void CMy2OpenGLView::OnSize(UINT nType, int cx, int cy) {CView::OnSize(nType, cx, cy);// TODO: Add your message handler code here//GLdouble aspect_ratio; // width/height ratio        if ( 0 >= cx || 0 >= cy )    {        return;    }    // select the full client area    ::glViewport(0, 0, cx, cy);    // compute the aspect ratio    // this will keep all dimension scales equal    m_aspectRatio = (GLdouble)cx/(GLdouble)cy;    // select the projection matrix and clear it    ::glMatrixMode(GL_PROJECTION);    ::glLoadIdentity();    // select the viewing volume//gluOrtho2D(60.0,100.0*aspect_ratio,0.0,100.0); //gluOrtho2D(-10.0,10.0,-10.0,10.0);//画三个点时,一点要设置成这样,不然编译出来显示不了图形//主要是这个函数,注意参数设置,不然看不到效果的    gluPerspective(30.0f, m_aspectRatio, 3.0f, 10.0f);        // switch back to the modelview matrix and clear it    ::glMatrixMode(GL_MODELVIEW);    ::glLoadIdentity();//::glDrawBuffer(GL_BACK);}

3、绘制函数如下:

注意:函数中注释的代码不加也可以选中对象,但是查资料看到大多数都有加上,建议加上

void CMy2OpenGLView::RenderSceneSelect(){//绘制函数//glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);// glMatrixMode(GL_MODELVIEW);// glLoadIdentity();// glPushMatrix();      glTranslatef(0.0f,0.0f,-5.0f);      glRotatef(m_xRot,1.0f,0.0f,0.0f);      glRotatef(m_yRot,0.0f,1.0f,0.0f);      glInitNames();//初始化堆栈名称      glPushName(0);//push一次才有栈顶,才能有后面的glLoadName()//绘制球体    glPushMatrix();   glColor3f(0.0f,0.0f,1.0f);           glTranslatef(-2.0f,0.0f,0.0f);           glLoadName(1);           glutSolidSphere(1.0f,20,20);   glPopMatrix();//绘制立方体   glPushMatrix();   glColor3f(0.5f,0.0f,0.5f);              glLoadName(2);              glTranslatef(2.0f,0.0f,0.0f);              glutSolidCube(1.0f);       glPopMatrix();glPopMatrix();}

4、加入对鼠标左键选择物体的处理:

注意:RenderSceneSelect()是我们的画图函数,改了名字后一定要和自己的文件名字一致,否则不会出现选中后弹出          MessageBox的消息框。

void CMy2OpenGLView::ProcessSelection(CPoint point){      int xPos = point.x ;      int yPos = point.y ;      GLuint selectBuff[64];      GLint hits, viewport[4];      glSelectBuffer(64, selectBuff);      glGetIntegerv(GL_VIEWPORT, viewport);      glMatrixMode(GL_PROJECTION);     glPushMatrix();      glRenderMode(GL_SELECT);      glLoadIdentity();      gluPickMatrix(xPos, viewport[3] - yPos, 2,2, viewport);        gluPerspective(45.0f, m_aspectRatio, .01f, 200.0f);  //改RenderScene()为RenderSceneSelect()名字的一定要注意了,  //很可能就是这句导致你选择物体后没反应  ///////******************************************/////////      RenderSceneSelect();  ///////******************************************/////////      hits = glRenderMode(GL_RENDER);        if(hits==1)    ProcessObject(selectBuff);        glMatrixMode(GL_PROJECTION);       glPopMatrix();        glMatrixMode(GL_MODELVIEW);}void CMy2OpenGLView::ProcessObject(GLuint *pSelectBuff){      int id = pSelectBuff[3];      if(id==1)  MessageBox("You clicked on Sphere");        if(id==2)             MessageBox("You clicked on Cube");}void CMy2OpenGLView::OnRButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultProcessSelection(point);CView::OnRButtonDown(nFlags, point);}

5、修改OnDraw()函数,为了效果更好,我把RenderScene()和RenderScene3D()注释掉了,加上RenderSceneSelect()函数:

void CMy2OpenGLView::OnDraw(CDC* pDC){CMy2OpenGLDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data herem_ElapsedTime = ::timeGetTime(); // get current time if(ElapsedTimeinMSSinceLastRender()<30)return ;  // Clear out the color & depth buffers    ::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );::glClearColor(0.0,0.0,0.5,0.5);//此函数在InitialOpenGL函数中设置默认的背景,此处重新设置,为蓝色背景glPushMatrix();//RenderScene();  //RenderScene3D();RenderSceneSelect();glPopMatrix(); glFlush();    // Tell OpenGL to flush its pipeline    ::glFinish();    // Now Swap the buffers    ::SwapBuffers( m_pDC->GetSafeHdc() ); //SwapBuffers(pDC->m_hDC);//Perform Post Display Processing//Only update the title every 15 redraws (this is about every 1/2 second)PostRenderScene();//此函数可以让标题显示出帧速率,没必要在OnCreate()额外加那两行//the very last thing we do is save//the elapsed time,this is use with the//next elapsed time to calculate the elapsed time since a render and the frame ratem_previousElapsedTime=m_ElapsedTime;}

运行结果:
0 0
原创粉丝点击