Reconstruct shader vertices in OpenGL

| | August 5, 2015

I’m not sure if ‘reconstruct’ is the correct term for this but essentially what I am trying to do is calculate vertex positions (that are already calculated via shader) on the CPU for the purpose of ray tracing. I need to know the locations of the models so I can detect if my ray passes through them. It would be nice if I could retrieve the values from memory after the the shader has calculated them but it doesn’t seem possible – or advisable.
What I have so far looks like it should work but when I trace my ray (that does pass directly through the model) none of the vertices fall inside the model.

Create the ray (Tested by drawing a line between far/near and it works fine):

public float[] getPickingVector(float[] modelview,
                                float[] projection,
                                int[] viewport,
                                float winX,
                                float winY) throws Exception {

    float[] mat4Tmp1 = new float[16];
    float[] mat4Tmp2 = new float[16];
    float[] vec4Tmp2 = new float[4];

    FloatUtil.mapWinToObjCoords(winX, winY, 0, modelview, 0, 
            projection, 0, 
            viewport, 0, 
            nearVector, 0, 
            mat4Tmp1, mat4Tmp2);

    FloatUtil.mapWinToObjCoords(winX, winY, 1, modelview, 0, 
            projection, 0, 
            viewport, 0, 
            farVector, 0, 
            mat4Tmp1, mat4Tmp2);

    // save the results in a vector, far-near
    destVector[0] = farVector[0] - nearVector[0];
    destVector[1] = farVector[1] - nearVector[1];
    destVector[2] = farVector[2] - nearVector[2];

    return destVector;
}

‘Reconstruct’ the model vertices by reading back the values of the vertex buffer that are keyed on the index buffer. I have stepped through the loop and the code does read back the vertex buffer values in the correct order:

//check by pairs of triangles that create a square.
public boolean findIntersection(Wh w, float[] mvp){

    float[] a = new float[4];
    float[] b = new float[4];
    float[] c = new float[4];

    boolean rslt = false;

    //init boundary vars.
    float[] tmp = {-2000,-2000,-2000};
    float[] tmp2 = {2000,2000,2000};


    //loop thru each triangle.  Arrays a,b and c each represent
    //a vertex of one triangle.  The are 12 in total creating a
    //box.
    for ( int i = 0; i < w.idxBuffer.length; i += 3  ){
         a[0] = w.vertBuffer[ (w.idxBuffer[i + 0] * 3) + 0];
         a[1] = w.vertBuffer[ (w.idxBuffer[i + 0] * 3) + 1];
         a[2] = w.vertBuffer[ (w.idxBuffer[i + 0] * 3) + 2];
         b[0] = w.vertBuffer[ (w.idxBuffer[i + 1] * 3) + 0];
         b[1] = w.vertBuffer[ (w.idxBuffer[i + 1] * 3) + 1];
         b[2] = w.vertBuffer[ (w.idxBuffer[i + 1] * 3) + 2];
         c[0] = w.vertBuffer[ (w.idxBuffer[i + 2] * 3) + 0];
         c[1] = w.vertBuffer[ (w.idxBuffer[i + 2] * 3) + 1];
         c[2] = w.vertBuffer[ (w.idxBuffer[i + 2] * 3) + 2];
         a[3] = 1;
         b[3] = 1;
         c[3] = 1;

         //****Here is where I suspect my problem is **********
         //To rebuild the vertices I multiply the vertex from the 
         //vertex buffer by the model/view/projection matrix, mimicking
         //what is done in the shader:
         //      gl_Position = MVP * vec4(VertexPosition,1.0);
         //My hope is that this will provide me with the correct positioning
         //of the model so the ray trace will work.
         FloatUtil.multMatrixVec(mvp, a, am);
         FloatUtil.multMatrixVec(mvp, b, bm);
         FloatUtil.multMatrixVec(mvp, c, cm);

         //The following creates max/min boundaries used to test for
         //a point being inside the box.
         //high x values
         if (tmp[0] < am[0]){tmp[0] = am[0];}
         if (tmp[0] < bm[0]){tmp[0] = bm[0];}
         if (tmp[0] < cm[0]){tmp[0] = cm[0];}

        //high y values
         if (tmp[1] < am[1]){tmp[1] = am[1];}
         if (tmp[1] < bm[1]){tmp[1] = bm[1];}
         if (tmp[1] < cm[1]){tmp[1] = cm[1];}

        //high z values
         if (tmp[2] < am[2]){tmp[2] = am[2];}
         if (tmp[2] < bm[2]){tmp[2] = bm[2];}
         if (tmp[2] < cm[2]){tmp[2] = cm[2];}

         //low x values
         if (tmp2[0] > am[0]){tmp2[0] = am[0];}
         if (tmp2[0] > bm[0]){tmp2[0] = bm[0];}
         if (tmp2[0] > cm[0]){tmp2[0] = cm[0];}

        //low y values
         if (tmp2[1] > am[1]){tmp2[1] = am[1];}
         if (tmp2[1] > bm[1]){tmp2[1] = bm[1];}
         if (tmp2[1] > cm[1]){tmp2[1] = cm[1];}

        //low z values
         if (tmp2[2] > am[2]){tmp2[2] = am[2];}
         if (tmp2[2] > bm[2]){tmp2[2] = bm[2];}
         if (tmp2[2] > cm[2]){tmp2[2] = cm[2];}

    }

    //The following traces the ray until one of the points falls
    //within the boundaries of the box.
    float fract = (nearClippingDistance / (farClippingDistance));

    System.out.println("x:" + tmp[0] + "  " + tmp2[0]);
    System.out.println("y:" + tmp[1] + "  " + tmp2[1]);
    System.out.println("z:" + tmp[2] + "  " + tmp2[2]);
    //boolean init = false;

    float idx = 0;
    float[] mult = new float[3];
    float[] t = new float[3];
    for (idx = fract; idx <= 1; idx += fract) {
        mult[0] = farVector[0] * idx;
        mult[1] = farVector[1] * idx;
        mult[2] = farVector[2] * idx;
        VectorUtil.addVec3(t, nearVector, mult);

        System.out.println("x:" + t[0] + "  y:" + t[1] + "  z:" + t[2]);

        if (((t[0] <= tmp[0]) && (t[0] >= tmp2[0])) && 
            ((t[1] <= tmp[1]) && (t[1] >= tmp2[1])) && 
            ((t[2] <= tmp[2]) && (t[2] >= tmp2[2]))){
            //ray intersects this box.
            rslt = true;

        }
    }  

    return rslt;

}

I have also tried many open source libraries that provide bounding box detecting / plane intersection / ray tracing but none of them work I think because my vertex values are somehow incorrect. Does anyone see a problem with what I am doing here?

One Response to “Reconstruct shader vertices in OpenGL”

  1. It would be nice if I could retrieve the values from memory after the the shader has calculated them but it doesn’t seem possible – or advisable

    But, it IS possible, and I would advise it:

    https://www.opengl.org/wiki/Transform_Feedback

Leave a Reply