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!
2 Answers
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);
-
\$\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\$– loryrutaJan 31, 2017 at 8:36
-
\$\begingroup\$ I'm sorry I wasn't been clear in the title. \$\endgroup\$– loryrutaJan 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álintJan 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álintJan 31, 2017 at 15:35
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.
-
\$\begingroup\$ May I know the reason for the downvote? \$\endgroup\$ Jan 31, 2017 at 15:56
Matrix4f.transform*()
. \$\endgroup\$