Jump to content
  • Advertisement
Sign in to follow this  
Xasz

OpenGL Selection and LoadIdentity()

This topic is 3849 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

So, any time I use LoadIdentity() while doing my selection pass of my render, the hit doesn't register, even using push and popmatrix. I can't think of any way around this, other than multiplying the current matrix by its inverse (will this even work or will it still kill my selection process?) and even that, I don't know how to do (I could do it manually, but I'm assuming that's a command to find the inverse) Someone help me make selection play nicely :( More detail: I've got a UI class, with several UIElement class objects in it. Each of these UIElements has a routine to render it that requires me to use LoadIdentity to get it to display in the proper location (Yes, I know it's possible to simply do the inverse operations, but getting all of that information where it needs to be would take more lines of code than the entirety of my program thus far) so, the UI, when rendered, just inits the names and renders the UIElements using their own routines. I just use the UI's render routine inside of my selection code and it works... as long as I don't use LoadIdentity() anywhere in there, which, as I said, I need to use. Maybe there's a different way to do selection so that I can use LoadIdentity? Here's my selection function:
int RetrieveObjectID(int x, int y)
{
	int objectsFound = 0;								// This will hold the amount of objects clicked
	int	viewportCoords[4] = {0};						// We need an array to hold our view port coordinates

	// This will hold the ID's of the objects we click on.
	// We make it an arbitrary number of 32 because openGL also stores other information
	// that we don't care about.  There is about 4 slots of info for every object ID taken up.
	unsigned int selectBuffer[32] = {0};				
														
	// glSelectBuffer is what we register our selection buffer with.  The first parameter
	// is the size of our array.  The next parameter is the buffer to store the information found.
	// More information on the information that will be stored in selectBuffer is further below.

	glSelectBuffer(32, selectBuffer);					// Setup our selection buffer to accept object ID's

	// This function returns information about many things in OpenGL.  We pass in GL_VIEWPORT
	// to get the view port coordinates.  It saves it like a RECT with {top, left, bottom, right}

	glGetIntegerv(GL_VIEWPORT, viewportCoords);			// Get the current view port coordinates

	// Now we want to get out of our GL_MODELVIEW matrix and start effecting our
	// GL_PROJECTION matrix.  This allows us to check our X and Y coords against 3D space.

	glMatrixMode(GL_PROJECTION);						// We want to now effect our projection matrix
	
	glPushMatrix();										// We push on a new matrix so we don't effect our 3D projection

		// This makes it so it doesn't change the frame buffer if we render into it, instead, 
		// a record of the names of primitives that would have been drawn if the render mode was
		// GL_RENDER are now stored in the selection array (selectBuffer).

		glRenderMode(GL_SELECT);						// Allows us to render the objects, but not change the frame buffer

		glLoadIdentity();								// Reset our projection matrix

		// gluPickMatrix allows us to create a projection matrix that is around our
		// cursor.  This basically only allows rendering in the region that we specify.
		// If an object is rendered into that region, then it saves that objects ID for us (The magic).
		// The first 2 parameters are the X and Y position to start from, then the next 2
		// are the width and height of the region from the starting point.  The last parameter is
		// of course our view port coordinates.  You will notice we subtract "y" from the
		// BOTTOM view port coordinate.  We do this to flip the Y coordinates around.  The 0 y
		// coordinate starts from the bottom, which is opposite to window's coordinates.
		// We also give a 2 by 2 region to look for an object in.  This can be changed to preference.

		gluPickMatrix(x, viewportCoords[3] - y, 2, 2, viewportCoords);

		// Next, we just call our normal gluPerspective() function, exactly as we did on startup.
		// This is to multiply the perspective matrix by the pick matrix we created up above. 

		gluPerspective(45.0f,(float)g_rRect.right/(float)g_rRect.bottom,0.1f,150.0f);
		
		glMatrixMode(GL_MODELVIEW);						// Go back into our model view matrix
	
		//DrawGLScene(0.0f);									// Now we render into our selective mode to pinpoint clicked objects
		theUI->Show();
		//blargh();
		// If we return to our normal render mode from select mode, glRenderMode returns
		// the number of objects that were found in our specified region (specified in gluPickMatrix())

		objectsFound = glRenderMode(GL_RENDER);			// Return to render mode and get the number of objects found

		glMatrixMode(GL_PROJECTION);					// Put our projection matrix back to normal.
	glPopMatrix();										// Stop effecting our projection matrix

	glMatrixMode(GL_MODELVIEW);							// Go back to our normal model view matrix

	// PHEW!  That was some stuff confusing stuff.  Now we are out of the clear and should have
	// an ID of the object we clicked on.  objectsFound should be at least 1 if we found an object.

	if (objectsFound > 0)
	{		
		// If we found more than one object, we need to check the depth values
		// of all the objects found.  The object with the LEAST depth value is
		// the closest object that we clicked on.  Depending on what you are doing,
		// you might want ALL the objects that you clicked on (if some objects were
		// behind the closest one), but for this tutorial we just care about the one
		// in front.  So, how do we get the depth value?  Well, The selectionBuffer
		// holds it.  For every object there is 4 values.  The first value is
		// "the number of names in the name stack at the time of the event, followed 
		// by the minimum and maximum depth values of all vertices that hit since the 
		// previous event, then followed by the name stack contents, bottom name first." - MSDN
		// The only ones we care about are the minimum depth value (the second value) and
		// the object ID that was passed into glLoadName() (This is the fourth value).
		// So, [0 - 3] is the first object's data, [4 - 7] is the second object's data, etc...
		// Be carefull though, because if you are displaying 2D text in front, it will
		// always find that as the lowest object.  So make sure you disable text when
		// rendering the screen for the object test.  I use a flag for RenderScene().
		// So, lets get the object with the lowest depth!		

		// Set the lowest depth to the first object to start it off.
		// 1 is the first object's minimum Z value.
		// We use an unsigned int so we don't get a warning with selectBuffer below.
		unsigned int lowestDepth = selectBuffer[1];

		// Set the selected object to the first object to start it off.
		// 3 is the first object's object ID we passed into glLoadName().
		int selectedObject = selectBuffer[3];

		// Go through all of the objects found, but start at the second one
		for(int i = 1; i < objectsFound; i++)
		{
			// Check if the current objects depth is lower than the current lowest
			// Notice we times i by 4 (4 values for each object) and add 1 for the depth.
			if(selectBuffer[(i * 4) + 1] < lowestDepth)
			{
				// Set the current lowest depth
				lowestDepth = selectBuffer[(i * 4) + 1];

				// Set the current object ID
				selectedObject = selectBuffer[(i * 4) + 3];
			}
		}
		
		// Return the selected object
		return selectedObject;
	}

	// We didn't click on any objects so return 0
	return 0;											
}
[Edited by - Xasz on May 28, 2008 7:01:35 PM]

Share this post


Link to post
Share on other sites
Advertisement
I have no clue what you want to do. Using glLoadIdentity() doesnt resgister a hit?

Sounds like your just trying to select objects like click buttons. This has nothing to do with GL. Maybe your doing something else. I have no clue why you brought up inverse matrices when your just drawing a UI.

glLoadIdentity();
//bind UI element here
glBegin(GL_QUADS);
//Draw a textured quad for a button

If your trying to click it, then you can just convert your mouse into coordinates from -1 to 1, and then test that with the quad. I dont' know what ur asking so my answer might be dumb.

Share this post


Link to post
Share on other sites
When I comment out the LoadIdentity, the object is drawn in the wrong place, but if I click it, the hit is processed fine. Leaving the LoadIdentity there causes it to be drawn in the right place, but it doesn't register the hit anymore

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!