LWJGL - 3D Mouse picking

I’ve been trying to figure out how to unproject top-left screen coords to a ray (origin and direction vector) in world coords.

But I can’t crack it. Does anyone have any good references?

Preferably using modern OpenGL

Hi,

what you need to do is apply the inverse of the world-to-NDC transformation to your normalized-device-coordinates (NDC) space.
You therefore have to have the projection and view matrices of your scene, which OpenGL uses to transform a vertex from world-to-NDC space.
Once you have these, you need to invert the combined view-projection matrix to obtain the reverse transformation.
After that, you apply that transformation to the corner coordinates of your NDC space, which are -1 and +1 in both X and Y. Z can be 0.0 and W must be 1.

You might also have a look at the ray tracing tutorial in LWJGL: http://blog.lwjgl.org/ray-tracing-with-opengl-compute-shaders-part-i/

This tutorial uses modern OpenGL (OpenGL 4.3 Compute Shaders actually, also with a backport to OpenGL 3.0 GPGPU with fragment shaders) and uses NDC-to-world transformations to generate the rays for each framebuffer pixel, based on a pinhole camera model.

Cheers,
Kai

Thanks this looks like a great resource.

For your concrete problem, you do not have to read it all, though.
Especially the first 2/3 of the article can be a bit long-winded, if you are not so much into ray tracing, history and problems of rendering in general… :slight_smile:

You can jump right into the section saying “Setting up the camera”.
Or better, have a look at the source code whose references are found in hyperlinks beginning with “accompanying …”.

Oh wow Display got replaced by GLFW. Interesting.

Time to update!

Okay after browsing and stuff I was able to put this together from snippets people left around:


public Ray getPickRay(float mouseX, float mouseY) {
        float screenSpaceX = ((2f * mouseX) / GameConstants.width - 1f) * aspectRatio;
        float screenSpaceY = ((-2f * mouseY) / GameConstants.height + 1);

        float viewRatio = Mathf.tan(Mathf.toRadians(fov) / 2f);

        screenSpaceX *= viewRatio;
        screenSpaceY *= viewRatio;

        Vector3f cameraSpaceNear = new Vector3f(screenSpaceX * zNear, screenSpaceY * zNear, -zNear);
        Vector3f cameraSpaceFar = new Vector3f(screenSpaceX * zFar, screenSpaceY * zFar, -zFar);

        Matrix4f tmpView = new Matrix4f(viewMatrix);
        Matrix4f invView = tmpView.invert();

        Vector3f worldSpaceNear = new Vector3f();
        Matrix4f.transform(invView, cameraSpaceNear, worldSpaceNear);

        Vector3f worldSpaceFar = new Vector3f();
        Matrix4f.transform(invView, cameraSpaceFar, worldSpaceFar);

        return ray.set(
                new Vector3f(worldSpaceNear.x, worldSpaceNear.y, worldSpaceNear.z),
                new Vector3f(
                        worldSpaceFar.x - worldSpaceNear.x,
                        worldSpaceFar.y - worldSpaceNear.y,
                        worldSpaceFar.z - worldSpaceNear.z
                ).normalize()
        );
    }

This works fine but I’m trying to make it work using my inverse projViewMatrix. For learning purposes.

I know it’s possible I just can’t find the right way.

Any ideas?