0
\$\begingroup\$

I'm developing a game and I'd like to make model * pos4 calc (that's usual in glsl vertex shader) in cpu instead of doing it in gpu. I'm using LWJGL and for the math impl I use JOML. Anyone know how to multiply a vec4 with a matrix 4x4? It would be nice showing me the JOML code but also the way to mul the mat values with the vec4 values is fine!

\$\endgroup\$
  • \$\begingroup\$ Check the JOML documentation. There are plenty of variations of Matrix4f.transform*(). \$\endgroup\$ – msell Jan 31 '17 at 14:47
1
\$\begingroup\$

Matrix-vector multiplication works the same as matrix-matrix multiplication, because a 4d vector is basically matrix with one of the dimensions equal to 1.


If we have a vector v = (x; y; z; w) and a matrix

    a b c d
M = e f g h
    i j k l
    m n o p

Then M * v is equal to

(x*a + y*b + z*c + w*d;
 x*e + y*f + z*g + w*h;
 x*i + y*j + z*k + w*l;
 x*m + y*n + z*o + w*p)

And v * M is equal to

(x*a + y*e + z*i + w*m; 
 x*b + y*f + z*j + w*n; 
 x*c + y*g + z*k + w*o; 
 x*d + y*h + z*l + w*p)

To do M * v in JOML, you need to use the matrix's transformPosition() method:

yourMatrix.transformPosition(yourVector);
\$\endgroup\$
  • \$\begingroup\$ Thank you Balint, but the calcule is not vector4 * matrix4x4, it's matrix4x4 * vector4. Is it the same? If not could you edit the question? I would be really pleased. \$\endgroup\$ – loryruta Jan 31 '17 at 8:36
  • \$\begingroup\$ I'm sorry I wasn't been clear in the title. \$\endgroup\$ – loryruta Jan 31 '17 at 8:44
  • \$\begingroup\$ @loyruta I messed it up a bit, those calculations are M * v. Also, M * v in row major is also v * M in column major \$\endgroup\$ – Bálint Jan 31 '17 at 10:30
  • \$\begingroup\$ @Bálint I think you're using slightly incorrect terms. {row|column} major ordering has nothing to do with how computations are performed. It's just a way of storing 2D array in memory. \$\endgroup\$ – HolyBlackCat Jan 31 '17 at 13:36
  • \$\begingroup\$ @HolyBlackCat scratchapixel.com/lessons/… "If you decide to write the vectors in column-major order instead ([3x1]), the [3x3] matrix needs to be on the left side of the multiplication and the vector or point on the right side" \$\endgroup\$ – Bálint Jan 31 '17 at 15:35
1
\$\begingroup\$

You should read these nice tutorials about matrices and vectors.

matrix × vector is a degenerate case of matrix × matrix multiplication.

(A vector can be considered a matrix with width or height equal to 1.)


Here is how matrix × matrix multiplication is performed:

Assume we have two matrices, A and B.

If A has size m×n and B has size n×p, then the resulting matrix C will have size m×p.

(We're using mathematical notation here. In α×β the first letter denotes height and the second letter denotes width.)

Notice how the same letter n denotes both the width of A and height of B. If they are different, you can't multiply such matrices.

Let's call resulting matrix C(m×p).

Then, to get a single element C[y][x] of the resulting matrix, you must take y-th row from the A and x-th column from the B, multiply them component-wise and add together the results.

Here is some pseudocode:

const int m = ...;
const int n = ...;
const int p = ...;

float a[m][n] = {...};
float b[n][p] = {...};
float c[m][p];

for (int i = 0; i < m; i++)
{
    for (int j = 0; j < p; j++)
    {
        c[i][j] = 0;

        for (int k = 0; k < n; k++)
        {
            c[i][j] += a[i][k] * b[k][j];
        }
    }
}

For example, if

    / 1 2 5 \         / 0 5 \
A = | 3 5 4 |     B = | 3 9 |
    \ 0 7 9 /         \ 1 4 /

Then C will be 2 numbers wide and 3 numbers high.

Let's compute a single element:

C[2][1] = A[2][0] * B[0][1] +
          A[2][1] * B[1][1] +
          A[2][2] * B[2][1] = 

        =    0    *    5    +
             7    *    9    +
             9    *    4    =

        = 99

As I said, when you multiply a vector and a matrix together, the vector is treated as a matrix too. If you do vector × matrix, then vector is treated as a matrix of size 1×n. If it's matrix × vector, then vector has size n×1.

It's not too hard to understand. If you orient your vector incorrectly (1×n instead of nx1 or vice versa), then the width of A would no longer be equal to the height of B.

Resulting vector will always have the same orientation (row or column) as the original vector.


P.S. I'm not familiar with JOML, but if @Bálint is correct, then yourMatrix.transformPosition(yourVector); performs matrix × vector, which is what you need.


P.P.S. @Bálint 's claim that memory ordering of a matrix (row or column major) affects computations is not correct. The above formula always holds true.

\$\endgroup\$
  • \$\begingroup\$ May I know the reason for the downvote? \$\endgroup\$ – HolyBlackCat Jan 31 '17 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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