Picking catastrophe

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.

[b]
- (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]
[/b][/QUOTE]

The program draws the objects as follows:

[b]

  • (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]
    [/b][/QUOTE]

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…

:slight_smile:

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.

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.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.