Search code examples
javascriptopengl-esmatrixwebglperspective

OpenGL vector projection inaccurate


I'm creating the perspective projection like this:

function quickViewMatrix( pos, center, w, h )
{
    var modelview = mat4.create();
    mat4.lookAt( pos, center, [ 0, 0, 1 ], modelview );
    var projection = mat4.create();
    mat4.perspective( 45, w/h, 1, 20, projection );
    var viewTransformation = mat4.create();
    mat4.multiply( projection, modelview, viewTransformation );
    return viewTransformation;
}

So, viewTransformation = PM. This matrix is then passed to a vertex shader where the multiplication (PM)*V is done.

Now I want to manually transform a world coordinate to a screen coordinate. I do that like this:

function worldToScreen( x, y, z, w, h )
{
    var out = vec3.create();
    mat4.multiplyVec3( cameraTransform, [ x, y, z ], out );
    out[0] /= out[2];
    out[1] /= out[2];
    out[0] = ( out[0] + 1.0 ) / 2.0 * w;
    out[1] = ( 1.0 - out[1] ) / 2.0 * h;
    return { x: out[0], y: out[1] };
}

cameraTransform here is a matrix created using the function above. This seems to work for the upper region of the screen, but the lower (and closer to the camera!) I get, the more inaccurate it becomes.

I transformed all points of a plane to screen coordinates manually (shown in red) this way and ended up with this:

http://puu.sh/fXGB

What am I doing wrong?


Solution

  • Turned out I was diving by the depth instead of w, which resulted in the problem.

    My new function:

    function worldToScreen( x, y, z, w, h )
    {
        var out = [];
        mat4.multiplyVec4( cameraTransform, [ x, y, z, 1.0 ], out );
        out[0] /= out[3];
        out[1] /= out[3];
        out[2] /= out[3];
        out[0] = ( out[0] + 1.0 ) / 2.0 * w;
        out[1] = ( 1.0 - out[1] ) / 2.0 * h;
        return { x: out[0], y: out[1]};
    }