Color picking in GLJPanel

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Color picking in GLJPanel

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 );

                        }

                });
        }
}
Reply | Threaded
Open this post in threaded view
|

Re: Color picking in GLJPanel

gouessej
Administrator
Hey

Please use JOGL 2.3.2 as we maintain only the latest version.

I'm not sure that you can work around this issue. Please use the system property jogl.gljpanel.noglsl very early.

By the way, the color picking doesn't work on computers using emulated palettes.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: Color picking in GLJPanel

copeg
Thanks for the advice. I've moved to the latest version (same issue). Thus far, couldn't come up with a workaround. As a result, I've implemented another picking method in place of the color approach that relies on conversion of screen to world coordinates. So far works