I'm making a 3D Software Renderer and I've got the translation, rotation and scaling matrices all done.
Now I've got a perspective projection matrix, which will apply the depth perspective to all my points. What I can't do is project the final perspective projected vector onto screen coordinates(Viewport transform).
This is the perspective projection matrix that I'm using right now: http://puu.sh/7XikH.jpg (sorry can't post images)
So basically I need a matrix that will take an already perspective projected vector and turn it into screen coordinates.
Alright here's some code:
This is the perspective projection matrix, I create one of these and multiply the last matrix I had by it, so this multiplies with the final fully translated rotated and scaled matrix
public static Matrix4 CreateProjectionMatrix(double znear, double zfar, int width, int height, double fov)
{
double[,] ret = new double[4, 4];
double e = 1 / Math.Tan(MathUtil.GetRadian(fov) / 2.0);
double ar = width / height;
double zp = zfar + znear;
double zn = zfar - znear;
ret[0, 0] = e; ret[0, 1] = 0; ret[0, 2] = 0; ret[0, 3] = 0;
ret[1, 0] = 0; ret[1, 1] = e / ar; ret[1, 2] = 0; ret[1, 3] = 0;
ret[2, 0] = 0; ret[2, 1] = 0; ret[2, 2] = -(zp / zn); ret[2, 3] = -((2 * zfar * znear) / zn);
ret[3, 0] = 0; ret[3, 1] = 0; ret[3, 2] = -1; ret[3, 3] = 0;
return new Matrix4(ret);
}
the other matrices are multiplied in this order:
public Matrix4 GetTransformationMatrix()
{
Matrix4 translationm = Matrix4.CreateTranslationMatrix(Translation);
Matrix4 rotationm = Matrix4.CreateRotationMatrix(Rotation);
Matrix4 scalem = Matrix4.CreateScaleMatrix(Scale);
//scale -> rotate -> translate
return translationm * (rotationm * scalem);
}
and this is the final matrix, the one I get by applying the perspective projection, I then multiply all the vertices with the result:
public Matrix4 GetProjectedTransformationMatrix()
{
Matrix4 projectionm = Projection.GetProjectionMatrix();
Matrix4 tranformationm = GetTransformationMatrix();
Matrix4 ret = projectionm * tranformationm;
return ret;
}
I'm missing a viewport matrix, the one that when I multiply the final vector with will give me the correct x and y screen coordinates. While I'm not using OpenGL, the way OpenGL or Direct3D sets up their viewport matrices would work I think.
Edited
I've solved the problem, although not the way I'd like.
I was looking for a matrix that would handle all the projection and coordinate transformations, something that would take the already transformed points with all the model and view matrix multiplications and turn that into screen coordinates.
What I'm doing right now is applying the same perspective projection matrix I had before and then divide both x and y by z and then applying the screen size factor, like this:
public Point GetProjectedPoint(Vector vec, Matrix4 mat)
{
Vector point = vec * mat;
double px = point.X / point.Z * Width;
double py = point.Y / point.Z * Height;
return new Point(px, py);
}
The way I thought this would work is the perspective projection(http://puu.sh/7XikH.jpg) would divide by Z, since that's where the "perspective (further away points = smaller)" effect comes from, and that would give me the final world coordinates(this confuses me since I'm dividing by Z on the final viewport projection, so what's the perspective projection doing after all?).
And then to turn it into screen coordinates the viewport matrix would first scale everything to Normalized Device Coordinates and then map it to the screen coordinates.
If someone could clarify what the pipeline should be and what I should be doing, or explain a better method that uses a proper matrix I'd appreciate it.