Picking / Selection problem

Started by
9 comments, last by darren_mfuk 17 years ago
Hey guys, I have followed NeHe's tutorial on selection / picking and have a problem. It seem to work ok, in that I know I am clicking something, the problem is knowing what I have clicked. Here is the code, with minimal changes :


int objectSelection(int mouseX, int mouseY)						// This Is Where Selection Is Done
{
	GLuint	buffer[512];										// Set Up A Selection Buffer
	GLint	hits;												// The Number Of Objects That We Selected
	GLint	hitID = 0;

	if (gameOver)												// Is Game Over?
		return 0;													// If So, Don't Bother Checking For Hits
	
	// The Size Of The Viewport. [0] Is <x>, [1] Is <y>, [2] Is <length>, [3] Is <width>
	GLint	viewport[4];

	// This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window
	glGetIntegerv(GL_VIEWPORT, viewport);
	glSelectBuffer(512, buffer);								// Tell OpenGL To Use Our Array For Selection

	// Puts OpenGL In Selection Mode. Nothing Will Be Drawn.  Object ID's and Extents Are Stored In The Buffer.
	(void) glRenderMode(GL_SELECT);

	glInitNames();												// Initializes The Name Stack
	glPushName(0);												// Push 0 (At Least One Entry) Onto The Stack

	glMatrixMode(GL_PROJECTION);								// Selects The Projection Matrix
	glPushMatrix();												// Push The Projection Matrix
	glLoadIdentity();											// Resets The Matrix

	// This Creates A Matrix That Will Zoom Up To A Small Portion Of The Screen, Where The Mouse Is.
	gluPickMatrix((GLdouble) clickXcoord, (GLdouble) (viewport[3] - clickYcoord), 1.0f, 1.0f, viewport);

	// Apply The Perspective Matrix
	gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);
	glMatrixMode(GL_MODELVIEW);									// Select The Modelview Matrix

		//DrawTargets();												// Render The Targets To The Selection Buffer
			DrawGLScene();

	glMatrixMode(GL_PROJECTION);								// Select The Projection Matrix
	glPopMatrix();												// Pop The Projection Matrix
	glMatrixMode(GL_MODELVIEW);									// Select The Modelview Matrix
	hits=glRenderMode(GL_RENDER);								// Switch To Render Mode, Find Out How Many
																// Objects Were Drawn Where The Mouse Was
	if (hits > 0)												// If There Were More Than 0 Hits
	{
		int	choose = buffer[3];									// Make Our Selection The First Object
		int depth = buffer[1];									// Store How Far Away It Is 

		for (int loop = 1; loop < hits; loop++)					// Loop Through All The Detected Hits
		{
			// If This Object Is Closer To Us Than The One We Have Selected
			if (buffer[loop*4+1] < GLuint(depth))
			{
				choose = buffer[loop*4+3];						// Select The Closer Object
				depth = buffer[loop*4+1];						// Store How Far Away It Is
			}       
		}


		hitID = choose;

	/*
		if (!object[choose].hit)								// If The Object Hasn't Already Been Hit
		{
			object[choose].hit=TRUE;							// Mark The Object As Being Hit
			score+=1;											// Increase Score
			kills+=1;											// Increase Level Kills
			if (kills>level*5)									// New Level Yet?
			{
				miss=0;											// Misses Reset Back To Zero
				kills=0;										// Reset Level Kills
				level+=1;										// Increase Level
				if (level>30)									// Higher Than 30?
					level=30;									// Set Level To 30 (Are You A God?)
			}
		}
	*/

		return hitID;
    }
	return 0;
}




Note: changes include, some variable names for the mouse co-ords, the gameOver variable. Then the code refering to object hits. All I need is the object ID, which I think is 'choose' - and I want to assign this to 'hitID = choose;' and return it. My DrawGLScene code :

glLoadName(100);	// Push on our label (IMPORTANT)
	// 3D SPHERE CENTER
	glPushMatrix();
		glColor3f(0.0f, 1.0f, 0.0f);
		glTranslatef(0.0f, 0.0f, 0.0f);
		Draw_Sphere();					
	glPopMatrix();

glLoadName(200);	// Push on our label (IMPORTANT)
	// 3D SPHERE LEFT
	glPushMatrix();
		glColor3f(1.0f, 0.0f, 0.0f);
		glTranslatef(-10.0f, 5.0f, 0.0f);
		Draw_Sphere();					
	glPopMatrix();
	
glLoadName(300);	// Push on our label (IMPORTANT)
	// 3D SPHERE RIGHT
	glPushMatrix();
		glColor3f(0.0f, 0.0f, 1.0f);
		glTranslatef(10.0f, 5.0f, 0.0f);
		Draw_Sphere();					
	glPopMatrix();

glLoadName(666);	// Push on our label (IMPORTANT)
	// render Cube
	glPushMatrix();
		glColor3f(1.0f, 1.0f, 1.0f);
		glTranslatef(0.0f, 1.0f, 50.0f);
		Draw_Box();
	glPopMatrix();

// more objects




OK the problem comes when I click anything, the value returned is always the LAST ID assigned. As in the code above 'glLoadName(666);' the value returned is always 666. I expected that for any objects 'AFTER glLoadName(666);' because I don't care about those. But clicking anything before that point, ie any of the spheres rendered all return 666. Everything I have been reading suggests using glLoadName and not glPushName, as I have searched the forum, I just can't spot the problem. Any ideas guys, THANKS ;-) [Edited by - darren_mfuk on March 9, 2007 8:47:13 PM]
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
Advertisement
Just a quick update,

Another thread suggested that 'glEnd();' was needed after glLoadName()

That hasn't worked, and no solution was actually posted for the other thread.

So any ideas, just shout ;-)
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
OK,

Another problem that I never mentioned, although I did read it in some other threads.

Was getting a return 'count' of 1 even clicking on nothing.
And when clicking on a single object, it was returning 2.

I have now found this was actually due to the 'crosshair' quad.

I did not see how NeHe accounted for this in his tutorial, but I guess that is not really importent, as the point is to get the object ID, not the number of objects hit.

As this was rendered after the last object assigned with '666', that is why that value was returned all the time.
As the crosshair quad had the same value.

Anyway I created a boolean 'modePicking' which I set true or false during the slection code.

then just added to the render code:

if (!modePicking)
RenderCrosshair(16, 16);

As for the actual problem of returning the object ID, I found that removing any code for glPrint() for the fonts, ie onscreen text causes the problem.

All on screen text is rendered last, after the objects.
ie Frame rate, time, other text etc etc..

I think this is something to do with glPrint() swithing projection/orth modes during GL_SELECT (picking mode) and messing things up.

I could use the above boolean again around all this code.
But I wanted to find out the cause of the problem, to avoid 'coding around' the issue.

Any ideas ??
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
Wow this forum really fills up fast !!

A post will end up 3 or 4 pages down the list, drowned by questions on which language to learn, or what book to buy, or please give me the full source code for my next MMORPG !!

I mean, I know this question is no doubt an easy one, and something silly I've missed.

But damn, don't these people read the stickys and FAQ !!!

OK, so I wont rant & rave too much !!

Any one had problems with picking and switching mode during picking, or using glPrint(); (fonts)

Cheers ;-)
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
I know exactly how you feel, I've asked three seperate questions on this forum and NONE of them were answered. Two of them weren't even replied to. Even though I bumped them each after they fell to halfway down the second page!

Anyway, sorry I can't help you, I don't even know C++. But maybe this will keep your thread up long enough to get it answered :-)
[rolleyes] Thanks theStormWeaver [rolleyes]
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
This is probably the wrong forum to ask your question, try the opengl forum.
Yeah thanks ;-)

I didn't know how to move the thread.
I mailed Admin, but have heard anything back.

Didn't want to 'double post' it so I left it here.

So if you know how to move a thread let me know ;-)
----------------------------------------Now just hit that link that says 'Rate This User' [wink]
Any ideas or updates guys.

Who do I do picking / selection .. and avoid 2D Orth objects being picked

Basically the object count returned when doing selection, counts things like crosshair, HUD objects etc etc.

----------------------------------------Now just hit that link that says 'Rate This User' [wink]
Hey Darren,
What I have found from doing picking and selection, is that if you have things like a HUD and crosshairs and things you want people to select, then you should keep the drawing of these things in separate functions.

Most of the selection examples call the main redraw function when they want to select something. This is ok in a basic example since the redraw code is simple and usually just draws a few selectable objects on the screen. But real world programs will probably be a little more complex and have more stuff going on in the redraw as I suspect you do.

So when you go to do the actual selection you don't really need to draw the stuff the user gets to see just the stuff the user needs to select. Since the stuff drawn during selection is never seen at all. You just need to make sure the projection is set up the way the user sees it and the camera needs to be set up like it is for the user as well. Then you can draw just the selectable stuff which shouldn't need to change the projection or the camera any further.

I haven't had reliable results with selection when I tried to change projections in the middle of it. So I'm assuming this is where your problem is coming from.

Hope this helps,
DG

This topic is closed to new replies.

Advertisement