PDA

View Full Version : Picking Problem



gottijay
07-05-2011, 08:27 AM
Hi i have been having this problem for a while now....my program records a hit when certain areas on the scene are clicked, but does not record a hit when any of the models are clicked, and is highly inaccurate, don't know what else I can do, read probably every article on picking still cant figure out what the problem is.....please I need your ideas on what could be causing this problem
this is what my code looks like


void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW); // Modeling transformation

glLoadIdentity();
//glPushMatrix();
//glTranslatef(0.0, 0.0, -500.0);
glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);

/*
//rotate about y axis now the x axis is changed.
glRotatef(angle[0], 1, 0, 0);
glRotatef(angle[1], 0, 1 ,0 );
glRotatef(angle[1], 0, 0 ,1 );
*/
gltbMatrix();
//draw the object
drawReflector(GL_RENDER);

glPopMatrix();

glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);
gltbMatrix();
drawMast(GL_RENDER);
glPopMatrix();

glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);
gltbMatrix();
drawReceiver(GL_RENDER);
glPopMatrix();

glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);
gltbMatrix();
drawConnector(GL_RENDER);
glPopMatrix();

glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);
gltbMatrix();
drawChessPawn(GL_RENDER);
glPopMatrix();

glPushMatrix();
glTranslatef(-pan_x,-pan_y, -500.0);
gltbMatrix();
drawStand(GL_RENDER);

glPopMatrix();
glPopMatrix();



glFlush();
glutSwapBuffers();

}


void selection(int x, int y)
{
GLuint buff[512] = {0};
GLint hits, view[4];




glSelectBuffer(256, buff); //This chooses the buffer where store the values for the selection data

glGetIntegerv(GL_VIEWPORT, view); //This retrieve info about the viewport



glRenderMode(GL_SELECT); // Switching in selecton mode

glInitNames();// Clearing the name's stack

glPushName(0); //filling the stack with one element


glMatrixMode(GL_PROJECTION); // Now modify the vieving volume, restricting selection area around the cursor
glPushMatrix();
glLoadIdentity();

gluPickMatrix((GLdouble)x,(GLdouble) (view[3] - y),1.0,1.0,view);
gluPerspective(45.0f,(float)view[2]/(float)view[3],1.0,1500.0);
//gluPickMatrix((GLdouble)x,(GLdouble) (view[3] - y),1.0,1.0, view); //restrict the draw to an area around the cursor
//gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,10.0f,10000.0f);


glMatrixMode(GL_MODELVIEW); // Draw the objects onto the screen

glutSwapBuffers(); //draw only the names in the stack, and fill the array
render(GL_SELECT);
//drawReflector(GL_SELECT);



glMatrixMode(GL_PROJECTION);
glPopMatrix();

/*
this will help us get the number of objects drawed in that area
and return to render mode
*/
hits = glRenderMode(GL_RENDER);

list_hits(hits, buff); // Print a list of the objects


//selectAll(hits, buff);

glMatrixMode(GL_MODELVIEW);
}




thank you very much for your help

Aleksandar
07-05-2011, 11:22 AM
Are the projection parameters the same in both cases (DRAW and SELECT)?

Also, you should draw objects the same way in both cases. From the comment I assume that you are just setting names and draw nothing.

The third and forth parameters should not be 1. Set it to some greater value. I guess the best value is 3. It is very hard to pick a single pixel accurately.


my program records a hit when certain areas on the scene are clicked, but does not record a hit when any of the models are clicked,
What's the difference between the "certain area on the scene" and the "model"?

gottijay
07-05-2011, 11:35 PM
Thanks Aleksander for your help, really appreciated



The third and forth parameters should not be 1. Set it to some greater value. I guess the best value is 3. It is very hard to pick a single pixel accurately.

i did set them to 5 and 3 and still got the same results.


What's the difference between the "certain area on the scene" and the "model"?

what i meant was that when i click some areas(mostly lower areas of the screen) where the models are not located i get hits recorded, but when i click the areas the models are located i dont get any hits.still confuses me why it does that.

Are the projection parameters the same in both cases (DRAW and SELECT)?

Also, you should draw objects the same way in both cases. From the comment I assume that you are just setting names and draw nothing.

i'm sorry i did not quite understand what you want me to do here,when you projection parameter's you mean?, i included my drawing function, there probably might be something wrong with it, that i have not be able to see.



void render(GLenum mode)
{
int i,j;



for (i=0;i<obj_qty;i++)
{


glPushMatrix(); // We save the current matrix


if (object[i].id_texture!=-1)
{
glBindTexture(GL_TEXTURE_2D, object[i].id_texture); // We set the active texture
glEnable(GL_TEXTURE_2D); // Texture mapping ON
}
else
glDisable(GL_TEXTURE_2D); // Texture mapping OFF


if(mode==GL_SELECT) glLoadName(i);//gives the first object a name

glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
for (j=0;j<object[i].polygons_qty;j++)
{
//----------------- FIRST VERTEX -----------------
//Normal coordinates of the first vertex
glNormal3f( object[i].normal[ object[i].polygon[j].a ].x,
object[i].normal[ object[i].polygon[j].a ].y,
object[i].normal[ object[i].polygon[j].a ].z);
// Texture coordinates of the first vertex
glTexCoord2f( object[i].mapcoord[ object[i].polygon[j].a ].u,
object[i].mapcoord[ object[i].polygon[j].a ].v);
// Coordinates of the first vertex

glVertex3f( object[i].vertex[ object[i].polygon[j].a ].x,
object[i].vertex[ object[i].polygon[j].a ].y,
object[i].vertex[ object[i].polygon[j].a ].z);

//----------------- SECOND VERTEX -----------------
//Normal coordinates of the second vertex
glNormal3f( object[i].normal[ object[i].polygon[j].b ].x,
object[i].normal[ object[i].polygon[j].b ].y,
object[i].normal[ object[i].polygon[j].b ].z);
// Texture coordinates of the second vertex
glTexCoord2f( object[i].mapcoord[ object[i].polygon[j].b ].u,
object[i].mapcoord[ object[i].polygon[j].b ].v);
// Coordinates of the second vertex
glVertex3f( object[i].vertex[ object[i].polygon[j].b ].x,
object[i].vertex[ object[i].polygon[j].b ].y,
object[i].vertex[ object[i].polygon[j].b ].z);

//----------------- THIRD VERTEX -----------------
//Normal coordinates of the third vertex
glNormal3f( object[i].normal[ object[i].polygon[j].c ].x,
object[i].normal[ object[i].polygon[j].c ].y,
object[i].normal[ object[i].polygon[j].c ].z);
// Texture coordinates of the third vertex
glTexCoord2f( object[i].mapcoord[ object[i].polygon[j].c ].u,
object[i].mapcoord[ object[i].polygon[j].c ].v);
// Coordinates of the Third vertex
glVertex3f( object[i].vertex[ object[i].polygon[j].c ].x,
object[i].vertex[ object[i].polygon[j].c ].y,
object[i].vertex[ object[i].polygon[j].c ].z);

}
glEnd();

glPopMatrix(); // Restore the previous matrix
}
}

Aleksandar
07-06-2011, 10:48 AM
1. Replace glutSwapBuffers() with glFlush() in your selection function.

2. Is gluPerspective() for your drawing code is exactly the same as in picking code? In other words, is there another gluPerspective(45.0f,(float)view[2]/(float)view[3],1.0,1500.0) call somewhere else in your code?

A tip: You don't need to check if you are in SELECT mode. glLoadName() has no effects in RENDER mode.

gottijay
07-06-2011, 12:22 PM
Thank you very very much aleksandar,you just saved me a whole lot of frustration...finally got it working...very grateful..

not to sound greedy or anything could you please give me an idea of how to perform dragging on objects after selection...


thank you...so relieved

next challenge dragging

Aleksandar
07-06-2011, 01:15 PM
I'm glad I could help. :)

Well, I don't have an instant recipe for dragging. The main problem is in the fact that you are moving your cursor in 2D and you probably want to move objects in 3D. You should decide whether some particular gestures mean movement that preserves the distance from the viewer, movement along some plane, or something else.

I think the following code is just for you:
http://www.codeproject.com/KB/openGL/TranslationController.aspx

gottijay
07-11-2011, 04:44 AM
Hi Aleksandar, i'm still having difficulty with dragging objects,
the first problem is that if i click an object it drags all the objects including currently selected objects.

the second problem is that the objects dont follow the mouse movements accurately ,what i mean is that models are usually some distance away from the mouse as the mouse moves, i sometimes have to take the mouse pointer out of the screen to get them at the center.

what i did was to create a mouse class that handles mouse movements...

this is what i have


void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // This clear the background color to dark blue
glMatrixMode(GL_MODELVIEW); // Modeling transformation
glLoadIdentity(); // Initialize the model matrix as identity

glTranslatef(mouse1.GetX(), mouse1.GetY(), 0.0);
drawModel(GL_RENDER);
glFlush();
glutSwapBuffers();

}

mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON &amp;&amp; glutGetModifiers() & GLUT_ACTIVE_SHIFT)
button = GLUT_MIDDLE_BUTTON;



if(button==GLUT_LEFT_BUTTON &amp;&amp; state== GLUT_DOWN)
{
glGetIntegerv(GL_VIEWPORT,viewport);
glSelectBuffer(SIZE, selectBuf);
glRenderMode(GL_SELECT);

glInitNames();
glPushName(-1);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,0.1f,10000.0f);
//gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
drawModel(GL_SELECT);

glMatrixMode (GL_PROJECTION);
glPopMatrix();
glFlush();

hits = glRenderMode(GL_RENDER);
processHits(hits, selectBuf);


mouse1.SetState(button, state);
mouse1.SetNewPos(x, y);
printf("Mouse %s At %d %d\n", (state == GLUT_DOWN) ? "Down" : "Up", x, y);
} glutPostRedisplay();

}
void
motion(int x, int y)
{

mouse1.SetOldPos(mouse1.GetX(), mouse1.GetY());
mouse1.SetNewPos(x, y);

printf("Mouse Drag Button ");

if (mouse1.IsLeft())
printf("Left\n");
else if (mouse1.IsRight())
printf("Right\n");
else
printf("Middle\n");

printf("\tFrom %d %d\n", mouse1.GetOldX(), mouse1.GetOldY());
printf("\tTo %d %d\n", mouse1.GetX(), mouse1.GetY());
printf("\tChange %d %d\n", mouse1.GetDiffX(), mouse1.GetDiffY());

glutPostRedisplay();
}



ant ideas what could be the problem becuase i am very sure the picking is working correctly,i am not sure if i need to put the gltranslate(..) in the display function because it always seems to translate every object in the scene.

thanks for your help.

Aleksandar
07-11-2011, 05:53 AM
the first problem is that if i click an object it drags all the objects including currently selected objects.
That's a correct behavior since you are a applying viewing transformation. Instead of moving a single objects you are moving the camera (or the whole scene). I would rather skip the whole story about the transformations and direct you to the chapter 3 of the Red book (OpenGL Programming Guide). In short, you should save current model-view matrix (glPushMatrix()), do the translation, draw the particular object, and than restore model-view matrix (glPopMatrix()).


the second problem is that the objects dont follow the mouse movements accurately ,what i mean is that models are usually some distance away from the mouse as the mouse moves, i sometimes have to take the mouse pointer out of the screen to get them at the center.
That's because your math is not correct. You have to calculate the translation parameters so that the point under the cursor stays under it after the mouse movement. Using mouse movement in screen coordinates is not enough for the transformation. It requires "a little bit more" complicated math. ;)

gottijay
07-11-2011, 06:27 AM
In short, you should save current model-view matrix (glPushMatrix()), do the translation, draw the particular object, and than restore model-view matrix (glPopMatrix()).;)


thanks Aleksander, i just have one method which i use to draw all the models(not the same as the one in my previous post...this one is drawn using a for loop),this is the part i have been struggling with for a while now, how do i draw the particular model picked?. or do i need to create a draw function for each of the models?



That's because your math is not correct. You have to calculate the translation parameters so that the point under the cursor stays under it after the mouse movement. Using mouse movement in screen coordinates is not enough for the transformation. It requires "a little bit more" complicated math. ;)

i'm really horrible at maths, is there anyway you could give me an algorithm that i could implement on mine..or any idea.
i had a look at the link you posted, it was a little too complex for me..
but thank you.

Aleksandar
07-11-2011, 08:15 AM
Each of your objects needs to have its own transformation. You can do it in a separate function or in the loop. It's your choice. But in any case you should read (at least) third chapter from the Red book.

Mathematical transformations are the fundamental part of 3D programming. Nothing can be done without them. I don't have any easy solution in my sleeves for what you want to achieve. Although, you could try to use a simple proportion. If you are using a perspective projection, calculate the (equivalent) amount of a movement in the plane that is parallel to a near clip plane and contains clicked point for the given mouse movement. Another way is to calculate where the ray casted from the viewer's position, and passing through the point under the mouse cursor (at the near clip plane), intersects plane along which you want to move the object.

gottijay
07-12-2011, 04:03 AM
thanks Aleksander for your help...i did read the book(opengl programming guide)..i am still confused as to how to apply it to solve my own problem...i made this changes and removed the camera movement that was there initially..what i did was basically this..

glPushMatrix();
// this pushes the 'world' matrix on the stack
glLoadIdentity();

gltranslatef ( x,y,z );

glPushMatrix();
// transform model

gltranslatef ( mx,my,mz );

glPopMatrix();
// done with object
glPopMatrix();
// done with world


any ideas what i may be doing wrong



mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON &amp;&amp; glutGetModifiers() & GLUT_ACTIVE_SHIFT)
button = GLUT_MIDDLE_BUTTON;



if(button==GLUT_LEFT_BUTTON &amp;&amp; state== GLUT_DOWN)
{
glGetIntegerv(GL_VIEWPORT,viewport);
glSelectBuffer(SIZE, selectBuf);
glRenderMode(GL_SELECT);

glInitNames();
glPushName(-1);

glMatrixMode(GL_PROJECTION);
glPushMatrix();//push world
glTranslatef(1.0, 1.0, 0.0);// translate world
drawModel(GL_RENDER);
glPushMatrix();//selected object
glLoadIdentity();

gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport);
gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,0.1f,10000.0f);

glTranslatef(mouse1.GetX(), mouse1.GetY(), 0.0);
drawModel(GL_SELECT);

glMatrixMode (GL_PROJECTION);
glPopMatrix();
glPopMatrix();
glFlush();

hits = glRenderMode(GL_RENDER);
processHits(hits, selectBuf);


mouse1.SetState(button, state);
mouse1.SetNewPos(x, y);
printf("Mouse %s At %d %d\n", (state == GLUT_DOWN) ? "Down" : "Up", x, y);
} glutPostRedisplay();

}

Aleksandar
07-12-2011, 05:37 AM
The first glPushMatrix(), ant the last glPopMatrix() are probably superfluous. What's the problem now?

gottijay
07-12-2011, 06:05 AM
The first glPushMatrix(), ant the last glPopMatrix() are probably superfluous. What's the problem now?

it does not move, none of the objects but i did replace the glTranslate function with ObjTranslate(&amp;object[obj_control],mouse1.GetX(), mouse1.GetY(), 0.0); this happens to make the object disappear or translate to a position not in the view

so i decided to use ObjTranslate(&amp;object[obj_control],0.0, 0.0, -1.0); it seemed to move a step with every click, the same happened to all of the other objects...

it appears the inaccuracy of my drag algorithm might be the cause....what do you think

Aleksandar
07-12-2011, 06:36 AM
That's probably because you don't update (mx,my,mz) properly.

Aleksandar
07-12-2011, 06:58 AM
You have edited previous post while I've been answering on it.


this happens to make the object disappear or translate to a position not in the view
That's probably result of transformation combining. The translation of the objects is superimposed to a view transformation. That's probable what you didn't get from the Red book, but is crucial for the transformations.

csnyman
08-13-2011, 04:58 AM
I have a very similar scenario as gottijay. I am rendering 108 billboards to the screen and would like to identify which one is being clicked on by the user. I have followed the code that he submitted and have compared it to my code and found that there are hardly any differences. The problem I have is that I get 108 hits, regardless of where I click on the screen. Could anyone help out, as I have been struggling with this problem for a week now.

The following code gets called whenever the mouse is clicked.



private void PickRects(MouseEventArgs e)
{
/* sets up selection mode, name stack, and projection matrix for picking. Then the objects are drawn */

selectBuf = new uint[512];
int hits;
int[] viewport = new int[4];

Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);

Gl.glSelectBuffer(512, selectBuf);
Gl.glRenderMode(Gl.GL_SELECT);

Gl.glInitNames();
Gl.glPushName(-1);
Global.billboardNum = 0;

Gl.glMatrixMode(Gl.GL_PROJECTION);
Gl.glPushMatrix();
Gl.glLoadIdentity();
/* create 5x5 pixel picking region near cursor location */
Glu.gluPickMatrix((double)e.X, (double)(viewport[3] - e.Y), 5.0, 5.0, viewport);

Render(Gl.GL_SELECT);

Gl.glPopMatrix();
Gl.glFlush();

hits = Gl.glRenderMode(Gl.GL_RENDER);
ProcessHits(hits, selectBuf);
}



Here is the Render method:



public void Render(uint RenderMode)
{
Gl.glEnable(Gl.GL_BLEND);
Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);

// Render billboards
// Loop through all billboards

if (RenderMode.Equals(Gl.GL_SELECT))
{
Gl.glPushMatrix();
Gl.glTranslated(posX , posY , posZ );
data[x][y][z].Billboard.Render(RenderMode);
data[x][y][z].billboardNum = Global.billboardNum;
Global.billboardNum++; //Global var to keep track
Gl.glPopMatrix();
Gl.glFlush();
}
else
{

Gl.glPushMatrix();
Gl.glMatrixMode(Gl.GL_MODELVIEW);
Gl.glTranslated(posX , posY , posZ );
data[x][y][z].Billboard.Render(RenderMode);
Gl.glPopMatrix();
Gl.glFlush();
}
}



And lastly this is my Billboard render class



public void Render(uint RenderMode)
{

Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureBindID);
Gl.glEnable(Gl.GL_TEXTURE_2D);

// Set material properties
{
float[] ambient = { 0.6f, 0.6f, 0.6f, 1f };
float[] diffuse = { 1, 1, 1, 1f };
float[] specular = { 0.1f, 0.1f, 0.1f, 1f };
float shininess = 5;
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, ambient);
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_DIFFUSE, diffuse);
Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SPECULAR, specular);
Gl.glMaterialf(Gl.GL_FRONT, Gl.GL_SHININESS, shininess);
}

// Rotate billboard

Gl.glPushMatrix();

float[] matrix = new float[16];
Gl.glGetFloatv(Gl.GL_MODELVIEW_MATRIX, matrix);
float[] transform = new float[16];

transform[0] = matrix[0];
transform[1] = matrix[4];
transform[2] = matrix[8];
transform[3] = 0;

transform[4] = matrix[1];
transform[5] = matrix[5];
transform[6] = matrix[9];
transform[7] = 0;

transform[8] = matrix[2];
transform[9] = matrix[6];
transform[10] = matrix[10];
transform[11] = 0;

transform[12] = 0;
transform[13] = 0;
transform[14] = 0;
transform[15] = 1;

Gl.glMultMatrixf(transform);

if(RenderMode.Equals(Gl.GL_SELECT))
Gl.glPushName(Global.billboardNum);

Gl.glBegin(Gl.GL_QUADS);
Gl.glNormal3d(0, 0, 1);
Gl.glTexCoord2d(0, 1);
Gl.glVertex3d(-Width / 2, -Height / 2, 0);

Gl.glTexCoord2d(1, 1);
Gl.glVertex3d( Width / 2, -Height / 2, 0);

Gl.glTexCoord2d(1, 0);
Gl.glVertex3d( Width / 2, Height / 2, 0);

Gl.glTexCoord2d(0, 0);
Gl.glVertex3d(-Width / 2, Height / 2, 0);
Gl.glEnd();

if(RenderMode.Equals(Gl.GL_SELECT))
Gl.glPopName();

Gl.glPopMatrix();

Gl.glDisable(Gl.GL_TEXTURE_2D);
}


Thank you very much for the help!

Aleksandar
08-13-2011, 11:22 AM
Projection matrix setup is missing.