0

I'm using SharpGL in a WPF window and have navigation and plotting of a survey point cloud with custom shaders for distance-based point size reduction. All working well but I've recently attempted to add the ability to select a point nearest to the ray cast by a mouse click. I used the steps 0 to 4 in this link: http://antongerdelan.net/opengl/raycasting.html

The problem I'm facing is that the ray seems to be very slightly shifted towards the camera vector causing me to miss the points I'm clicking on and only scrape their inside edge. I'm drawing the ray starting from the camera position too so initially the ray should appear as a dot before moving the camera (looking down the trajectory line) but I can see it clearly drawn to the middle of the screen. Here's a screenshot showing where the ray misses the point when I click on its center:

Screenshot

This is the code I'm using to calculate the ray start and end coordinates:

    public void CreateVerticesForMouseCoord(OpenGL gl, float winx, float winy)
    {

        int[] viewport = new int[4];
        gl.GetInteger(OpenGL.GL_VIEWPORT, viewport);
        float window_width = viewport[2];
        float window_height = viewport[3];

        Console.WriteLine("Window size: " + window_width + "," + window_height);

        vec4 clipPosition = new vec4(0.0f, 0.0f, 1.0f, 1.0f);

        // Normalize the x and y coordinates
        clipPosition.x = 2.0f * (winx / window_width) - 1.0f;
        clipPosition.y = -2.0f * (winy / window_height) + 1.0f;

        mat4 viewInv = glm.inverse(viewMatrix);
        mat4 projInv = glm.inverse(projectionMatrix);

        vec4 camPosition = projInv * clipPosition;
        camPosition.w = 0;
        camPosition.z = -1;
        vec4 worldPosition = viewInv * camPosition;

        vec4 camCamPos = new vec4(0.0f, 0.0f, 0.0f, 1.0f);
        vec4 objCamPos = glm.inverse(viewMatrix) * camCamPos;
        vec4 camCamDir = new vec4(0.0f, 0.0f, -1.0f, 0.0f);
        vec4 objCamDir = glm.inverse(viewMatrix) * camCamDir;

        float x1 = objCamPos.x + 30.0f * worldPosition.x;
        float y1 = objCamPos.y + 30.0f * worldPosition.y;
        float z1 = objCamPos.z + 30.0f * worldPosition.z;
        float x2 = objCamPos.x - 0.0f * worldPosition.x;
        float y2 = objCamPos.y - 0.0f * worldPosition.y;
        float z2 = objCamPos.z - 0.0f * worldPosition.z;

        Console.WriteLine("Screen coordinates: " + winx + ","+winy);
        Console.WriteLine("Clip coordinates: " + clipPosition.x + "," + clipPosition.y + "," + clipPosition.z+ ","+ clipPosition.w);
        Console.WriteLine("Camera coordinates: " + camPosition.x + "," + camPosition.y + "," + camPosition.z+","+ camPosition.w);
        Console.WriteLine("World coordinates: " + worldPosition.x + "," + worldPosition.y + "," + worldPosition.z+","+ worldPosition.w);

        Console.WriteLine("Camera Position: " + objCamPos.x + "," + objCamPos.y + "," + objCamPos.z + "," + objCamPos.w);
        Console.WriteLine("Camera Direction: " + objCamDir.x + "," + objCamDir.y + "," + objCamDir.z + "," + objCamDir.w);

        float[] mousePointArray = { x1, y1, z1, x2, y2, z2 };

The output looks like this:

    Window size: 470,314
    Screen coordinates: 316,184
    Clip coordinates: 0.3446808,-0.1719745,1,1
    Camera coordinates: 0.1877808,-0.06259361,-1,0
    World coordinates: 0.1877808,-0.06259361,-1,0
    Camera Position: 4,7,6,1
    Camera Direction: 0,0,-1,0

The offset does appear to get bigger the further away from the center of the screen I click. Any help I can get diagnosing this would be much appreciated, I've spent two days reading articles and fiddling with the code to no avail.

Ross Batten
  • 114
  • 8
  • Why are you setting `camPosition.w = 0; camPosition.z = -1;`? You are basically throwing away half of the data. And you need to do the perspective divide like Rabbid mentioned. – Nico Schertler Jan 30 '18 at 21:02
  • Ok I understand now how the projection matrix and the w-component interact. I did a test to see what coordinates are coming out from the corners of the clip-space (-1 to 1 in all three dimensions) and the resultant eye-space coordinates don't correlate with the projection matrix constructor parameters. Basically with a fov of 20 degrees the corners end up tracing an arc of just under 22 degrees and a near plane distance of 4 results in near points at z = 3.7 and a far plane distance of 10 results in far points at z=10.75. Why is nothing as I coded it? – Ross Batten Jan 31 '18 at 01:38
  • I figured out the cause of the distortion. The perspective function in glm outputs a matrix with the bottom right element set to 1 when it should be 0. I found it by going element-wise through the matrix and checking the maths behind. By forcing element 3,3 (zero-index) to be zero after creating the perspective matrix all the transforms line up perfectly. – Ross Batten Jan 31 '18 at 03:39

0 Answers0