Search code examples
opengljoglprojection

opengl normalized device coordinates larger than 1


I am currently coding a menu system in JAVA and need to convert from world coordinates to screen coordinates. I have read many a post on how to do it and have built the following:

    float[] v = new float[]{0,0,0,1}; //four vector location of object in object space


    //multiply by model matrix

    v[0] = model[0]*v[0] + model[4]*v[1] + model[8]*v[2] + model[12]*v[3];
    v[1] = model[1]*v[0] + model[5]*v[1] + model[9]*v[2] + model[13]*v[3];
    v[2] = model[2]*v[0] + model[6]*v[1] + model[10]*v[2] + model[14]*v[3];
    v[3] = model[3]*v[0] + model[7]*v[1] + model[11]*v[2] + model[15]*v[3];

    //multiply by projection matrix

    v[0] = projection[0]*v[0] + projection[4]*v[1] + projection[8]*v[2] + projection[12]*v[3];
    v[1] = projection[1]*v[0] + projection[5]*v[1] + projection[9]*v[2] + projection[13]*v[3];
    v[2] = projection[2]*v[0] + projection[6]*v[1] + projection[10]*v[2] + projection[14]*v[3];
    v[3] = projection[3]*v[0] + projection[7]*v[1] + projection[11]*v[2] + projection[15]*v[3];

    //account for distortions
    v[0] = v[0]/v[3];
    v[1] = v[1]/v[3];
    v[2] = v[2]/v[3];
    v[3] = v[3]/v[3];   

    //transform to screen coords.
    onScreenX = (int)((viewport[2] * (v[0] + 1.0f)) / 2.0f) + viewport[0];
    onScreenY = (int)((viewport[3] * (v[1] + 1.0f)) / 2.0f) + viewport[1];

    System.out.println(onScreenX + ", " + onScreenY);

Now the big issue I am having is that after I do the perspective divide I should have values between -1 and 1. However, I get some that are outside of this range even though the object is clearly on the screen. I am not sure what I could be missing here.

I already know of the the function gluProject() but this calculation is located far from where my glu object is located and so the function would be of no use. It must be done with matrix math.


Solution

  • These calculations overwrite values in the v vector with new ones, and then use them where the old values should still be used.

    Just looking at the first two assignments:

    v[0] = model[0]*v[0] + model[4]*v[1] + model[8]*v[2] + model[12]*v[3];
    v[1] = model[1]*v[0] + model[5]*v[1] + model[9]*v[2] + model[13]*v[3];
    

    The first statement assigns a new value to v[0], and then uses it on the right side of the second statement. So for the calculation of v[1], the new value for v[0] is used together with the old values of v[1], v[2] and v[3].

    The same pattern continues through the entire calculations.

    The easiest way to avoid this is to use a new vector for each step of the calculation. For example:

    float[] vModel = new float[4];
    vModel[0] = model[0]*v[0] + model[4]*v[1] + model[8]*v[2] + model[12]*v[3];
    vModel[1] = model[1]*v[0] + model[5]*v[1] + model[9]*v[2] + model[13]*v[3];
    ...
    
    float[] vProj = new float[4];
    vProj[0] = projection[0]*vModel[0] + ...
    ...
    

    This avoids overwriting values with new ones while the old one is still in use.