指定了一个具有n个元素的整形数组buffer作为拾取缓冲区。对于每个命中消息,都会在拾取缓冲区数组中添加一条记录,每条记录包含了以下的信息:
其中,参数mode值可以为GL_RENDER(默认值)、GL_SELECT或GL_FEEDBACK,分别指定应用程序处于渲染模式、选择模式和反馈模式。应用程序一直处于当前模式下,直到调用本函数改变为其他模式为止。
其中参数xPick和yPick指定相对于显示区域左下角的拾取窗口中心的双精度浮点屏幕坐标值。当使用鼠标进行选择操作时,xPick和yPick由鼠标位置确定,但要注意y坐标的反转。参数widthPick和heightPick指定拾取窗口的双精度浮点宽高值。参数vp指定了一个包含当前显示区域的坐标位置和尺寸等参数的整型数组,该参数可以通过函数glGetIntegerv来获得。这个函数可以设置一个用于拾取操作的观察空间。
程序3-3OpenGL实现的拾取操作的例子
#include <gl/glut.h>
#include "stdio.h"
const GLint pickSize = 32;
int winWidth = 400, winHeight = 300;
voidInitial(void)
{
glClearColor(1.0f, 1.0f, 1.0f,1.0f);
}
voidDrawRect(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);
}
voidProcessPicks(GLint nPicks, GLuint pickBuffer[])
{
GLint i;
GLuint name, *ptr;
printf("选中的数目为%d个\n",nPicks);
ptr=pickBuffer;
for(i=0;i<nPicks; i++){
name=*ptr; //选中图元在堆栈中的位置
ptr+=3; //跳过名字和深度信息
ptr+=name-1; //根据位置信息获得选中的图元名字
if(*ptr==1) printf("你选择了红色图元\n");
if(*ptr==2) printf("你选择了绿色图元\n");
if(*ptr==3) printf("你选择了蓝色图元\n");
ptr++;
}
printf("\n\n");
}
voidChangeSize(int w, int h)
{
winWidth = w;
winHeight = h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
voidDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
DrawRect(GL_RENDER);
glFlush();
}
voidMousePlot(GLint button, GLint action, GLint xMouse, GLintyMouse)
{
GLuint pickBuffer[pickSize];
GLint nPicks, vp[4];
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[3]-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();
}
}
intmain(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE |GLUT_RGB);
glutInitWindowSize(400,300);
glutInitWindowPosition(100,100);
glutCreateWindow("拾取操作");
glutDisplayFunc(Display);
glutReshapeFunc(ChangeSize);
glutMouseFunc(MousePlot);
Initial();
glutMainLoop();
return 0;
}