Reply – Color picking in GLJPanel
Your Name
Subject
Message
or Cancel
In Reply To
Color picking in GLJPanel
— by copeg copeg
Trying to implement picking using the color based approach - render each unique object's primitives as a unique color. Disable autoswap of the component, then when picking render the unique colors to the back buffer and use glReadPixels of the back buffer to get the color under the mouse without swapping the buffer. The issue arises when I use a Swing GLJPanel - the back buffer gets rendered during the picking phase eg the unique colors are rendered onto the JPanel (rather than rendered to the back buffer and not seen again).

JOGL 2.3.1, Windows 7

Demo below with triangle (click on the triangle as see the green picking color). Any ideas? FWIW this works with a GLCanvas, but would very much like to avoid using a heavyweight component in my application



import java.awt.Color;
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.lang.reflect.InvocationTargetException;
import java.nio.FloatBuffer;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLJPanel;

/**
 * Demo program to demonstrate clearing upon rotation
 * @author Greg Cope
 *
 */
public class SwingJOGLRotationClear implements GLEventListener {

        final GLProfile profile = GLProfile.get( GLProfile.GL2 );
        GLCapabilities capabilities = new GLCapabilities( profile );
        {
                capabilities.setDoubleBuffered(true);
                capabilities.setSampleBuffers(true);
                capabilities.setFBO(true);
        }

        // The canvas
        final GLJPanel glcanvas = new GLJPanel( capabilities ){
                @Override
                public void swapBuffers(){
                        //Log when buffers are swapped
                        System.out.println("Swapping buffers");
                        super.swapBuffers();
                }
        };
       
        private Point mouseDownPoint = null;
        public static DisplayMode dm, dm_old;
        private float rquad = 0.0f;

        private volatile boolean picking = false;
        private MouseEvent pickingEvent = null;

        private int glWidth = -1;
        private int glHeight = -1;

        @Override
        public void display( GLAutoDrawable drawable ) {
               
                System.out.println("Rendering: " + picking);
                final GL2 gl = drawable.getGL().getGL2();  
                gl.glMatrixMode( GL2.GL_MODELVIEW );
                gl.glLoadIdentity();

                gl.glClearColor(0f, 0f, 0f, 0f);
                gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT );
               
                gl.glEnable(GL2.GL_LIGHTING);
                gl.glEnable(GL2.GL_DEPTH_TEST);
                gl.glEnable(GL2.GL_LIGHTING);
                gl.glEnable(GL2.GL_LIGHT0);
                gl.glEnable(GL2.GL_NORMALIZE);
                gl.glDisable(GL2.GL_CULL_FACE);

               
                float[] position = new float[]{0f,0f,50f,0f};
                float[] ambient = new float[]{ 0.1f,0.1f,0.1f,0f};
                float[] diffuse = new float[]{ 0.9f,0.9f,0.9f,0f };
                float[] specular = new float[]{ 0.5f,0.5f,0.5f,0f };

                gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, position, 0);
                gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_AMBIENT, ambient, 0);
                gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_DIFFUSE, diffuse, 0);
                gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_SPECULAR, specular, 0);

                float[] spec = new float[]{1f,1f,1f};
                gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, spec, 0);
                gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, 100);
                gl.glEnable(GL2.GL_LIGHTING);
               
                if ( picking ){
                        System.out.println("drawing to back buffer");
                        gl.glDrawBuffer(GL2.GL_BACK);
                        gl.glDisable(GL2.GL_LIGHTING);
                        gl.glColor3f(0f,1f,0f);
                }else{
                        gl.glColor3f(1f,0f,0f);
                }
                float z = -1.5f;
                gl.glTranslated(0, 0, z);
                gl.glRotatef(rquad, 0f, 1f, 0f);//1.0f, 1.0f, 1.0f);
                gl.glTranslated(0, 0, -z);
               
                float[] mat = new float[]{1f,0,0,1f};
                gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_DIFFUSE, mat, 0);
                gl.glNormal3f(0,0,1);
                gl.glBegin(GL2.GL_TRIANGLES);
                gl.glVertex3f(-1f, 0, z);
                gl.glVertex3f(0f,1f, z);
                gl.glVertex3f(1f,0f,z);
                gl.glEnd();

               
 
                if ( picking ){
                        System.out.println("Picking from back buffer");;
                        FloatBuffer pixels = FloatBuffer.allocate(4);
                        gl.glReadBuffer(GL2.GL_BACK);
                        gl.glReadPixels(pickingEvent.getX(), glHeight - pickingEvent.getY(),
                                        1, 1, GL2.GL_RGBA, GL2.GL_FLOAT, pixels);
                        Color color = new Color(pixels.get(0), pixels.get(1), pixels.get(2));
                        System.out.println("Pickied color: " + color);
                        picking = false;
                }else{
                        drawable.swapBuffers();
                }
               
        }

        @Override
        public void dispose( GLAutoDrawable drawable ) {
        }

        @Override
        public void init( GLAutoDrawable drawable ) {
                glcanvas.setAutoSwapBufferMode(false);
                final GL2 gl = drawable.getGL().getGL2();
                gl.glShadeModel( GL2.GL_SMOOTH );
                gl.glClearColor( 0f, 0f, 0f, 0f );
                gl.glClearDepth( 1.0f );
                gl.glShadeModel( GL2.GL_SMOOTH );
                gl.glEnable( GL2.GL_DEPTH_TEST );
                gl.glDepthFunc( GL2.GL_LEQUAL );
                gl.glHint( GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST );
        }

        @Override
        public void reshape( GLAutoDrawable drawable, int x, int y, int width, int height ) {

                final GL2 gl = drawable.getGL().getGL2();
                if( height <= 0 )
                        height = 1;

                glWidth = width;
                glHeight = height;
                gl.glViewport( 0, 0, width, height );
                gl.glMatrixMode( GL2.GL_PROJECTION );
                gl.glLoadIdentity();
                gl.glFrustum(-1, 1, -1, 1,1, 100);
        }

        public static void main( String[] args ) throws InvocationTargetException, InterruptedException {

                SwingUtilities.invokeAndWait(new Runnable(){

                        @Override
                        public void run() {

                                final SwingJOGLRotationClear demo = new SwingJOGLRotationClear();
                                demo.glcanvas.setAutoSwapBufferMode(false);//disable auto swap
                                /*
                                 * Listeners for draggin
                                 */
                                demo.glcanvas.addMouseListener(new MouseAdapter(){
                                        @Override
                                        public void mousePressed(MouseEvent e){
                                                demo.mouseDownPoint = e.getPoint();
                                                demo.pickingEvent = e;
                                        }
                                        @Override
                                        public void mouseClicked(MouseEvent e){
                                                demo.picking = true;
                                                demo.glcanvas.repaint();
                                        }
                                });
                                demo.glcanvas.addMouseMotionListener(new MouseMotionAdapter(){
                                        @Override
                                        public void mouseDragged(MouseEvent e){
                                                demo.rquad += demo.mouseDownPoint.getX() - e.getX();
                                                demo.mouseDownPoint = e.getPoint();
                                                demo.glcanvas.repaint();
                                        }
                                });


                                demo.glcanvas.addGLEventListener( demo );
                                demo.glcanvas.setPreferredSize( new Dimension(400, 400) );

                                final JFrame frame = new JFrame ( "Demo" );
                                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                                frame.getContentPane().add( demo.glcanvas );
                                frame.setSize( frame.getContentPane().getPreferredSize() );
                                frame.setVisible( true );

                        }

                });
        }
}