problem with picking objects in opengl

hi

i’m trying to implement object picking in opengl by using glRenderMode(GL_SELECT) and a name stack as described here:

http://www.lighthouse3d.com/opengl/pick-…-?openglway

it works great except i’m having problems with some objects not being reported as selected. this are smaller objects like gui controls but the size doesn’t seem to be the reason, i’m also using the hierarchical mode to be able to distinguish which control inside which object i’m selecting but the level in the stack doesn’t seem to be the reason too.

perhaps i have some problem in my code, but i’m reviewing it once and again and it seems correct.

i’m suspecting there’s some opengl functionality i’m using and from that point the rest of the objects are not being reported.

has anybody used this method sometime and found some problem like this?

ok, find it, i wasn’t setting GL_MODELVIEW before rendering the scene for picking so objects without gl transformation was being detected right but after doing some translations i was changing the projection matrix and the coordinates were wrong.

hey arturo, I have just implemented some ray picking with openscenegraph and it’s pretty sweet. It’s a pretty big lib and might be overkill for your purpose but if you want to give it a try on linux I can send you my ofxOsg “preAlpha” files.

Let me know if you are interested.
(I might also have some linux question later, still banging my head on my fresh ubuntu install)

Arturo, if you come up with some good selection code you should post it up, I see a lot of people posting about how to do this, and there is one example from Theo floating around, but more can’t hurt.

@stefan, yes, send me, with this method i’m only able to know what object is being selected but not in what part of it i’m clicking. although right now i only need to correct the perspective for simple selection, it can be useful to take a look.

@joshua, sure :slight_smile:

so the idea is that whenever you receive a mouse click, or any other coordinate event you render again the whole scene with glRenderMode(GL_SELECT) but modifying the projection matrix so it only renders a 1x1 or the area you want around that coordinates with gluPickMatrix. that way every object that is rendered is detected and reported to be in that coordinates. this code should work for any perspective settings as i’m reading the current matrix and multiplying by that when i go to GL_SELECT:

  
void glSelect(int x, int y)  
{  
	GLuint buff[512] = {0};  
	GLint hits, view[4];  
	GLfloat proj_matrix[16];  
  
	/*  
		This choose the buffer where store the values for the selection data  
	*/  
	glSelectBuffer(256, buff);  
  
	/*  
		This retrieves info about the viewport  
	*/  
	glGetIntegerv(GL_VIEWPORT, view);  
  
	glGetFloatv(GL_PROJECTION_MATRIX, proj_matrix);  
  
  
	/*  
		Switching in selecton mode  
	*/  
	glRenderMode(GL_SELECT);  
  
	/*  
		Clearing the names' stack  
		This stack contains all the info about the objects  
	*/  
	glInitNames();  
  
	/*  
		Now modify the viewing volume, restricting selection area around the cursor  
	*/  
	glMatrixMode(GL_PROJECTION);  
	glPushMatrix();  
  
		glLoadIdentity();  
		/*  
			restrict the draw to an area around the cursor  
		*/  
		gluPickMatrix(x, y, 1.0, 1.0, view);  
		glMultMatrixf(proj_matrix);  
		/*  
			Draw the objects onto the screen  
		*/  
		glMatrixMode(GL_MODELVIEW);  
  
		/*  
			draw only the names in the stack, and fill the array  
		*/  
		draw();  
  
		/*  
			Do you remeber? We do pushMatrix in PROJECTION mode  
		*/  
		glMatrixMode(GL_PROJECTION);  
	glPopMatrix();  
  
	/*  
		get number of objects drawed in that area  
		and return to render mode  
	*/  
	hits = glRenderMode(GL_RENDER);  
  
	/*  
		Print a list of the objects  
	*/  
	list_hits(hits, buff);  
  
	glMatrixMode(GL_MODELVIEW);  
}  

in mousePressed you call:

  
glSelect(x,ofGetHeight()-y); //the y is inversed as i'm not doing that in the matrix settings as it's done in oF  

this function prints all the hits:

  
void list_hits(GLint hits, GLuint *buffer)  
{  
	unsigned int j;  
	GLuint *ptr, minZ, minminZ, nearestId, *ptrNames, numberOfNames;  
	printf ("hits = %d\n", hits);  
	ptr = (GLuint *) buffer;  
	minminZ = 0xffffffff;  
	for (int i = 0; i < hits; i++) {  
		numberOfNames = *ptr;  
		ptr++;  
		minZ = *ptr;  
  
		ptrNames = ptr+2;  
  
		if(minminZ>minZ && numberOfNames>0){  
			minminZ = minZ;  
			nearestId = ptrNames[0];  
		}  
  
		printf("%d names found:",numberOfNames);  
		for (j = 0; j < numberOfNames; j++,ptrNames++) {  
			printf ("%d ", *ptrNames);  
		}  
		printf ("\n");  
		ptr += numberOfNames+2;  
	}  
	printf("nearest id %d\n",nearestId);  
	printf ("\n");  
  
}  

and to give a name to the objects you have 2 possibilities:

glLoadName(GLint);

gives a name to everything you render from that point, you will need to add glPushName(0) to the previous code before the call to draw.

in my case i have several objects in a hierarchy so i want to distinguish what part of which object has been selected so i use the stack mode:

  
glPushName(id);  //the id of the main object  
  
//render something  
  
glPushName(BUTTON_1);  
  
button1.draw();  
  
glPopName();  
  
glPushName(BUTTON_2);  
  
button2.draw();  
  
glPopName();  
  
....  
  
glPopName();  

this way when i return to GL_RENDER i get the id of the pressed object + the specific part of it.

also be careful if you do this in a thread (with tuio for example) as it will crash, so you will need to accumulate all the pressed events in a vector and process all of them in the update cycle.

[quote author=“stefanix”]Let me know if you are interested.
(I might also have some linux question later, still banging my head on my fresh ubuntu install)[/quote]
I am also interested in your ofxOsg. Perhaps I can contribute back, I am using OpenScenegraph instead of OpenFrameworks for 6 years now :wink:

cheers,
Stephan

Thanks arturo, I stuck it up on the wiki too (though I don’t think too many people use it).

Hi,

Just a word of caution about Object picking with GL_Select.

Beware that a BIG drop in performance will exist in ATI or NVIDIA GPUs :frowning:

The hardware accelaration for GL_Select is only in full power on the high end craphics cards specially for graphics workstation.

The Bad Thing, that’s only a matter of drivers, ( some folks have hacked the drivers ) but not a good solution.

So, if u have lots of objects to pick ( like i have , > 10000) it’s better that you dont relly on that method for object picking.

chears,
Carlos