LWJGL Forum

Programming => OpenGL => Topic started by: Wavewash on January 05, 2006, 22:09:56

Title: Picking Buffer always empty.
Post by: Wavewash on January 05, 2006, 22:09:56
I have been playing with picking for a few days now and have not been able to get it to work. I can get it so that the computer responds when my mouse is over geometry which is in the picking buffer but I cannot get a select buffer which has the numbers from the name stack in it.

The following is my selection code, basically cut and pasted from the Nehe lesson 32. Except for the rendering code is my own. I also removed the check to see whether the mouse is down before the selection is done. So it just does a constant check where ever the mouse is. The hit count actually increses when over geometry that I have defined but when I go to check the selection buffer it's empty and only prints out 0's. Since I am able to get an increase in hit count when over geometry I think that my picking projection matrix is set up properly . My only problem is getting the selection buffer to have information in it with the hit records.


private void selection() {                                            // This Is Where Selection Is Done
       int buffer[] = new int[512];                                        // Set Up A Selection Buffer
       int hits;                                               // The Number Of Objects That We Selected

       // The Size Of The Viewport. [0] Is <x>, [1] Is <y>, [2] Is <length>, [3] Is <width>

       int viewport[] = new int[4];

       // This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window
       IntBuffer temp = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer();
       temp.order();
       GL11.glGetInteger(GL11.GL_VIEWPORT, temp);
       temp.get(viewport);
       temp = ByteBuffer.allocateDirect(2048).asIntBuffer();
       GL11.glSelectBuffer(temp);                                // Tell OpenGL To Use Our Array For Selection
       temp.get(buffer);

       // Puts OpenGL In Selection Mode. Nothing Will Be Drawn.  Object ID's and Extents Are Stored In The Buffer.
       GL11.glRenderMode(GL11.GL_SELECT);

       GL11.glInitNames();                                              // Initializes The Name Stack
       GL11.glPushName(0);                                              // Push 0 (At Least One Entry) Onto The Stack

       GL11.glMatrixMode(GL11.GL_PROJECTION);                                // Selects The Projection Matrix
       GL11.glPushMatrix();                                             // Push The Projection Matrix
       GL11.glLoadIdentity();                                           // Resets The Matrix
       
       int mouse_x=Mouse.getX();
       int mouse_y=Mouse.getY();

       // This Creates A Matrix That Will Zoom Up To A Small Portion Of The Screen, Where The Mouse Is.
       GLU.gluPickMatrix((float) mouse_x, (float) (viewport[3] - mouse_y), 1.0f, 1.0f, viewport);

       // Apply The Perspective Matrix
       GLU.gluPerspective(45.0f, (float) (viewport[2] - viewport[0]) / (float) (viewport[3] - viewport[1]), 0.1f, 100.0f);
       GL11.glMatrixMode(GL11.GL_MODELVIEW);                                 // Select The Modelview Matrix
       
       
       GL11.glLoadIdentity();
       GL11.glLoadName(5);
       WUnit.setpos(0.0f, 0.0f, -2.0f);
       GL11.glColor3f(1.0f, 1.0f, 1.0f);
       WUnit.DrawTextBG();
       GL11.glColor3f(0.0f, 1.0f, 0.0f);
       WUnit.DrawText();
       
       GL11.glLoadIdentity();
       GL11.glLoadName(6);
       WUnit.setpos(1.0f, 0.0f, -2.0f);
       GL11.glColor3f(1.0f, 1.0f, 1.0f);
       WUnit.DrawTextBG();
       GL11.glColor3f(0.0f, 1.0f, 0.0f);
       WUnit.DrawText();
       
       
       
       GL11.glMatrixMode(GL11.GL_PROJECTION);                                // Select The Projection Matrix
       GL11.glPopMatrix();                                              // Pop The Projection Matrix
       GL11.glMatrixMode(GL11.GL_MODELVIEW);                                 // Select The Modelview Matrix
       hits = GL11.glRenderMode(GL11.GL_RENDER);                               // Switch To Render Mode, Find Out How Many
                                                                   // Objects Were Drawn Where The Mouse Was
       if(hits > 0) {                                               // If There Were More Than 0 Hits
           int choose = buffer[3];                                 // Make Our Selection The First Object
           int depth = buffer[1];                                  // Store How Far Away It Is

           for (int i = 1; i < hits; i++) {                // Loop Through All The Detected Hits
               // If This Object Is Closer To Us Than The One We Have Selected
               if (buffer[i * 4 + 1] < (int)depth) {
                   choose = buffer[i * 4 + 3];                      // Select The Closer Object
                   depth = buffer[i * 4 + 1];                       // Store How Far Away It Is
               }
           }
           
           System.out.println(choose);

       }
   }


Any help would be appreciated, thanks!
Title: Picking Possible Broken
Post by: Wavewash on February 11, 2006, 18:39:43
I've tried the Picking with LWJGL for awhile now. Has anyone gotten this to work? The Nehe picking demo translated over to LWJGL is broken so I have no way to verify that LWJGL is broken. Please let me know if you have got picking to working using GL11.glRenderMode(GL11.GL_SELECT);. Thanks
Title: Picking Buffer always empty.
Post by: Evil-Devil on February 14, 2006, 16:33:48
The last time i tried picking was as i translated the RedBook Picking example to lwjgl and IIRC it worked.
Title: Picking Buffer always empty.
Post by: seven_dc on February 15, 2006, 10:40:38
Quote from: "Evil-Devil"The last time i tried picking was as i translated the RedBook Picking example to lwjgl and IIRC it worked.
Care to share the source code with us?
Title: Picking Buffer always empty.
Post by: Wavewash on February 22, 2006, 05:36:18
Quote from: "seven_dc"
Quote from: "Evil-Devil"The last time i tried picking was as i translated the RedBook Picking example to lwjgl and IIRC it worked.
Care to share the source code with us?

Let's see if I can do the same. I'll post my code.

~Mo
Title: Picking Buffer always empty.
Post by: thirstynellan on February 27, 2006, 17:50:34
I, too, have had some troubles getting picking to work.  The sample code from the red book (in C) works just fine for me, but when I try to do picking in LWJGL, I get a null pointer exception when I call:
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);

According to the Eclipse debugger, the exception is occurring on line 1198 in GL11.java (version 0.99):
long function_pointer = GLContext.getCapabilities().GL11_glGetIntegerv_pointer;

Has anyone else seen this kind of thing before?

BTW, the previous entry in this thread said something about sample code being available, but I'm not sure where to find it.

Thanks in advance for any advice anyone could offer!
--Geoff
Title: hmmmmm...
Post by: Fool Running on February 27, 2006, 22:44:40
Make sure you call Display.Create() and are using OpenGL entirely in one thread. Those are the 2 most common causes of the null exception you are getting.
Title: Picking Buffer always empty.
Post by: darkprophet on February 27, 2006, 23:24:43
Quote
Make sure you call Display.Create() and are using OpenGL entirely in one thread.

Not unless your using CVS LWJGL, you can call Display.releaseContext() from the thread that did the Display.create(); and then call Display.makeCurrent(); on the rendering thread...But thats getting complicated :)

DP
Title: Picking Buffer always empty.
Post by: thirstynellan on March 03, 2006, 14:05:28
Ah... I was doing two things wrong that caused the NullPointerException:
(1) I was calling glGetInteger from outside the correct thread
(2) I was not allocating enough space in my IntBuffer to receive the result.
So now myprogram doesn't crash anymore.  :)

However, now I've run into the problem that started this thread in the first place; namely, the pick buffer comes up empty.  :?  Does anyone have some sample picking code in LWJGL that I could refer to?  There was some mentioned in an earlier post, but I'm not sure where to find it.

Thanks in advance for any input/guidance/wisdom you could offer!
--Geoff
Title: Picking Buffer always empty.
Post by: thirstynellan on March 03, 2006, 20:10:16
Eureka!  :D  I found out why my code was producing an empty picking buffer, and it's probably the same reason that Wavewash had trouble too.  Here's the analysis:

Notice that in his code (I use masculine pronouns for convenience), he's using passing an IntBuffer object to glSelectBuffer() as mandated by LWJGL. He then immediately puts the contents of the IntBuffer into an int array, and then uses that array in the picking-evaluation code.  However, OpenGL is writing the contents of the pick buffer to the original IntBuffer object, *not* to the int array.  Wavewash should change his code to read the pick buffer from the IntBuffer directly; or at least copy the IntBuffer into an array *after* glRenderMode(GL_RENDER) returns.

Thoughts?  Does that make sense?  Or did I misunderstand the issue?

--Geoff
Title: Re: Picking Buffer always empty.
Post by: laDanz on January 17, 2007, 10:34:22
*up*

has anyone a working solution on the problem???

i 'll find it great if you could post the code

Thanxxx ...
Title: Re: Picking Buffer always empty.
Post by: laDanz on January 22, 2007, 08:24:54
*up*
::)
Title: Re: Picking Buffer always empty.
Post by: amoeba on August 11, 2007, 23:16:35
I am trying to get this picking working. I am registering hits correctly, but cant seem to get the pick buffer working correctly.

The whole intbuffer confuses me (why do we have to use this), but I am using the NeHe picking demo code (http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=32) LWJGL port code. I cant get the port working - assume it is broken. The author is Mark Bernard, date: 07-Sept-2004.

Are there any working demo's/tutorials/examples please?
Title: Re: Picking Buffer always empty.
Post by: amoeba on August 14, 2007, 20:31:34
Right, after THREE years (I gave up 3 years ago!) I have finally got it working!

It looks to me like a fundemental problem with the IntBuffer code;


    int buffer[] = new int[256];  // Set Up A Selection Buffer
    IntBuffer temp = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer();
    temp.order();
    GL11.glGetInteger(GL11.GL_VIEWPORT, temp);
    temp.get(viewport);
//    temp = ByteBuffer.allocateDirect(1024).asIntBuffer();
    temp = ByteBuffer.allocateDirect(1024).order(ByteOrder.nativeOrder()).asIntBuffer();
    GL11.glSelectBuffer(temp); // Tell OpenGL To Use Our Array For Selection
    //temp.get(buffer);


So as you can see, I have changed the 2nd initialising of the temp IntBuffer. I also commented out the final temp.get(buffer), and moved it way down to immediately before I check the buffer for testing - i.e. after all rendering.

This seems to work for me - anyone wanting more information give me a private msg.
Title: Re: Picking Buffer always empty.
Post by: yahivin on September 08, 2007, 19:31:00
I spent all day trying to get picking and no one had posted a working code sample for LWJGL, so I figure I can save others some time.

Picking Test:

/*
* Copyright (c) 2002-2004 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
*   notice, this list of conditions and the following disclaimer in the
*   documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
*   its contributors may be used to endorse or promote products derived
*   from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* PickingTest.java
* This was modified from some example code on LWJGL sample and forums code.
* Created on Sep 6, 2007, 4:00:20 PM
*/

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.glu.GLU;

/**
*
* @author tomu
*/

public class PickingTest {
/** The normal title of the window */
private String WINDOW_TITLE = "Picking Test";

/** The width of the game display area */
private int width = 800;

/** The height of the game display area */
private int height = 600;

/** The time at which the last rendering looped started from the point of view of the game logic */
private long lastLoopTime = getTime();

/** The time since the last record of fps */
private long lastFpsTime = 0;

/** The recorded fps */
private int fps;

private static long timerTicksPerSecond = Sys.getTimerResolution();

private boolean lastMouseDown = false;

      /** Creates a new instance of Main */
      public PickingTest() {
initialize();
      }

      /**
       * @param args the command line arguments
       */
      public static void main(String[] args) {
new PickingTest().execute();
      }

private void execute() {
try {
gameLoop();
} catch(Exception ex) {
ex.printStackTrace();
} finally {
Display.destroy();
}
}

/**
* Run the main game loop. This method keeps rendering the scene
* and requesting that the callback update its screen.
*/
private void gameLoop() {
while (Game.gameRunning) {
// Game Logic
gameLogic();

// Game Rendering
// clear screen
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
DrawEntities();

// update window contents
Display.update();
}
}
/**
* Notification that a frame is being rendered. Responsible for
* running game logic and rendering the scene.
*/
public void gameLogic() {
int mx = Mouse.getX(), my = Mouse.getY();

//SystemTimer.sleep(lastLoopTime+10-SystemTimer.getTime());
Display.sync(60);

// work out how long its been since the last update, this
// will be used to calculate how far the entities should
// move this loop
long delta = getTime() - lastLoopTime;
lastLoopTime = getTime();
lastFpsTime += delta;
fps++;

// update our FPS counter if a second has passed
if (lastFpsTime >= 1000) {
Display.setTitle(WINDOW_TITLE + " (FPS: " + fps + "; mx: "+mx+"; my: "+my+")");
lastFpsTime = 0;
fps = 0;
}

// Selection Magic
if(Mouse.isButtonDown(0) && !lastMouseDown) {
selection(mx, my);
}

lastMouseDown = Mouse.isButtonDown(0);

// if escape has been pressed, stop the game
if (Display.isCloseRequested() || Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
Game.gameRunning = false;
}
}

/**
* Intialise the common elements for the game
*/
public void initialize() {
// initialize the window beforehand
try {
setDisplayMode();
Display.setTitle(WINDOW_TITLE);
Display.setFullscreen(false);
Display.create();
     
// Allow cursor to appear
Mouse.setGrabbed(false);

GL11.glDepthRange(0.0, 1.0);

GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();

GL11.glOrtho(0, 8, 0, 8, -0.5, 2.5);


} catch (LWJGLException le) {
System.out.println("Game exiting - exception in initialization:");
le.printStackTrace();
Game.gameRunning = false;
return;
}
}
/**
* Sets the display mode for fullscreen mode
*/
private boolean setDisplayMode() {
    try {
// get modes
DisplayMode[] dm = org.lwjgl.util.Display.getAvailableDisplayModes(width, height, -1, -1, -1, -1, 60, 60);

org.lwjgl.util.Display.setDisplayMode(dm, new String[] {
    "width=" + width,
    "height=" + height,
    "freq=" + 60,
    "bpp=" + org.lwjgl.opengl.Display.getDisplayMode().getBitsPerPixel()
   });

return true;

    } catch (Exception e) {
e.printStackTrace();
System.out.println("Unable to enter fullscreen, continuing in windowed mode");
    }

return false;
}

/**
* Get the high resolution time in milliseconds
*
* @return The high resolution time in milliseconds
*/
public static long getTime() {
// we get the "timer ticks" from the high resolution timer
// multiply by 1000 so our end result is in milliseconds
// then divide by the number of ticks in a second giving
// us a nice clear time in milliseconds
return (Sys.getTime() * 1000) / timerTicksPerSecond;
}

      /**
       *
       */
      private void DrawEntities() {
            // cycle round drawing all the entities we have in the game
            GL11.glLoadName(1);
            GL11.glBegin(GL11.GL_QUADS);
            GL11.glColor3f(1.0f, 1.0f, 0.0f);
            GL11.glVertex3i(2, 0, 0);
            GL11.glVertex3i(2, 6, 0);
            GL11.glVertex3i(6, 6, 0);
            GL11.glVertex3i(6, 0, 0);
            GL11.glEnd();

            GL11.glLoadName(2);
            GL11.glBegin(GL11.GL_QUADS);
            GL11.glColor3f(0.0f, 1.0f, 1.0f);
            GL11.glVertex3i(3, 2, -1);
            GL11.glVertex3i(3, 8, -1);
            GL11.glVertex3i(8, 8, -1);
            GL11.glVertex3i(8, 2, -1);
            GL11.glEnd();

            GL11.glLoadName(3);
            GL11.glBegin(GL11.GL_QUADS);
            GL11.glColor3f(1.0f, 0.0f, 1.0f);
            GL11.glVertex3i(0, 2, -2);
            GL11.glVertex3i(0, 7, -2);
            GL11.glVertex3i(5, 7, -2);
            GL11.glVertex3i(5, 2, -2);
            GL11.glEnd();
      }

      /**
       * The selection magic happens here.
       * @param mouse_x
       * @param mouse_y
       */
      private void selection(int mouse_x, int mouse_y) {
// The selection buffer
IntBuffer selBuffer = ByteBuffer.allocateDirect(1024).order(ByteOrder.nativeOrder()).asIntBuffer();
int buffer[] = new int[256];

IntBuffer vpBuffer = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder()).asIntBuffer();
// The size of the viewport. [0] Is <x>, [1] Is <y>, [2] Is <width>, [3] Is <height>
            int[] viewport = new int[4];

// The number of "hits" (objects within the pick area).
int hits;

// Get the viewport info
            GL11.glGetInteger(GL11.GL_VIEWPORT, vpBuffer);
            vpBuffer.get(viewport);

// Set the buffer that OpenGL uses for selection to our buffer
GL11.glSelectBuffer(selBuffer);

// Change to selection mode
GL11.glRenderMode(GL11.GL_SELECT);

// Initialize the name stack (used for identifying which object was selected)
GL11.glInitNames();
GL11.glPushName(0);


GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
GL11.glLoadIdentity();

/*  create 5x5 pixel picking region near cursor location */
GLU.gluPickMatrix( (float) mouse_x, (float) mouse_y, 5.0f, 5.0f, viewport);

GL11.glOrtho(0.0, 8.0, 0.0, 8.0, -0.5, 2.5);
DrawEntities();
GL11.glPopMatrix();

// Exit selection mode and return to render mode, returns number selected
hits = GL11.glRenderMode(GL11.GL_RENDER);
System.out.println("Number: " + hits);

selBuffer.get(buffer);
            // Objects Were Drawn Where The Mouse Was
            if (hits > 0) {
                  // If There Were More Than 0 Hits
                  int choose = buffer[3]; // Make Our Selection The First Object
                  int depth = buffer[1]; // Store How Far Away It Is
                  for (int i = 1; i < hits; i++) {
                        // Loop Through All The Detected Hits
// If This Object Is Closer To Us Than The One We Have Selected
                        if (buffer[i * 4 + 1] < (int) depth) {
                              choose = buffer[i * 4 + 3]; // Select The Closer Object
                              depth = buffer[i * 4 + 1]; // Store How Far Away It Is
                        }
                  }

                  System.out.println("Chosen: " + choose);
            }
}
           
}


There may be a small bug with the layering, let me know if this is helpful or if you have any suggestions.
Title: Re: Picking Buffer always empty.
Post by: Del on February 24, 2009, 10:26:12
I changed
    //create 5x5 pixel picking region near cursor location
             GLU.gluPickMatrix( (float) mouse_x, (float) mouse_y, 5.0f, 5.0f, viewport);


to

            //create 5x5 pixel picking region near cursor location
            GLU.gluPickMatrix( (float) mouse_x, (float) mouse_y, 5.0f, 5.0f,IntBuffer.wrap(viewport));

To get the last example to work. It was either incorrect code before or a change in GLU.gluPickMatrix since the lastest lwjgl version?

Is this the correct way of solving this?

Thanks, Del

Edit -
Also, would this be a good way to detect what I've hit, in say a first person shooter if mouse x and y where just switch with the crosshair's x and y(center of screen in most cases)?
Title: Re: Picking Buffer always empty.
Post by: manji on April 29, 2009, 10:32:44
Thank you all very much for your comments and source! They have been very helpful for me, and picking works like a charm now.

@Del: I had the same problem and the solution you gave suits me fine.