Collision/intersection help

Hi,

Im trying to do some simple picking.

Ive got a number of different objects, spheres/triangles and some oddly shaped objects. Given a 3d vector i want to know the 3d locations where the vector intersects any of the objects. For example from location 0,0,0 looking at direction 1,1,1 at what x,y,z location (if any) does this vector intersect my teapot.

Ive tried using GL_SELECT but that doesn’t give me x,y,z locations where a ray would intersect.

Thanks for your help

The best way is just to do all the calculations on the CPU. Just mathematically check if your ray is intersecting anything.

The second way is “easier”, but costs a lot of performance and doesn’t tell you which object the ray is intersecting with, only where the ray intersected. There’s a convenient function in GLU which allows you to do the OpenGL transformations “backwards”, meaning that if you have the screen coordinates and the scene depth of a pixel it will give you the 3D world space coordinates of that pixel. The problem is acquiring the depth value, which forces the CPU to wait for the GPU to finish rendering, which then forces the GPU to wait because it doesn’t have any other commands. Anyway, I just copy-pasted this code from somewhere so I don’t take credit for it (but it does work):


    private FloatBuffer getMousePosition(int mouseX, int mouseY) {
        IntBuffer viewport = BufferUtils.createIntBuffer(16);
        FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
        FloatBuffer projection = BufferUtils.createFloatBuffer(16);
        FloatBuffer winZ = BufferUtils.createFloatBuffer(1);
        FloatBuffer position = BufferUtils.createFloatBuffer(3);

        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);

        GL11.glReadPixels(mouseX, mouseY, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, winZ);

        if (winZ.get(0) == 1) {
            return null;
        }

        GLU.gluUnProject(mouseX, mouseY, winZ.get(), modelview, projection, viewport, position);

        return position;
    }

Hi

You can use OpenGL picking to get this kind of information, you have to analyse the hits correctly. There is an example here:
http://jogamp.org/jogl-demos/src/demos/misc/Picking.java

I advise you to have a look at the manual of the method glSelectBuffer to understand the hit contents:
http://www.opengl.org/sdk/docs/man/xhtml/glSelectBuffer.xml

The use of OpenGL picking is discouraged according to the OpenGL FAQ, I agree with the first sentence of the previous post (thanks theagentd).

Edit.: replace BufferUtils.createFloatBuffer() by Buffers.newDirectFloatBuffer(), do the same thing for int NIO buffers. Rather use drawable.getGL().getGL2() or GL2 instead of GL11, replace GLU by “new GLUgl2()” and it should work.

Oh, this was in the JOGL Development section… T__T Sorry…

@theagentd

i used the following instead which seemed to compile for me:

    private DoubleBuffer getMousePosition(int mouseX, int mouseY, GL GL11) {
        
        IntBuffer viewport = BufferUtil.newIntBuffer(16);
        DoubleBuffer modelview = BufferUtil.newDoubleBuffer(16);
        DoubleBuffer projection = BufferUtil.newDoubleBuffer(16);
        DoubleBuffer winZ = BufferUtil.newDoubleBuffer(1);
        DoubleBuffer position = BufferUtil.newDoubleBuffer(3);


        GL11.glGetDoublev(GL11.GL_MODELVIEW_MATRIX, modelview);
        GL11.glGetDoublev(GL11.GL_PROJECTION_MATRIX, projection);
        GL11.glGetIntegerv(GL11.GL_VIEWPORT, viewport);

        GL11.glReadPixels(mouseX, mouseY, 1, 1, GL11.GL_DEPTH_COMPONENT, GL11.GL_DOUBLE, winZ);

        if (winZ.get(0) == 1) {
            return null;
        }

        glu.gluUnProject((double)mouseX, (double)mouseY, (double)winZ.get(0), modelview, projection, viewport, position);


        System.out.println(position.get(0)+" "+position.get(1)+" "+position.get(2)+" "+winZ.get(0));
    
        return position;
    }

Thanks for your reply man but it didn’t give me the correct z positions. I had a simple sphere, and used a mouse click coordinates to run the getMousePosition method, however it only ever returned winZ as 0 (converting to a projection.get(2) of 0.5 for everything). Whereas i want to know the different z-values for different parts of the sphere.

@gouessej

Ive been trying to use openGL picking but have been getting depth-values of like 1578192816 and even after reading about glSelectBuffer I still don’t know how to turn this into a z-coordinate. I know to divide by 2^31 but even then im not sure what it means.

@Matt878
Like Gouessej pointed out the code I posted was for LWJGL but you’re using JOGL which has the OpenGL functions organized a little differently. Since the OpenGL functions are in the GL variable you have to use it instead of the static GL11 of LWJGL. The code is a simple port to JOGL of the function I posted which simply names the GL object you have GL11 so that everything compiles without any changes. Again, sorry about that.

If you get weird depth values make sure what you’re reading is correct. The correct use of this method would be something like this:


gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
drawAllObjects(gl);
DoubleBuffer pos = getMousePosition(mouseX, mouseY, gl);
doStuffWithThe3DMousePos(pos);
draw2DStuffLikeUI(gl);

Also make sure that depth testing and writing is working properly, that glClearDepth has a good value (should be 1.0 in 99% of all cases) and that your projection matrix is set up properly.

Yea thats how I was using it but I would like to get the 3d coordinate of the object im picking, instead it seems to just give the 3d coordinates of my mouse.

I think i may just rely on manually casting a ray and seeing what it intersects (unforunately wont work for complex objects), though I thought there would be a simple way to do this.

This method just gets the 3D coordinates of your mouse, which I explained in my first post…

In the end I think what you really want is just plain picking, but I have no experience at all with. Try to read up on the links Gouessej posted.

It’s possible to emulate picking by for example writing an object ID to the alpha channel of the screen buffer. Instead of reading back depth, you’d read back the alpha component instead and use that value to determine which object was clicked on. Using the alpha channel limits you to 255 different objects (0 would be reserved for no object), but this can be worked around if you really want by using a separate pass or using multiple render targets.

Right, yea I just want picking, but I want to know the x,y,z coordinate of the intersection, Im not sure how to determine this given the depth-value returned by the GL_SELECTION method.

You have forgotten to use gluUnProject:
http://www.opengl.org/sdk/docs/man/xhtml/gluUnProject.xml