PDA

View Full Version : object selection problem - please help



c0de
02-16-2010, 11:22 PM
Hello. I have a problem with object selection in a scene. I read the other posts regarding this kind of problem but I couldn't find a clear solution.
In my application the objects are drawn in lists and the color is set with glMaterial. I have 8 lists and each of them contain 2-to-4 different objects (different colors). I'm working with Qt and initializeGL() function builds the lists. Because the objects are linked serially the paintGL() looks like this (truncated for 4 objects):



void GLWidget::paintGL()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glCallList(baseObj);
glPushMatrix();
glTranslatef(0.0,0.0,410.0);
glRotatef(z1,0,0,1);
glCallList(link1Obj);
glPushMatrix();
glTranslatef(150.0,-130.0,0);
glRotatef(z2,0,1,0);
glCallList(link2Obj);
glPushMatrix();
glRotatef(z3,0,1,0);
glCallList(link3Obj);
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
}

From the other posts I understood that selecting objects based on the back buffer color would be recommended (if I'm not wrong). The problem is that I dont know if this is possible when using glMaterials.
Is there a way to do color based selection when using materials?
Are there other ways to pick/select objects (independent of the GPU model... I have an ATI mobility 2600) considering that my objects are quite complicated in shape?
Thank you.

P.S: this is my initializeGL:


void GLWidget::initializeGL()
{
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_DEPTH_TEST);
glEnable (GL_NORMALIZE);
glEnable (GL_LIGHTING);
trajectoryObj = makeTrajectory(1);
floorObj = makeFloor(1);
dummyObj = makeDummy(1);
axesObj = makeAxes(1);
baseObj = makeBase(1);
link1Obj = makeLink1(1);
link2Obj = makeLink2(1);
link3Obj = makeLink3(1);
link4Obj = makeLink4(1);
link5Obj = makeLink5(1);
link6Obj = makeLink6(1);
fingerObj = makeFinger(1);

glEnable (GL_LIGHT0);
glEnable (GL_LIGHT1);
glEnable (GL_LIGHT2);

}

zweifel
02-17-2010, 09:11 AM
I use myself the classic OpenGL solution and just draw the with the GL_SELECT mode set by glRenderMode().

Full explanation here http://glprogramming.com/red/chapter13.html

I do not know if this is the best approach, but I think either way it must render the scene 2 times.

c0de
02-18-2010, 12:07 AM
Thank you.
I tried selection using GL_SELECT but still having some problems. After the left click the whole scene is a mess... looks like its zoomed with a very high factor and also rotated. I cant bring back the objects to the screen.
This is what I used for selection (on left click):


if (event->buttons() & Qt::LeftButton) {

GLuint selectBuf[512];
GLint hits;
GLint viewport[4];
glGetIntegerv (GL_VIEWPORT, viewport);

glSelectBuffer (512, selectBuf);
glRenderMode (GL_SELECT);
rendermode = GL_SELECT;
glInitNames();
glPushName(0);
glMatrixMode (GL_PROJECTION); // <-- this causes a problem
glLoadIdentity ();
gluPickMatrix ((GLdouble) event->x(), (GLdouble) (viewport[3] - event->y()),5.0, 5.0, viewport);
glOrtho(-3200, +3200, +2080, -2080, -8000.0,8000.0);
selectmode(); //draw the scene
glMatrixMode (GL_MODELVIEW);
hits = glRenderMode (GL_RENDER);
rendermode = GL_RENDER;
processHits (hits, selectBuf);
}

I took glOrtho from my redraw function which is:


void GLWidget::resizeGL(int width, int height)
{
glViewport(0,0,800,520);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-3200, +3200, +2080, -2080, -8000.0,8000.0);
glMatrixMode(GL_MODELVIEW);
}

if I comment the line glMatrixMode (GL_PROJECTION) the scene is properly drawn but the select returns the whole list of objects (always the 1st object is the one with id=0).
My processHits function looks like this:


void GLWidget::processHits (GLint hits, GLuint buffer[])
{
unsigned int i, j;
GLuint names, *ptr;
QString thetext;
QMessageBox msgBox;
thetext = QString("hits %1").arg(hits);
msgBox.setText(thetext);
msgBox.exec();
ptr = (GLuint *) buffer;
for (i = 0; i < hits; i++) { /* for each hit */
names = *ptr;
ptr++;
ptr++;
ptr++;
for (j = 0; j < names; j++) {
thetext = QString("Name ID %1\n").arg(*ptr);
msgBox.setText(thetext);
msgBox.exec();
ptr++;
}
}
}


... and the selectmode function (which draws the scene in select mode):


void GLWidget::selectmode()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |GL_STENCIL_BUFFER_BIT);
// glLoadIdentity();
glClearColor(0.0f,0.2f,0.2f,0.0f);
glDisable(GL_LIGHTING);
//scale the scene
glScalef(scale+1,scale+1,scale+1);
//move scene
glTranslatef(xmove,ymove+350,zmove);
//rotate scene
glRotatef(60.0, 1.0, 0.0, 0.0);
glRotatef(30.0, 0.0, 0.0, 1.0);
glRotatef(xRot+90, 0.0, 0.0, 1.0);
glRotatef(yRot, 0.0, 1.0, 0.0);
glRotatef(zRot, 1.0, 0.0, 0.0);
//draw objects
glPushMatrix();
glRotatef(90, 0.0, 0.0, 1.0);
glTranslatef(0.0,0.0,410.0);
if(showTrajectory != 0 )
glCallList(trajectoryObj);
glPopMatrix();
glCallList(floorObj);
glPushMatrix();
if(displayLink.at(0) != 0)
{
glLoadName(1);
glCallList(baseObj);
}
if(displayFrame.at(0) != 0)
{
glPushMatrix();
glRotatef(180, 0.0, 0.0, 1.0);
glCallList(axesObj);
glPopMatrix();
}
glPushMatrix();
glTranslatef(0.0,0.0,410.0);
glRotatef(z1,0,0,1);
if(displayLink.at(1) != 0)
{
glLoadName(2);
glCallList(link1Obj);
}
if(displayFrame.at(1) != 0)
{
glPushMatrix();
glRotatef(180, 0.0, 0.0, 1.0);
glCallList(axesObj);
glPopMatrix();
}
glPushMatrix();
glTranslatef(150.0,-130.0,0);
glRotatef(90,0,1,0);
glRotatef(z2,0,1,0);
if(displayFrame.at(2) != 0)
{
glPushMatrix();
glRotatef(-90,0,1,0);
glTranslatef(0.0,130.0,0);
glRotatef(-90, 1.0, 0.0, 0.0);
glRotatef(-180, 0.0, 1.0, 0.0);
glRotatef(90, 0.0, 0.0, 1.0);
glCallList(axesObj);
glPopMatrix();
}
if(displayLink.at(2) != 0)
{
glLoadName(3);
glCallList(link2Obj);
}
glPushMatrix();
glTranslatef(-360.0,75.0,0.0);
glRotatef(z3,0,1,0);
if(displayFrame.at(3) != 0)
{
glPushMatrix();
glTranslatef(0.0, 55.0,0);
glRotatef(90, 1.0, 0.0, 0.0);
glCallList(axesObj);
glPopMatrix();
}
if(displayLink.at(3) != 0)
{
glCallList(link3Obj);
}
glPushMatrix();
glTranslatef(-100.0,75.0, 135);
glRotatef(z4,0,0,1);
if(displayLink.at(4) != 0)
glCallList(link4Obj);
if(displayFrame.at(4) != 0)
glCallList(axesObj);
glPushMatrix();
glTranslatef(0.0,0.0,295);
glRotatef(-z5,0,1,0);
if(displayLink.at(5) != 0)
glCallList(link5Obj);
if(displayFrame.at(5) != 0)
{
glPushMatrix();
glRotatef(90, 1.0, 0.0, 0.0);
glCallList(axesObj);
glPopMatrix();
}
glPushMatrix();
glTranslatef(0.0,0.0,100);
glRotatef(z6,0,0,1);
if(displayLink.at(6) != 0)
glCallList(link6Obj);
if(displayFrame.at(6) != 0)
glCallList(axesObj);
glPushMatrix();
glTranslatef(0.0,0.0,50);
glPushMatrix();
glPushMatrix();
glTranslatef(0.0,0.0,47.5);
glLoadName(4);
glCallList(dummyObj);
if(displayFrame.at(7) != 0)
{
glCallList(axesObj);
}
glPopMatrix();
if(gripper_status == TRUE)
gripper_stroke=27.5;
else
gripper_stroke=17.5;
glTranslatef(0.0,gripper_stroke,0.0);
if(displayLink.at(7) != 0)
glCallList(fingerObj);
glTranslatef(0.0,-gripper_stroke,0.0);
glRotatef(180,0,0,1);
glTranslatef(0.0,gripper_stroke,0.0);
if(displayLink.at(7) != 0)
glCallList(fingerObj);
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
}

I'm sure I'm missing something but I cant figure out what.
I appreciate any help. Thanks

c0de
02-18-2010, 02:47 AM
I think I solved the problem. Seems that the projection matrix was manipulated wrong. These are the modifications I made:
In mouse event:


if (event->buttons() & Qt::LeftButton) {

GLint viewport[4];
GLfloat proj[16];
GLuint selectBuf[512];
int hits;
glGetIntegerv(GL_VIEWPORT,viewport);
glGetFloatv(GL_PROJECTION_MATRIX, proj);//save the projection matrix

glSelectBuffer(512,selectBuf);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPickMatrix(event->x(),viewport[3]-event->y(),1,1,viewport);
glMultMatrixf(proj);// projection
glMatrixMode(GL_MODELVIEW);
selectmode();
glMatrixMode(GL_PROJECTION);
glFlush();
hits = glRenderMode(GL_RENDER);
resizeGL(0,0);
if (hits != 0)
processHits(hits,selectBuf);
}

Also in the selectmode function I uncommented glLoadIdentity and loaded name 0 at the beginning. Since the objects are linked and after each list call the matrix is pushed, I used glPushName/PopName for each object. processHits is looking now only in the last hit for the last object. For example, if I click object no. 5 the names stack will contain the names 0,1,2,3,4,5...
I'm not sure if this is the best solution, but at least it works. If anyone can give me better ideas/advices I appreciate it.
Thanks