Reputation: 8529
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:
What am I doing wrong?
Upvotes: 0
Views: 306
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
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