Sign in to follow this  

Picking / Selection problem

This topic is 3918 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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]

Share this post


Link to post
Share on other sites
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 ;-)

Share this post


Link to post
Share on other sites
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 ??

Share this post


Link to post
Share on other sites
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 ;-)

Share this post


Link to post
Share on other sites
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 :-)

Share this post


Link to post
Share on other sites
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 ;-)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Thanks,

That's what I kind of thought.

I just added this basically (and toggle the boolean true/false in the selection code


// RENDER CODE

if (!modePicking)
{
// all 2D stuff to be excluded from selection/picking
// cross hair
// HUD
// fonts etc etc

}




// SELECTION CODE CONDENSED
modePicking = TRUE;

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(FOV, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, CAMERA_FARPLANE);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
DrawGLScene(); // Render Scene To The Selection Buffer
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

modePicking = FALSE;

Share this post


Link to post
Share on other sites

This topic is 3918 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this