PDA

View Full Version : Picking catastrophe...



topherreynoso
06-01-2009, 02:22 PM
Hey everyone, I'm new to OpenGL but loving it so far. Unfortunately though I can't seem to get picking to work properly. It loads up just fine and displays everything properly but when I go to select something it always has hits in it no matter where I am in the window and they are not valid hits. I have tried everything I can think of and in all sorts of ways. The latest attempt and the relevant code is below, thanks in advance for the help.

[CODE]
- (void)mouseMoved:(NSEvent *)theEvent
{
if(gZoom == NO && gPan == NO && gTrackball == NO && gNotes == NO)
{
int x, y;
NSPoint location = [self convertPoint:[theEvent locationInWindow] fromView:nil];
x = location.x;
y = location.y;
GLfloat fAspect; // Screen aspect ratio

// Space for selection buffer
GLuint selectBuff[512];

// Hit counter and viewport storeage
GLint hits, viewport[4];
GLdouble proj[16];

// Setup selection buffer
glSelectBuffer(512, selectBuff);

// Change render mode
glRenderMode(GL_SELECT);

// Initialize names
glInitNames();

// Switch to projection and save the matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

// Obtain current projection matrix
glGetDoublev(GL_PROJECTION_MATRIX, proj);

// Get the viewport
glGetIntegerv(GL_VIEWPORT, viewport);

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

// Apply perspective matrix
fAspect = (float)[self bounds].size.width / (float)[self bounds].size.height;
gluPerspective(35.0f, fAspect, 0.1f, 1000.0f);

glPopMatrix ();

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

// Clear the window with current clearing color
[self drawObjects];

glPopMatrix();

// Collect the hits
hits = glRenderMode(GL_RENDER);

// If a single hit occured, display the info.
if(hits == 1)
{
// does picking functions here
}
else
{
// does nothing
}
}
}

[/B][/QUOTE]

The program draws the objects as follows:
[CODE]
- (void)drawRect:(NSRect)bounds
{
// Draw the objects
GLint zeroOpacity = 0;
[[self openGLContext] setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
[[self window] setOpaque:NO];
[self resize];
[self renderObjects];
glFlush();
}

- (void)renderObjects
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);

// Save the matrix state
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// Camera
glTranslatef(xTrans, yTrans, zTrans);
if(scribeViewInfo == self && gTrackBallRotation[0] != 0.0f) // User is rotating the camera with the mouse
glRotatef(gTrackBallRotation[0], -gTrackBallRotation[1], gTrackBallRotation[2], -gTrackBallRotation[3]);
else // User is not rotating camera so use the standard world rotation
glRotatef(worldRotation[0], -worldRotation[1], worldRotation[2], -worldRotation[3]);
gluQuadricNormals(gluNewQuadric(), GLU_SMOOTH);

// Light values and coordinates
GLfloat whiteLight[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat sourceLight[] = {0.25f, 0.25f, 0.25f, 1.0f};
GLfloat diffuseLight[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat lightPos[] = {0.0f, -20.0f, 40.0f, 0.0f};

glEnable(GL_DEPTH_TEST); // Hidden surface removal
glFrontFace(GL_CCW); // Counter clock-wise polygons face out

// Enable lighting
glEnable(GL_LIGHTING);

// Setup and enable light
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, sourceLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_LIGHT0);

// Enable color tracking
glEnable(GL_COLOR_MATERIAL);

// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

[self drawObjects];
}

- (void)drawObjects
{
glPushMatrix();
// Objects are all drawn with their own glPushMatrix and glPopMatrix
glPopMatrix();

[/B][/QUOTE]

scratt
06-01-2009, 09:02 PM
Honestly, ditch that method for picking. It's deprecated in newer OpenGL versions, and it's inefficient.

Far better to wrap your objects up in a collision class like Coldet, which you can get from SourceForge.

And then use ray intersection picking on the CPU side using the following procedure..
http://www.opengl.org/resources/faq/technical/selection.htm

In the long run this is going to be far more flexible, use less GPU bandwidth, and not be out of date in the future...

:)

remdul
06-02-2009, 08:16 AM
Yes, the picking/selection mechanism in OpenGL is pretty much obsolete. I'm surprised it actually still works on most hardware, I would've imagined it be neglected by the vendors in their driver implementations (I imagine influence from CAD software vendors could explain this).

Anyway, you can also try color picking, which is done by encoding the object index to RGB color, rendering the objects, and reading back the color (glReadPixels) under the cursor. Then decode the RGB color to index.

However, that is not guaranteed to be foolproof, as the spec does not define pixel accurate results, and it fails in 16-bit display modes. Driver settings such as anti-aliasing and optimizations may also interfere.

The only 100% reliable way is to do the picking on the CPU.

topherreynoso
06-02-2009, 12:27 PM
Thanks guys, I'll get into it today! For those who are interested in learning anything about the methods that I have above though, just so you know, the problem was that you need to draw only those objects which are to be pickable instead of all of the objects in the scene, especially if one of your objects is a huge background that you DON'T want the user to be able to pick.