1
votes

I'm fairly new to 3D Graphics, so I expect I have done something fundamentally wrong. I have built 4 matrixes to handle my objects in 3D space, a Scaling matrix, Translation Matrix, Perspective Matrix and Rotation matrix.

The rotation and scaling matrix work fine, however my Perspective and Translation Matrixes do not behave as expected, from what I understand the Translation and Perspective Matrixes look like:

Translation      Perspective 
[1, 0, 0, x]    [1, 0,  0 , 0]
[0, 1, 0, y]    [0, 1,  0 , 1]
[0, 0, 1, z]    [0, 0,  1 , 0]
[0, 0, 0, 1]    [0, 0, 1/D, 1]

To understand how everything works behind the scenes I am writing my own Math lib - to create the matrixes defined above I have the following methods:

public static ASMATRIX4 CreatePerspectiveMatrix(double focalLength)
{
    // Create matrix as an identity matrix
    var m = new ASMATRIX4();

    // Set the perspective matrix 
    m.Matrix[3].Points[2] = 1 / focalLength;
    m.Matrix[1].Points[3] = 1;

    return m;
}

public static ASMATRIX4 CreateTranslationMatrix(double x, double y, double z)
{
    // reset to identity matrix
    var m = new ASMATRIX4();

    // Set the translation matrix
    m.Matrix[0].Points[3] = x;
    m.Matrix[1].Points[3] = y;
    m.Matrix[2].Points[3] = z;

   return m;
}

Nothing too complicated, but when I multiply my matrixes together, nothing happens - I can rotate about any axis, but I cannot translate. Also note above that new ASMATRIX4() initialises a new 4x4 matrix as an identity matrix.

To multiply my matrixes together I do the following:

m_scaling = ASMATRIX4.CreateScalingMatrix(s, s, s);
m_translation = ASMATRIX4.CreateTranslationMatrix(tX, tY, tZ);
m_perspective = ASMATRIX4.CreatePerspectiveMatrix(f);
m_rotation = ASMATRIX4.RotateByDegrees(rX, rY, rZ);

var transformationMatrix = m_scaling*m_translation*m_perspective*m_rotation;

I also wrote an operator overload to handle multiplying matrixes together:

public static ASMATRIX4 operator *(ASMATRIX4 mA, ASMATRIX4 mB)
{
    //  Creates a new identity matrix
    var m = new ASMATRIX4();

    // Multiply the two matrixes together and return the output matrix
    for (var i = 0; i < 4; i++)
    {
        for (var j = 0; j < 4; j++)
        {
            m.Matrix[i].Points[j] =
                (mB.Matrix[i].Points[0]*mA.Matrix[0].Points[j]) +
                (mB.Matrix[i].Points[1]*mA.Matrix[1].Points[j]) +
                (mB.Matrix[i].Points[2]*mA.Matrix[2].Points[j]) +
                (mB.Matrix[i].Points[3]*mA.Matrix[3].Points[j])
        }
    }
    return m;
 }

Finally to actually transform my mesh, I have an array of Faces, that I draw to a 2D rendering context, the method below transforms each face by the transformation matrix defined above.

private void TransformMesh()
{
    var transformationMatrix = m_scaling*m_translation*m_perspective*m_rotation;
    for (var i = 0; i < m_numFaces; i++)
    {     
        m_meshData[i] = m_meshData[i].TransformFace(transformationMatrix);
    }
}

The TransformFace method looks as described below:

public ASFace TransformFace(ASMATRIX4 matrix)
{
    var transformedFace = new ASFace();

    for (var i = 0; i < 3; i++)
    {
        transformedFace.m_points[i] = m_points[i].TransformVector(matrix);
        transformedFace.m_points[i] = transformedFace.m_points[i].Rescale();
    }

    return transformedFace;
 }

This first method in the loop transforms the homogenous point by the input matrix, and then a rescale method is called to normalise the vector.

I'm confused as to what I have done wrong? I am thinking the order of operations on multiplying the matrixes could be wrong but I am not too sure, any suggestions would be greatly appreciated.

2
The order of multiplication is important, is it a prepend or append multiply? You could shuffle the matrices in the m_scaling*m_translation*m_perspective*m_rotationJeroen van Langen
I believe its an appendAlex
@Alex Also confirm your constructor for ASMATRIX4 is creating an identity matrix and not a zero or (less likely) random matrix. I know it says that in the comments, but you should check to ensure that's the case.andand
Thanks for the heads up andand, I've already confirmed this - it produces an identity matrix each time. Feeling fairly baffledAlex
@Alex It would be helpful, then, if you could post sample inputs and outputs (i.e. matrix operands, and results) along with a Short, Self Contained, Correct (Compilable), Example (sscce.org). The way your code is listed here, and given the answers below haven't addressed your problem, the likely cause of the problem may not be in anything you have thusfar included above.andand

2 Answers

4
votes

I'm not an expert about this, but aren't you missing a row/column here?

-- EDITED (tnx andand)

public static ASMATRIX4 operator *(ASMATRIX4 mA, ASMATRIX4 mB)
{
    //  Creates a new identity matrix
    var m = new ASMATRIX4();

    // Multiply the two matrixes together and return the output matrix
    for (var i = 0; i < 4; i++)
    {
        for (var j = 0; j < 4; j++)
        {
            m.Matrix[i].Points[j] =
                (mB.Matrix[i].Points[0]*mA.Matrix[0].Points[j]) +
                (mB.Matrix[i].Points[1]*mA.Matrix[1].Points[j]) +
                (mB.Matrix[i].Points[2]*mA.Matrix[2].Points[j]) +
                (mB.Matrix[i].Points[3]*mA.Matrix[3].Points[j]);   //  <----
        }
    }
    return m;
}
3
votes

I see two problems in your posted code. First, your CreatePerspectiveMatrix method does not set the (1, 3) element to 1; either the method or the initial definition of the perspective matrix is wrong. (Or both!) Second, in your multiplication code you seem to be only multiplying the sub-matrix of the first three rows and columns. Since these sub-matrices are initially unit matrices, it's not too surprising that nothing happens.