《基于MFC的OpenGL编程》Part 14 Selection
2016-03-07 08:34
369 查看
《基于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
2、OnSize函数修改如下,主要将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 default ProcessSelection(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 here m_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 rate m_previousElapsedTime=m_ElapsedTime; }
运行结果:
相关文章推荐
- Spring 实践 -AOP
- Spring 实践 -AOP
- Spring 实践 -AOP
- C#语言基础— 数据类型及其转换
- C#语言基础— 输入与输出
- Eclipse jar打包详解
- Eclipse工程依赖
- HDU 3903 Trigonometric Function
- 四:java中传统线程同步与通信
- 创建滚动进度条的几种方法
- cloud-init源代码目录简介
- qt for 安卓
- GeekBand - C++课程
- 当技术已经产品
- 解决java compiler level does not match the version of the installed java project facet
- Struts2 中的值栈的理解
- 并发编程之线程安全性
- C++ 静态数组过大,栈溢出
- 我与小娜(27):AlphaGo围棋手的技术奥秘
- c++ 去除字符串中的空格和标点符号 (remove_if 函数的用法)