1
\$\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\$
1
  • \$\begingroup\$ Check the JOML documentation. There are plenty of variations of Matrix4f.transform*(). \$\endgroup\$
    – msell
    Jan 31, 2017 at 14:47

2 Answers 2

4
\$\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\$
8
  • \$\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, 2017 at 8:36
  • \$\begingroup\$ I'm sorry I wasn't been clear in the title. \$\endgroup\$
    – loryruta
    Jan 31, 2017 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, 2017 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\$ Jan 31, 2017 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, 2017 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\$
1
  • \$\begingroup\$ May I know the reason for the downvote? \$\endgroup\$ Jan 31, 2017 at 15:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .