Okay, so I have been having some trouble wrapping my head around projections, i.e. the part where a piece of 3D geometry gets converted into 2D coordinates on the screen. Orthogonal projection seems straight forward enough; just eliminate the Z-coordinate for a vertex position and use X and Y to render the geometry to the screen. However, I am having more trouble with perspective projections on multiple levels. Before I state the exact nature of my problem I have to emphasize that I am writing my own graphics implementation, so all of this low-level stuff isn't magically handled by DirectX, OpenGL or some other API. I should also mention that, I am aiming to implement a perspective projection where the viewer is looking down the positive Z axis (unlike OpenGL, I believe).
Here is a piece of pseudo code that is based on my actual code. I believe the end result is wrong, since a specified triangle that is on-screen orthogonally is not visible when applying perspective correction, even if the distances from the screen to the vertices are 1 (which should result in an indistinguishable result from orthogonal projection, if I am not mistaken).
// Render a triangle using perspective projection
Vertex v1, v2, v3; // given some random values
Matrix4x4 perspectiveMatrix = CreatePerspectiveMatrix(deg2rad(90), screenW/screenH, 0.001, 10000); // see below for definition of CreatePerspectiveMatrix
v1.position = v1.position * perspectiveMatrix;
v2.position = v2.position * perspectiveMatrix;
v3.position = v3.position * perspectiveMatrix;
Matrix4x4 viewportMatrix = CreateViewportMatrix(0, screenW, 0, screenH); // see below for definition of CreateViewportMatrix
v1 = v1/v1.position.w; // divides every single component of vertex by W (positions, colors, normals etc.)
v2 = v2/v2.position.w;
v3 = v3/v3.position.w;
v1.position = v1.position * viewportMatrix;
v2.position = v2.position * viewportMatrix;
v3.position = v3.position * viewportMatrix;
RenderTriangle(v1, v2, v3);
...
// Create a perspective projection matrix (see slide 17 of specified document below)
Matrix4x4 CreatePerspectiveMatrix(float fov, float aspect, float near, float far)
{
return Matrix4x4(
tan(fov/2)/aspect, 0, 0, 0, // X row
0, 1/tan(fov/2), 0, 0, // Y row
0, 0, (near+far)/(near-far), (2*near*far)/(near-far), // Z row
0, 0, -1, 0 // W row
);
}
...
// Create a viewport matrix (see slide 20 of specified document below)
Matrix4x4 CreateViewportMatrix(float x0, float x1, float y0, float y1)
{
return Matrix4x4 f(
(x1-x0)/2, 0, 0, x0 +(x1-x0)/2, // X row
0, (y1-y0)/2, 0, y0 +(y1-y0)/2, // Y row
0, 0, 1, 0, // Z row
0, 0, 0, 1 // W row
);
}
Perhaps someone with a little experience in the field could identify what I am doing wrong. Maybe I am passing the wrong values to the functions creating the matrices?
I should note that I am aware that the perspective matrix negates the Z axis of my vertices. I have however made a temporary hack that negates the Z axis again directly after applying the perspective matrix to a vertex. I do not believe this is the source of my problem.
My work is based on this lecture:
http://graphics.ucsd.edu/courses/cse167_f05/CSE167_04.ppt(If you can't view .PPT use try this address [requires Google ID]:
http://docs.google.com/viewer?url=http://graphics.ucsd.edu/courses/cse167_f05/CSE167_04.ppt).
I believe it contains all of the information I need in order to project vertices correctly to the screen, I gues I just haven't quite connected all the dots yet. Hopefully you could help me with that.
Thanks in advance!
/JNT