OPENGL 鼠标拾取基础
拾取模式
基本的思路如下,这里的选择模式是OpenGL API 提供的特别绘制模式
* 得到鼠标点击位置的窗口坐标
* 进入选择模式
* 重新定义观察体
* 绘制场景
* 退出选择模式
名字堆栈
为了识别绘制的物体,必须对场景中的相关物体进行重命名。当进入到选择模式的时候,物体的名字被收集到一个数组里,对于未命名的物体,则只有深度信息被收集。
我们绘制一个雪人先,6*6 排布的36个雪人 头和身子分开绘制,如何制定名字堆栈?
#define BODY
#define HEAD
...
void renderInSelectionMode()
{
glInitNames();
glPushName(BODY);
drawBody();
glPushName();
drawHead();
drawEyes();
glPopName();
drawGround();
}
函数详解与补充:
1. void glInitNames(); 创建名字堆栈并初始化,必须在其他所有名字操作前被调用
2. void glPushname(GLuint name); 压入名字到堆栈 至少能容纳64个,溢出报错:GL_STACK_OVERFLOW
3. void glPopName(); 栈顶去掉名字 空栈中执行此操作:GL_STACK_UNDER_FLOW
4. void glLoadName(GLuint name); 等价于glPopName()和glPushName(name) 连用
-注意-
* 以上函数在非选择模式将被忽略
* 不能再glBegin 和 glEnd 间放置这些函数
* 支持多重命名和层次命名
如:
for(int i=-3;i<3;i++)
glPushName(i);
for(int j=-3;j<3;j++){
glPushName(j);
glTranslate(i*10.0,0.0,j*10.0);
glCallList(snowmanDL);
glPopName();
glPopMatrix();
}
glPopName();
}
这样当鼠标击中雪人时,就会得到两个名字,行数和列数
选择模式
现在我们介绍了Opengl的命名机制,下面进入为拾取设计的选择模式
下面代码给出了进入选择模式和开始拾取的所有操作,稍作修改你可以把上面代码用到自己的应用程序,但只在进入绘制模式时,在任何图形元素被绘制之前
#define BUFSIZE 512
GLuint selectBuf[BUFSIZE];
...
void startPicking(int cursorX,int cuesorY)
{
GL int viewport[4];
glSelectBuffer(BUFSIZE,selectBuf);
glRenderMode(GL_SELECT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glGetIntegerv(GL_VIEWPOINT,viewport);
glPickMatrix(cursorX,viewport[3]-cursorY,5,5,viewport);
gluPerspective(60,1,0.1,1000);
glMatrixMode(GL_MODELVIEW);
glInitName();
}
- 先告诉OpenGL 击中的保存地点:
void glSelectBuffer(GLsizei size,GLuint*buffer);
- 用下面函数进入选择模式
void glRenderMode(GLeum mode);
参数: mode 使用GL-SELECT GL_RENDER来在选择模式和正常绘制模式之间做切换 - 应用程序需要重新定义观察体,使得只有鼠标邻近的位置被绘制,为了实现这一点,需要将矩阵模式设置为CL-PROJECTION ,然后将投影矩阵变为单位矩阵,
- 定义观察体。使得只有光标附件的小区域被绘制
void gluPickMatrix(GL double x,GLdouble y,GLdouble width,GLdouble height,GLint viewport[4]);
参数:x,y 定义光标位置,注意opengl的窗口原点坐标在左下角 而操作系统一般在左上角,所以减去y width height 当前视区的尺寸 viewport 当前视区
所以在调取当前函数前,先用glGetIntegerv() 获取当前视区尺寸 - 设置投影(和正常绘制一样流程)
- 切换到GL_MODELVIEW,并初始化名字堆栈,开始绘制
glRenderMode(GL_RENDE);//返回正常模式,这个函数将返回在选择模式下创建击中的个数,在这之后应用程序才可以开始处理缓存,由于在进入选择模式之前已经push了矩阵,现在只需要pop一下,进行恢复
void stopPicking(){
int hits;
//重新载入原来的投影矩阵
glMatrixMode(GL_PROJECTION);
glPopMatrix;
glMatrixMode(GL_MODEVIEW);
glFlush();
//返回法线绘制模型
hits=glRenderMode(GL_RENDER);
//如果有hit执行它们
if(hits!=0)
prosessHit(hits,sesectBuf);
}