您的位置:首页 > 编程语言

《基于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;

}


运行结果:




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: