opengl中的选择基本思路:
1,获得视口信息,指定返回点击记录的数组。
2,glRenderMode(GL_SELECT)进入选择模式,
3,对名字堆栈进行初始化
4,利用gluPickMatrix构造拾取矩阵进行选择,
鼠标左键拾取cube,为了保证每次只能有一个cube被选中,MouseCB函数中对z值进行比较。保证始终z最小的cube被选择。相应的处理语句:
运行效果:
下面是整个cpp:
const int BUFSIZE = 512;
int g_iWidth = 800;
int g_iHeight = 600;
float g_fAngle = 0;
const GLfloat red[] = { 231/255.0, 36.0/255.0, 46/255.0,1.0};
const GLfloat yellow[] = { 253.0/255.0, 208.0/255.0, 0.0/255., 1.0};
class Cube
{
public:
double x,y,z;
bool selected;
Cube()
: x(0), y(0), z(0)
, selected(false)
{}
void Draw()
{
glPushMatrix();
glTranslated(x, y, z);
if (selected)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, red);
else
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, yellow);
glutSolidCube(1.0);
glPopMatrix();
}
};
Cube cube[4];
void Init();
void DrawGLScene();
void Reshape(int w, int h);
void KeyBoardCB(unsigned char key, int x, int y);
void MouseCB(int button, int state, int x, int y);
void Idle();
void PaintScreen(GLenum mode);
int main(int argc, char **argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (800, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow ("OpenGL Select Obj");
Init();
glutDisplayFunc ( DrawGLScene );
glutReshapeFunc ( Reshape );
glutMouseFunc( MouseCB );
glutKeyboardFunc( KeyBoardCB );
glutIdleFunc( Idle );
glutMainLoop ();
return 0;
}
void Init()
{
glClearColor(84/255.0, 0.0/255.0, 125.0/255.0, 0.0);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
for(int i=0; i<4; i++)
cube[i].x = i*2-3;
}
void Reshape(int Width, int Height)
{
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (GLfloat)Width/(GLfloat)Height, 1.0, 20.0);
}
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(6.0,4.0,10.0,0.0,0.0,0.0,0.0,1.0,0.0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
PaintScreen(GL_RENDER);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glutSwapBuffers();
}
void PaintScreen(GLenum mode)
{
glPushMatrix();
glRotated( g_fAngle, 0.0, 1.0, 0.0 );
for(int i=0; i<4; i++)
{
if (mode==GL_SELECT)
glLoadName(i);
cube[i].Draw();
}
glPopMatrix();
}
void Idle()
{
g_fAngle += 0.5;
if( g_fAngle >= 360 )
g_fAngle = 0;
//调用DrawGLScene函数
glutPostRedisplay();
}
void KeyBoardCB(unsigned char key, int x, int y)
{
if(key == 27)
exit(0);
}
void MouseCB(int button, int state, int mousex, int mousey)
{
if( button != GLUT_LEFT || state != GLUT_DOWN)
return;
GLuint selectBuf[BUFSIZE];
GLint hits;
GLint viewport[4];
static bool IsFirst = true;
glGetIntegerv (GL_VIEWPORT, viewport);
glSelectBuffer (BUFSIZE, selectBuf);
glRenderMode(GL_SELECT); // Enter the SELECT render mode
glInitNames();
glPushName(-1);
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
gluPickMatrix((GLdouble) mousex, (GLdouble) (viewport[3] - mousey), 5.0, 5.0, viewport);
gluPerspective(30.0, (GLfloat)g_iWidth/(GLfloat)g_iHeight, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
PaintScreen(GL_SELECT);
glPopMatrix ();
glFlush();
hits = glRenderMode (GL_RENDER);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, g_iWidth, g_iHeight);
gluPerspective(30.0, (GLfloat)g_iWidth/(GLfloat)g_iHeight, 1.0, 20.0);
if(hits)
{
int n = 0;
double minz = selectBuf[1];
for(int i=1; i<hits; i++)
{
if( selectBuf[1+i*4] < minz )
{
n = i;
minz = selectBuf[1+i*4];
}
}
//hit记录第四项为ID编号
cube[selectBuf[3+n*4]].selected = !( cube[selectBuf[3+n*4]].selected );
}
//glutPostRedisplay();
}