Picking Problem

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

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.

What’s the difference between the “certain area on the scene” and the “model”?

Thanks Aleksander for your help, really appreciated

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

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.

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 
	}
   }
   

  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.

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

I’m glad I could help. :slight_smile:

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

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 && glutGetModifiers() & GLUT_ACTIVE_SHIFT)
        button = GLUT_MIDDLE_BUTTON;
    
	

	if(button==GLUT_LEFT_BUTTON && 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
", (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
");
   else if (mouse1.IsRight())     
      printf("Right
");
   else
      printf("Middle
");

   printf("	From   %d %d
", mouse1.GetOldX(), mouse1.GetOldY());
   printf("	To     %d %d
", mouse1.GetX(), mouse1.GetY());
   printf("	Change %d %d
", 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.

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()).

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. :wink:

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?

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.

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.

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 && glutGetModifiers() & GLUT_ACTIVE_SHIFT)
        button = GLUT_MIDDLE_BUTTON;
    
	

	if(button==GLUT_LEFT_BUTTON && 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
", (state == GLUT_DOWN) ? "Down" : "Up", x, y);
 	} glutPostRedisplay();

}

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(&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(&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

That’s probably because you don’t update (mx,my,mz) properly.

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.

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!

Projection matrix setup is missing.