Picking/selection

Does anyone have an example of picking/selection?

For the life of me I can’t seem to get the simple one off NeHe (lesson 32) to work (of course I’m only taking snippets of the C code and placing them in my Java/JOGL code, so perhaps I’m missing something. I’m almost at hte point of converting the whole thing to JOGL. I’m sure my employer is happy for me to do that! :slight_smile: ).

Following on from this, do people generally use GL picking for object selection in applications with potentially thousands of objects or do they manage it internally with B-Tree style mapping for example?

Thanks for any advice.

Greg.

Greg,

I am stuck here too.

Be sure to update to build 1.1.0-b06
There is a fix to glPickMatrix (or related code) mentioned in this build’s updates.

At the same time, b06 broke something else that I have to fix so I had to take a step back.

Mitch

Interestingly I’m also finding that the glGetIntegerv(GL.GL_VIEWPORT, <my int[4] variable>) doesn’t work.

It doesn’t seem to write to the into the variable. Quite strange. I’ve had to manually hack the values into the array for the screen pos/width/height, but it didn’t help.

Greg.

Are you doing all of your GL calls within your GLEventListener’s init(), display(), and other callbacks?

Picking and selection via the OpenGL selection buffer definitely work in JOGL. Here’s an example from our JavaOne 2004 talk, originally authored by Thomas Bladh.


//=================================================================================
// Picking 0.2                                                       (Thomas Bladh)
//=================================================================================
// A simple picking example using java/jogl. This is far from a complete solution 
// but it should give you an idea of how to include picking in your assigment 
// solutions.
//
// Notes: * Based on example 13-3 (p 542) in the "OpenGL Programming Guide"
//        * This version should handle overlapping objects correctly.
//---------------------------------------------------------------------------------
import java.awt.*;
import java.awt.event.*;
import java.awt.Canvas.*;
import java.nio.*;
import java.util.*;
import net.java.games.jogl.*;
import net.java.games.jogl.util.*;

class Picking
{
      public static void main(String[] args) 
      {
               new Picking();
        }
        
        Picking()
        {
            Frame frame = new Frame("Picking Example");
            GLDrawableFactory factory = GLDrawableFactory.getFactory();
            GLCapabilities capabilities = new GLCapabilities();
            GLCanvas drawable = factory.createGLCanvas(capabilities);
            drawable.addGLEventListener(new Renderer());
                frame.add(drawable);
            frame.setSize(400, 400);
            final Animator animator = new Animator(drawable);
                frame.addWindowListener(new WindowAdapter()
               {
                         public void windowClosing(WindowEvent e) 
                         {
                               animator.stop();
                               System.exit(0);
                         }
               });
                frame.show();
                animator.start();      
        }

      static class Renderer implements GLEventListener, MouseListener, MouseMotionListener 
        {
            static final int NOTHING = 0, UPDATE = 1, SELECT = 2;
            int cmd = UPDATE;
            int mouse_x, mouse_y;
      
                private GL gl;
            private GLU glu;
                private GLDrawable gldrawable;
            
            public void init(GLDrawable drawable) 
                {
                        gl = drawable.getGL();
                  glu = drawable.getGLU();
                        this.gldrawable = drawable;
                        gl.glEnable(GL.GL_CULL_FACE);
                        gl.glEnable(GL.GL_DEPTH_TEST);
                        gl.glEnable(GL.GL_NORMALIZE);
                  gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                    drawable.addMouseListener(this);
                        drawable.addMouseMotionListener(this);
                }
          
                public void reshape(GLDrawable drawable, int x, int y, int width, int height) 
                {
                  
                  float h = (float) height / (float) width;
                  gl.glViewport(0, 0, width, height);
                        gl.glMatrixMode(GL.GL_PROJECTION);
                    gl.glLoadIdentity();
                  glu.gluOrtho2D(0.0f,1.0f,0.0f,1.0f);
                }

                public void display(GLDrawable drawable) 
                {
                  switch(cmd)
                  {
                        case UPDATE:
                              drawScene();
                              break;
                        case SELECT:
                              int buffsize = 512;
                              double x = (double) mouse_x, y = (double) mouse_y;
                              int[] viewPort = new int[4];
                                        IntBuffer selectBuffer = BufferUtils.newIntBuffer(buffsize);
                                  int hits = 0;
                              gl.glGetIntegerv(GL.GL_VIEWPORT, viewPort);
                                    gl.glSelectBuffer(buffsize, selectBuffer);
                                  gl.glRenderMode(GL.GL_SELECT);
                              gl.glInitNames();
                                  gl.glMatrixMode(GL.GL_PROJECTION);
                                 gl.glPushMatrix();
                                  gl.glLoadIdentity();
                                  glu.gluPickMatrix(x, (double) viewPort[3] - y, 5.0d, 5.0d, viewPort);
                                glu.gluOrtho2D(0.0d, 1.0d, 0.0d, 1.0d);
                              drawScene();
                              gl.glMatrixMode(GL.GL_PROJECTION);
                              gl.glPopMatrix();
                              gl.glFlush();
                                  hits = gl.glRenderMode(GL.GL_RENDER);
                              processHits(hits, selectBuffer);
                              cmd = UPDATE;
                              break;
                  }
            }

            public void processHits(int hits, IntBuffer buffer)
            {
                  System.out.println("---------------------------------");
                  System.out.println(" HITS: " + hits);
                  int offset = 0;
                  int names;
                  float z1, z2;
                  for (int i=0;i<hits;i++)
                  {
                        System.out.println("- - - - - - - - - - - -");
                        System.out.println(" hit: " + (i + 1));
                        names = buffer.get(offset); offset++;
                        z1 = (float) buffer.get(offset) / 0x7fffffff; offset++;
                        z2 = (float) buffer.get(offset) / 0x7fffffff; offset++;
                        System.out.println(" number of names: " + names);
                        System.out.println(" z1: " + z1);
                        System.out.println(" z2: " + z2);
                        System.out.println(" names: ");

                        for (int j=0;j<names;j++)
                        {
                              System.out.print("       " + buffer.get(offset)); 
                              if (j==(names-1))
                                    System.out.println("<-");
                              else
                                    System.out.println();
                              offset++;
                        }
                        System.out.println("- - - - - - - - - - - -");
                  }
                  System.out.println("---------------------------------");
            }
            
            public int viewPortWidth()
            {
                  int[] viewPort = new int[4];
                  gl.glGetIntegerv(GL.GL_VIEWPORT, viewPort);
                  return viewPort[2];
            }

            public int viewPortHeight()
            {
                  int[] viewPort = new int[4];
                  gl.glGetIntegerv(GL.GL_VIEWPORT, viewPort);
                  return viewPort[3];
            }

            public void drawScene()
            {
                  gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

                  // Colors
                        float red[] =   {1.0f,0.0f,0.0f,1.0f};
                        float green[] = {0.0f,1.0f,0.0f,1.0f};
                        float blue[] =  {0.0f,0.0f,1.0f,1.0f};
      
                  // Red rectangle
                  GLRectangleEntity r1 = new GLRectangleEntity(gl, glu);
                  r1.x = 0.15f;
                  r1.y = 0.25f;
                  r1.w = 0.4f;
                  r1.h = 0.4f;
                  r1.c = red;
                  r1.id = 10;
                  r1.draw();

                  // Green rectangle
                  GLRectangleEntity r2 = new GLRectangleEntity(gl, glu);
                  r2.x = 0.35f;
                  r2.y = 0.45f;
                  r2.w = 0.4f;
                  r2.h = 0.4f;
                  r2.c = green;
                  r2.id = 20;
                  r2.draw();

                  // Blue rectangle
                  GLRectangleEntity r3 = new GLRectangleEntity(gl, glu);
                  r3.x = 0.45f;
                  r3.y = 0.15f;
                  r3.w = 0.4f;
                  r3.h = 0.4f;
                  r3.c = blue;
                  r3.id = 30;
                  r3.draw();

                  gl.glFlush();
            }

            public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
                        
                public void mousePressed(MouseEvent e) 
            {
                  cmd = SELECT;
                  mouse_x = e.getX();
                  mouse_y = e.getY();
            }

            public void mouseEntered(MouseEvent e) {}
                public void mouseExited(MouseEvent e) {}
                public void mouseReleased(MouseEvent e) {}
                public void mouseClicked(MouseEvent e) {}
                public void mouseDragged(MouseEvent e) {}
                public void mouseMoved(MouseEvent e) {}
    
            public abstract class GLEntity
            {
                  float x, y, z;
                  float[] c;
                  int id = 0;
                  boolean outline = false;
                  GL gl;
                  GLU glu;
                  public GLEntity(GL gl, GLU glu)
                  {
                        this.gl = gl;
                        this.glu = glu;
                  }
                  public void draw()
                  {
                        gl.glPushName(id);
                        _draw();
                  }
                  public abstract void _draw();
            }

            public class GLRectangleEntity extends GLEntity
            {
                  float w = 0.1f;
                  float h = 0.1f;
                  public GLRectangleEntity(GL gl, GLU glu)
                  {
                        super(gl, glu);
                  }
                  public void _draw()
                  {
                        if (outline)
                              gl.glPolygonMode(GL.GL_FRONT, GL.GL_LINE);
                        else
                              gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);

                        gl.glColor4fv(c);
                        gl.glBegin(GL.GL_POLYGON);
                              gl.glVertex3f(x, y, z);
                              gl.glVertex3f(x + w, y, z);
                              gl.glVertex3f(x + w, y + h, z);
                              gl.glVertex3f(x, y + h, z);
                        gl.glEnd();
                  }                  
            }
      }
}

Thanks for the demo code Ken. In answer to your question, no I wasn’t doing the selection stuff in the display() method. I was doing it in another method that was triggered on mouse selection.
Once I moved the code into the display method all was well. :slight_smile:

However, I’ve now remembered however that I have a requirement to have a small (~2) pixel “buffer” around my objects that still triggers selection. I assume that GL’s selection buffer works to exact dimensions, which in a way rules this method out for me.

I guess the big question is, do you recommend I stick with the GL picking, or should I implement my own quad-tree (for example) selection myself?

gluPickMatrix should probably do what you want.

However, in general I recommend implementing application-level selection. Most applications have to manage objects’ transforms explicitly anyway, and it’s easier to extract the data you need if you implement picking on top of that.