65.9K
CodeProject 正在变化。 阅读更多。
Home

OpenGL 场景中的鼠标选择

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (18投票s)

2002年10月26日

CPOL

3分钟阅读

viewsIcon

253564

downloadIcon

12548

另一种在OpenGL场景中使用鼠标选择对象的方法。

Sample Image - OpenGLMouseSellection.jpg

引言

本文介绍了如何在OpenGL场景中实现鼠标选择,以及在MDI应用程序中移动、旋转和缩放OpenGL场景和进行消毒。该项目使用MFC模板类来保存对象原语。有几种方法可以在OpenGL场景中实现选择。以下是一个简短的描述。

选择

选择方法是OpenGL的机制,它的工作方式如下。将场景绘制到帧缓冲区,然后进入选择模式并重新绘制场景。当您处于选择模式时,帧缓冲区的内容不会改变,直到您退出选择模式。当您退出选择模式时,OpenGL会返回一个与视锥体相交的原语列表。选择命中是由原语和视锥体之间的交集引起的。原语列表实际上是作为整数数组返回的。您可以通过在选择模式下发出原语绘制命令时将名称加载到名称堆栈上来构造名称堆栈。因此,当返回名称列表时,您可以使用它来确定用户可能在屏幕上选择了哪些原语。

反馈

反馈与选择类似,一旦您处于任何一种模式,就不会产生像素,屏幕也会被冻结。不会发生绘图;相反,关于原本将被渲染的原语的信息被发送回应用程序。选择和反馈模式之间的关键区别在于发送回什么信息。在反馈模式下,关于转换后的原语的信息被发送回一个浮点值数组。发送回反馈数组的值包括指定什么类型的原语(点、线、多边形、图像或位图)已被处理和转换的标记,以及该原语的顶点、颜色或其他数据。

拾取射线

另一种方法包括通过鼠标位置发射拾取射线,并测试与当前显示对象的交点。OpenGL不包含任何射线相交的函数。要生成拾取射线,您需要OpenGL矩阵变换,以及一些线性代数的知识。

实现

我为鼠标选择实现的方法涉及将对象(原语)的一小部分区域投影到屏幕上并测试鼠标单击。下面的代码演示了如何将对象点投影到屏幕上。

 
//Needs to retrieve OpenGL transformation matrices before projection
glGetIntegerv(GL_VIEWPORT, m_spheres->viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, m_spheres->modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, m_spheres->projMatrix);

//Projection 
gluProject(m_spheres->m_xc,m_spheres->m_yc,
        m_spheres->m_zc,m_spheres->modelMatrix, 
        m_spheres->projMatrix,m_spheres->viewport,
        &m_spheres->winx,&y,&m_spheres->winz);
m_spheres->winy=m_spheres->viewport[3] - (GLint) y - 1;

每个形状对象都包含投影点和矩形。当您想要选择形状时,请使用LButtonDown消息处理程序并测试其在矩形中的点。下面的代码显示了Sphere对象的测试。

void CMyView::OnLButtonDown(UINT nFlags, CPoint point) 
{
    m_LeftButtonDown = TRUE;
    m_LeftDownPos = point;
    SetCapture();

    CMyDoc* pDoc = (CMyDoc*)GetDocument();
    ASSERT(pDoc);
    CTypedPtrList<CObList,CSphere*>& sphereList =pDoc->m_SphereList;
    POSITION pos = sphereList.GetHeadPosition();
    while (pos != NULL)
    {
        CSphere* spheres = sphereList.GetNext(pos);
        spheres->m_Select=FALSE;
        if(spheres->GetRect().PtInRect(point))
        {
            m_sph=spheres;
            m_sph->m_Select=TRUE;
        }
    }

    Invalidate();
    CView::OnLButtonDown(nFlags, point);
}

摘要

实现的问题是对象的可投影区域有多大。如果将投影区域设置得太大,则可能会合并两个不同的区域。如果投影区域太小,则很难用鼠标拾取它。

参考文献

  1. OpenGL编程指南 OpenGL学习官方指南,1.1版本
  2. Open GL Super Bible (出版社: Macmillan Computer Publishing) 作者: Waite group Press ISBN: 1571690735 出版日期: 08/01/96
© . All rights reserved.