Overv
Overv

Reputation: 8529

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?

Upvotes: 0

Views: 306

Answers (2)

Chris Broadfoot
Chris Broadfoot

Reputation: 5112

On a side note, you can perform matrix multiplication from within a shader. This is much faster than doing it in JS.

Here's a good start: http://www.davidcornette.com/glsl/glsl.html

Upvotes: 0

Overv
Overv

Reputation: 8529

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]};
}

Upvotes: 1

Related Questions