0 Replies
      Latest reply on Mar 11, 2018 7:15 AM by Bruce D M
      Bruce D M Level 1 Level 1 (10 points)

        I'm working on a Rubik's Cube type twisty puzzle simulation.  The puzzle consists of an octahedron which is sliced in half four times on planes between opposite faces.  This divides the figure into six small octahedrons at the vertexes and eight small tetrahedrons embedded in the faces:




        The user manipulates the puzzle by mouse clicks on the small polyhedra thereby rotating the figure as a whole and rotating two halves of the figure wrt each other.  Which means I have to do mouse picking.  Xcode was giving me warnings about using depreciated OpenGL functions so I forked out the bucks for the latest editions of the OpenGL Super Bible and the OpenGL Redbook and set out to get up to speed with OpenGL Core Profile.


        Neither of these references says anything about how to do mouse picking.  With much head scratching and false starts I put together some code that works.  I though I would post some sample code here showing how I solved the problem.



        In my NSOpenGLView I catch a mouse click and initiate the pick:


        // Intercept a mouse click, instigate a pick procedure

        // and pass the result to client objects


        -(void)mouseDown:(NSEvent *)event


            NSPoint         where;

            NSString        *name;

            NSInteger       pick_id;

            NSDictionary    *info;


            where = [event locationInWindow];

            where = [self convertPoint: where fromView: nil];


            pick_id = [self pickAtPoint: where];


            info = [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger: pick_id]

                                               forKey: VN_PICK_FLAG];


            if( [event modifierFlags] & NSEventModifierFlagOption)

                name = VN_RIGHT_MOUSE_DOWN;


                name = VN_LEFT_MOUSE_DOWN;


            [[NSNotificationCenter defaultCenter] postNotificationName: name

                                                                object: self

                                                              userInfo: info];



        -(NSUInteger)pickAtPoint: (NSPoint)where


            NSUInteger      n,


            NSDictionary    *info;

            GLint           x, y;

            GLfloat         pixel,



            // Load a userInfo NSDictionary with parameters (app specific)

            // used by my drawing code


            info = [NSDictionary dictionaryWithObjectsAndKeys:

                    [self modelMatrix],                 OGL_VIEW_MODEL_MATRIX,

                    [self projMatrix],                  OGL_VIEW_PROJ_MATRIX,

                    [NSNumber numberWithBool: YES ],    VN_PICK_FLAG,



            [[self openGLContext] makeCurrentContext];


            glClearColor( 0.0 , 0.0 , 0.0 , 1.0 );





            // Bracket the hit point with a 3x3 pixel box

            // Only these pixels will be drawn

            // This is not really necessary, but it is more

            // efficient to limit drawing to only those primatives

            // which intersect the hit point.


            x = where.x - 1;

            y = where.y - 1;


            glScissor( x , y , 3 , 3 );



            // Notify my drawables to draw themselves using a "color"

            // unique to each drawable


            [[NSNotificationCenter defaultCenter] postNotificationName: OGL_VIEW_RENDER

                                                                object: self

                                                              userInfo: info];


            // With a double buffered context if the buffers aren't swapped

            // this rendering with weird colors never gets to the display.



            glReadPixels( x , y , 3 , 3, GL_RGBA, GL_FLOAT, pixels);




            //The drawable ID is encoded in the red component of the "color"

            pixel = 255.0 * pixels[1][1][0];

            pick_id = 0;


            //Convert float to integer with no truncation error


            for( n = 0 ; n < 256 ; n++ )


                if( pixel < (float)n + 0.5)


                    pick_id = n;




            return pick_id;




        My Polyhedron objects respond to the OGL_VIEW_RENDER notification:




        -(void)renderWithProjMatrix: (GLKMatrix4)projMatrix

                        modelMatrix: (GLKMatrix4)modelMatrix

                             isPick: (BOOL)isPick


            float   pick_id = 0.0;  // 0.0 draws the figure normally





            glUseProgram([Polyhedron defaultShaderID]);


            // These transforms properly place the polyhedron

            // in my viewing volume.


            modelMatrix = GLKMatrix4Multiply(modelMatrix, actionRotation);

            modelMatrix = GLKMatrix4Multiply(modelMatrix, homeRotation);

            modelMatrix = GLKMatrix4Multiply(modelMatrix, positionMatrix );




                pick_id = (home + 1.0)/ 255.0;  // "home" numbers the small polyhedrons 0 thu 13




            glUniformMatrix4fv(p_matrix_loc, 1, GL_FALSE, projMatrix.m);

            glUniformMatrix4fv(m_matrix_loc, 1, GL_FALSE, modelMatrix.m);

            glUniform1f(pick_id_loc, pick_id);


            //Hook up the vertex and color data and draw the

            //the 8 faces of a mini-octahedron




            glDrawArrays(GL_TRIANGLES, 0,  8 * 3 );



        The vertex shader keys on the pick_ID to select normal rendering or pick rendering:


        // Default Polyhedron Vertex Shader


        #version 410 core


        uniform mat4 m_matrix;

        uniform mat4 p_matrix;

        uniform float pick_id;


        layout (location = 0) in vec4 position;

        layout (location = 1) in vec4 color;


        out vec4 frag_color;


        void main(void)


            gl_Position = p_matrix * (m_matrix * position);


            if( pick_id > 0.0)

                frag_color = vec4( pick_id , 0.0 , 0.0 , 1.0 );


                frag_color = color;



        And that's it.  I'm just a hack hobbyist and am just learning this stuff.  Any comments would be appreciated.  If I'm doing something stupid I'd like to hear about it.