opengl采用一种比较复杂的方式来实现拾取操作,即选择模式。选择模式是一种绘制模式,它的基本思想是在一次拾取操作时,系统会根据拾取操作的参数(如鼠标位置)生成一个特定视景体,然后又系统重新绘制场景中的所有图元,但这些图元并不会绘制到颜色缓存中,系统跟踪有哪些图元绘制到了这个特定的视景体中,并将这些对象的标识符保存到拾取缓冲区数组中。

步骤:

1、设置拾取缓冲区:void glSelectBuffer(GLsizei n,GLunint *buff);

2、进入选择模式:指定选择模式采用函数:GLint glRenderMode(GLenum mode);

3、名字堆栈操作:

初始化名字堆栈:void glInitNames();

压栈:void glPushNmae(GLuint name);

弹栈:void glLoadName(GLuint name);

出栈:void glPopNmae();

4、设置合适的变换过程:矩形拾取窗口来实现拾取:gluPickMatrix(xPick,yPick,widthPick,heightPick,*vp);

5、位每个图元分配名字并绘制

6、切换回渲染模式

7、分析选择缓冲区中的数据

程序如下:

#include"gl/glut.h"
#include"stdio.h"
#include"iostream"
using namespace std;
const GLint pickSize=;//拾取缓冲区的大小
int winWidth=,winHeight=;
void Initial(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
}
//按照指定的模式绘制矩形对象
void DrawRect(GLenum mode)
{
if(mode==GL_SELECT)glPushName();//将名字1压入堆栈
glColor3f(1.0f,0.0f,0.0f);
glRectf(60.0f,50.0f,150.0f,150.0f);//绘制红色矩形
if(mode==GL_SELECT)glPushName();//将名字2压入堆栈
glColor3f(0.0f,1.0f,0.0f);
glRectf(230.0f,50.0f,330.0f,150.0f);//绘制绿色矩形
if(mode==GL_SELECT)glPushName();//将名字3压入堆栈
glColor3f(0.0f,0.0f,1.0f);
glRectf(140.0f,140.0f,240.0f,240.0f);//绘制蓝色矩形
}
void ProcessPicks(GLint nPicks,GLuint pickBuffer[])
{
GLint i;
GLuint name,*ptr;
printf("选中的数目为%d个\n",nPicks);
ptr=pickBuffer;
for(i=;i<nPicks;i++)
{
name=*ptr;//选中图元在堆栈中的位置
ptr+=;//跳过名字和深度信息
ptr+=name-;//根据位置信息获得选中的图元名字
if(*ptr==)printf("你选择了红色图元\n");
if(*ptr==)printf("你选择了绿色图元\n");
if(*ptr==)printf("你选择了蓝色图元\n");
ptr++;
}
printf("\n\n");
} void ChangeSize(int w,int h)
{
winWidth=w;
winHeight=h;
glViewport(,,w,h);//指定视区,即指定窗口中用于图形显示的区域
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRect(GL_RENDER);//用渲染模式绘制图形
glFlush();
}
void MousePlot(GLint button,GLint action,GLint xMouse,GLint yMouse)
{
GLuint pickBuffer[pickSize];
GLint nPicks,vp[];
if(button==GLUT_LEFT_BUTTON&&action==GLUT_DOWN)
{
glSelectBuffer(pickSize,pickBuffer);//设置选择缓冲区
glRenderMode(GL_SELECT);//激活选择模式
glInitNames();//初始化名字堆栈
glMatrixMode(GL_PROJECTION);
glPushMatrix();//将当前的投影矩阵复制一个并压入堆栈
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT,vp);//获得当前窗口显示区域的参数
//定义一个10*10的选择区域
gluPickMatrix(GLdouble(xMouse),GLdouble(vp[]-yMouse),10.0,10.0,vp);
gluOrtho2D(0.0,winWidth,0.0,winHeight);
DrawRect(GL_SELECT);//用选择模式绘制图形
//恢复投影变换
glMatrixMode(GL_PROJECTION);
glPopMatrix();//将投影矩阵堆栈中的栈顶元素删除
glFlush();
//获得选择集并输出
nPicks=glRenderMode(GL_RENDER);
ProcessPicks(nPicks,pickBuffer);//输出选择结果
glutPostRedisplay(); }
}
int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(,);
glutInitWindowPosition(,);
glutCreateWindow("拾取操作");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize);
glutMouseFunc(MousePlot);
Initial();
glutMainLoop();
return ;
}
05-08 14:57