2
$\begingroup$

I can't for the life of me figure out how to use a perspective projection matrix. My understanding is that, once objects are in view space, the the perspective transform uses the z-coordinate to scale the x and y coordinates.

Here's the code I'm using (C#, dotnet 7).

var viewToScreen = Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.Tau / 4), 1.0f, 0.1f, 100f);

var square1 = new Vector3[]
{
    new(+1, +1, 1),
    new(-1, +1, 1),
    new(+1, +1, 1),
    new(+1, -1, 1),
};

var square2 = Array.ConvertAll(square1, v =>
{
    v.Z += 3;
    return v;
}).Dump("Square 2 (World Space)");

var screen1m1 = Array.ConvertAll(square1, v => Vector3.Transform(v, viewToScreen));

var screen2m1 = Array.ConvertAll(square2, v => Vector3.Transform(v, viewToScreen))

However, after the transform, the X and Y coordinates remain unchanged. Only the Z coordinate is changed, and then only slightly. This is consistent with an orthogonal projection, not a perspective projection.

What am I doing wrong here?

$\endgroup$
3
  • $\begingroup$ I don't get the v.Z +=3 part... but projection matrices only work with 4D vectors. After multiplication the result vector needs to be divided by its 4th w component. so: Vector4D result = projectionMatrix * viewMatric * position4D where the 4th component of position4D should be 1. At the end you need to calculate: $result = result / result.w$ $\endgroup$
    – Thomas
    Dec 23, 2022 at 9:50
  • $\begingroup$ I'm creating a second set of points, further from the screen along the z coordinate. $\endgroup$ Dec 23, 2022 at 10:23
  • $\begingroup$ Please add that as an answer. It worked! And, the simple C# solution is just to use Vector4 instead of Vector3, which automatically appends the 1. $\endgroup$ Dec 23, 2022 at 10:39

1 Answer 1

2
$\begingroup$

The way to do the projection is the following:

Matrix4x4 projection;
Matrix4x4 modelView;
Vector4D position4D;

//fist the position's 4th value (w) need to be set to value "1"
position4D = Vector4D(position3D, 1); //the 1 in the 4th component is very important!
Vector4D result = projection * modelView * position4D;
//at the end, the result need to be divided by its 4th component (w) 
result = result / result.w;

The last line is of major importance, because the projection (perspective) is not linear. the division by the 4th component can not be applied within the matrix.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.