Can't get Picking to work

I tried following the Nehe tutorial on picking, but aparantly I haven’t understood everything :slight_smile: Think you guys could take a look at my method to check for hits? When I change perspectives or change the screen size I make a glFrustum call, but it isn’t called in this method. Does it need to be?

Here’s the method. I hope you guys can help me figure out the problem!


public InteractionTarget getTargetHit(GLDrawable drawable, int mouseX, int mouseY) {
	GL gl = drawable.getGL();
	
	int[] viewport = new int[4];
	// This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window
	gl.glGetIntegerv(GL.GL_VIEWPORT, viewport);
	//where our hits will be stored
	IntBuffer buffer = BufferUtils.newIntBuffer(elements.size());
	gl.glSelectBuffer(elements.size(), buffer);
	
	gl.glRenderMode(GL.GL_SELECT);
	
	gl.glInitNames();								// Initializes The Name Stack
	gl.glPushName(0);
	
	gl.glMatrixMode(GL.GL_PROJECTION);						// Selects The Projection Matrix
	gl.glPushMatrix();								// Push The Projection Matrix
	gl.glLoadIdentity();
	
	drawable.getGLU().gluPickMatrix(mouseX, viewport[3] - mouseY, 1.0f, 1.0f, viewport);
	
	gl.glMatrixMode(GL.GL_MODELVIEW);						// Select The Modelview Matrix
	gl.glLoadIdentity();
	
	camera.look(drawable);
	
	//Render all the objects in a Thread safe way
	ArrayList elements = getElements();
	synchronized (elements) {
		//Draw all of the Elements in the scene that have InteractionTargets
		for (int i = 0; i < elements.size(); i++) {
			Element e = (Element)elements.get(i);
			
			if ((e.getInteractionTarget(Element.TARGET_POSITION) != null
						&& e.getInteractionTarget(Element.TARGET_POSITION).isEnabled()) ||
				(e.getInteractionTarget(Element.TARGET_SIZE) != null
						&& e.getInteractionTarget(Element.TARGET_SIZE).isEnabled()) ) {
				
				System.out.println("checking " + i + " " + e.getClass());
				gl.glLoadName(i);
				e.draw(drawable);
			}
		}
	}
	
	gl.glMatrixMode(GL.GL_PROJECTION);						// Select The Projection Matrix
	gl.glPopMatrix();								// Pop The Projection Matrix
	gl.glMatrixMode(GL.GL_MODELVIEW);						// Select The Modelview Matrix
	
	int hits = gl.glRenderMode(GL.GL_RENDER);
	
	System.out.println("hits: " + hits);
	
	if (hits > 0) {
		
		int	choose = buffer.get(3);					// Make Our Selection The First Object
		long depth = ((long)buffer.get(1)) & 0xFFFFFFFFL;
		
		for (int loop = 1; loop < hits; loop++) {
			// If This Object Is Closer To Us Than The One We Have Selected
			long newDepth = ((long)buffer.get(loop*4+1)) & 0xFFFFFFFFL;
			if (newDepth < depth) {
				choose = buffer.get(loop*4+3);			// Select The Closer Object
				depth = newDepth;			// Store How Far Away It Is
			}       
		}
		
		return (InteractionTarget)( ((Element)elements.get(choose)).getInteractionTarget(Element.TARGET_POSITION) );
	}
	
	return null;
}
Camera class:
public void look(GLDrawable drawable) {
	
	Vec3D position = getPerspectivePosition();
	
	if (getProjectionMode() == Camera.MODE_PLANAR_XY) {
		drawable.getGLU().gluLookAt(
				position.x, position.y, position.z,
				focusX, focusY, focusZ,
				0, 1, 0);
	}
	else
	drawable.getGLU().gluLookAt(
		position.x, position.y, position.z,
		focusX, focusY, focusZ,
		0, 0, 1); //so that our coordinate system is in the same direction as the simple3d one
	//usually 0, 1, 0 is used
}

The code basically looks correct as far as I can tell. Are you calling this method from one of your GLEventListener’s callback methods?

yep, this method is called from inside the mouseMoved() method which is called through the GLEventListener.

Perhaps there’s something wrong with calling canvas.getGL()? canvas is the GLEventListener and GLCanvas being drawn on.

It seems pretty much correct to me too. Something I do remember from when I implemented selection in my application is that the select buffer actually contains unsigned values. So in order to use the depth values correctly you have to convert it to a long:

((long)depth) & 0xFFFFFFFFL

yeah I don’t even get the chance to deal with depth values yet. Right now “hits” is always 0.

Could you call Thread.dumpStack() from within that method and post the output? I don’t know what mouseMoved() method you’re talking about but I hope it isn’t that of a MouseMotionListener. JOGL does not make the OpenGL context current within mouse, keyboard and other event listeners.

well that may have been part of the problem. The only way I’ve found to get mouse events in JOGL tutorials has been through the MouseListener and MouseMotionListener. At any rate, I changed my code so that mouseMoved() sets a boolean so that when display() is called, I do the picking in there with the current GLDrawable. Still no luck. I tried adding a gl.glLoadIdentity(); just after I switch to the model view matrix so that I could more easily ensure the render routine and picking routines didn’t mess up the matrices for each other.

Any other ideas?

Could you try plugging in the DebugGL pipeline in your GLEventListener.init() method and see if any errors are reported?

BTW, I also had a problem with feedback buffers
in selection mode. It didn’t work and returned
nothing. I didn’t probe deep into it though.
Could be related. Was any testing done on
JOGL’s feedback/picking?

Hmmm I don’t know how to do that. I did, however, run one of the JOGL demo’s that used picking successfully, so I know it can be done on my computer.

Look at the top of the Gears demo’s init() method to see how to install the DebugGL pipeline.

Well, it works fine for me, so there’s one test case right there!

Works fine for me too. (except for the unsigned int issue)

Got the debug pipeline up. I was getting an error. I double-checked the tutorial and found I had put something out of order, so I changed it and now I get no errors, but I also get no picking working.

One question I have. NeHe’s tutorial has this:
gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);

after selecting the model view matrix just before rendering. Is that equivalent to the:
camera.look(drawable); I’m using?

I changed about the first 10 lines of getTargetHit (updated up top), still no success. I’m getting this output when I print:
checking 0 class org.opensourcephysics.display3d.jogl.ElementCircle
checking 1 class org.opensourcephysics.display3d.jogl.ElementBox
checking 2 class org.opensourcephysics.display3d.jogl.ElementArrow
hits: 0

I get that every time I move the mouse.

Looking again at one of the picking examples, I think you need to multiply the pick matrix by the projection matrix. In your example code above I think you’re losing your perspective projection when you set up your pick matrix. It should look something like this:


glu.gluPickMatrix(...);
glu.gluPerspective(...);

See this example.

thank you for that example! I now get a response when I mouse over an object. However, regardless of how many objects my mouse is over, this code:

int hits = gl.glRenderMode(GL.GL_RENDER);
System.out.println("hits: " + hits);

always prints out “hits: -1”

Why is that?

According to the manual page for glSelectBuffer you’re overflowing your hit buffer.

Awesome! That’s what I needed to know. Silly me for not thinking to check there :stuck_out_tongue:

I have one more question about this. I’d like to do the picking whenever I want to, which means I need to get the current GLDrawable context whenever I want to. However the only way I know to do this is to call repaint() and grab it from display(). Is there a way I can do this without calling repaint()?

To force picking you should set up your state to request a pick and call GLCanvas.display(). In the current JOGL APIs there is no way to force the context to be made current aside from calling GLEventListener.display().


public void display(GLDrawable drawable) {
	if (requestingPickingUpdate) {
		//Do nothing now for debug purposes
		//lastPickedTarget = getTargetHit(drawable, lastMotionEvent.getX(), lastMotionEvent.getY());
		requestingPickingUpdate = false;
		return;
	}
	...then the rest of my render code
}
private void rePickTarget() {
	requestingPickingUpdate = true;
	canvas.display();
}

With this the canvas ends up flickering as if the perspective is changing back and forth when I call rePickTarget(); As you can see, no opengl calls actually happen during display(). However, the screen still changes. Why is this? I even put a printout in display() where the actual drawing occurs to find that it never prints out during all of this flickering, so it’s all happening with no opengl calls in display().

EDIT: I’ve studied a bit more what I’m looking at and I realized that what is happening is that JOGL is aparantly flipping between the two buffers. Each time display() calls and no rendering occurs, the buffer is flipped. How do I convince it not to do this?