0
votes

I'm currently attempting to teach myself perspective projection, my reference is the wikipedia page on the subject here: http://en.wikipedia.org/wiki/3D_projection#cite_note-3

My understanding is that you take your object to be project it and rotate and translate it in to "camera space", such that your camera is now assumed to be origin looking directly down the z axis. (This matrix op from the wikipedia page: http://upload.wikimedia.org/math/5/1/c/51c6a530c7bdd83ed129f7c3f0ff6637.png)

You then project your new points in to 2D space using this equation: http://upload.wikimedia.org/math/6/8/c/68cb8ee3a483cc4e7ee6553ce58b18ac.png

The first step I can do flawlessly. Granted I wrote my own matrix library to do it, but I verified it was spitting out the right answer by typing the results in to blender and moving the camera to 0,0,0 and checking it renders the same as the default scene.

However, the projection part is where it all goes wrong.

From what I can see, I ought to be taking the field of view, which by default in blender is 28.842 degrees, and using it to calculate the value wikipedia calls ez, by doing

ez = 1 / tan(fov / 2);

which is approximately 3.88 in this case.

I should then for every point be doing:

x = (ez / dz) * dx; y = (ez / dz) * dy;

to get x and y coordinates in the range of -1 to 1 which I can then scale appropriately for the screen width.

However, when I do that my projected image is mirrored in the x axis and in any case doesn't match with the cube blender renders. What am I doing wrong, and what should I be doing to get the right projected coordinates?

I'm aware that you can do this whole thing with one matrix op, but for the moment I'm just trying to understand the equations, so please just stick to the question asked.

1
I think we need to see some actual code. Are you working with OpenGL? Even though your object's vertex coordinates are 3D, both OpenGL and GLSL will create a 4th component (w) and expect a 4X4 matrix. Actually, you need three matrices: Model, View and Projection. - jwlaughton
The View matrix is formed from the camera's (eye's) position, view direction and camera up direction. The Projection matrix defines the frustum and is formed from the left, right, top, bottom, near and far clipping planes. The Model matrix is formed from various transformations like scale, rotation and translation. You multiply each vertex by these three matrices: Projection * View * Model * Vertex. BTW, if you aren't using OpenGL or GLSL, just use 1.0 for the w coordinate. - jwlaughton
Google glFrustum and gluLookAt to see how to form the Projection and View matrices. - jwlaughton

1 Answers

-1
votes

From what you say in your question it's unclear whether you're having trouble with the Projection matrix or the Model matrix.

Like I said in my comments, you can Google glFrustum and gluLookAt to see exactly what these matrices look like. If you're familiar with matrix math (and it looks like you are), you will then understand how the coordinates are transformed into a 2D perspective.

Here is some sample OpenGL code to make the View and Projection Matrices and Model matrix for a simple 30 degree rotation about the Y axis so you can see how the components that go into these matrices are calculated.

// The Projection Matrix

glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
near = -camera.viewPos.z - shapeSize * 0.5;
if (near < 0.00001)
    near = 0.00001;

far = -camera.viewPos.z + shapeSize * 0.5;
if (far < 1.0)
    far = 1.0;
radians = 0.0174532925 * camera.aperture / 2; // half aperture degrees to radians
wd2 = near * tan(radians);
ratio = camera.viewWidth / (float) camera.viewHeight;
if (ratio >= 1.0) {
    left  = -ratio * wd2;
    right = ratio * wd2;
    top = wd2;
    bottom = -wd2;
} else {
    left  = -wd2;
    right = wd2;
    top = wd2 / ratio;
    bottom = -wd2 / ratio;
}

glFrustum (left, right, bottom, top, near, far);

// The View Matrix

glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
gluLookAt (camera.viewPos.x, camera.viewPos.y, camera.viewPos.z,
           camera.viewPos.x + camera.viewDir.x,
           camera.viewPos.y + camera.viewDir.y,
           camera.viewPos.z + camera.viewDir.z,
           camera.viewUp.x, camera.viewUp.y ,camera.viewUp.z);

// The Model Matrix

glRotatef (30.0, 0.0, 1.0, 0.0);

You'll see that glRotate actually does a quaternion rotation (angle of rotation plus a vector about which to do the rotation).

You could also do separate rotations about the X, Y and Z axis.

There's lot's of information on the web about how to form 4X4 matrices for rotations, translations and scales. If you do each of these separately, you'll need to multiply them to get the Model matrix. e.g:

If you have 4X4 matrices rotateX, rotateY, rotateZ, translate, scale, you might form your Model matrix by:

Model = scale * rotateX * rotateZ * rotateY * translate.

Order matters when you form the Model matrix. You'll get different results if you do the multiplication in a different order.

If your object is at the origin, I doubt you want to also put the camera at the origin.