To answer your question directly:
No, your two pieces of code do not do the same thing. Not even close. Also both snippets of code have nothing to do with matrix multiplication.
As andrew already mentioned, Unity’s Matrix4x4 struct already has a multiply operator which does already calculate the matrix product for you.
We don’t even know what your rv, lhs and rhs variables actually represent (yes, they should represent matrices, however we have no idea about the datatypes and your matrix layout). It looks like your “values” is a two dimensional array or a custom indexer of a class, we don’t know. Anyways, what does Length actually return assuming we talk about 4x4 matrices? Does it return 16 or 4? Yes, when you want to create your own matrix class / type, the matrix multiplication is simply that you calculate the dot product between the row vector of the first matrix with the column vector of the second vector. The resulting value is the value for the intersection of those two vectors. So for a 4x4 matrix you need a total of 16 dot products, nothing more, where each dot product requires 4 multiplications and 3 additions. As you can see in the code I’ve linked above, Unity has actually “unrolled” the code as using two loops would be worse in terms of performance. Using constant values as indices is faster than using a variable.
If, for whatever reason, you want to roll your own matrix type and you want to implement the matrix multiplication yourself in a generic way for arbitrarily sized matrices, yes, you would need 3 loops where the inner most loop would carry out the actual dot product. It’s almost impossible to built upon your code since we don’t even know if your first index denotes the column or row index.
I quickly wrote this bare minimum general purpose matrix class:
public class Matrix
{
// sticking with Unity's convention of having a column major format.
// So the first N values represent the first column where N is the number of rows
public int columns;
public int rows;
public float[] values;
public Matrix(int aRows, int aColumns, bool aSetIdentity = false)
{
rows = aRows;
columns = aColumns;
values = new float[rows * columns];
if (aSetIdentity)
{
int count = rows;
if (columns < count)
count = columns;
for (int i = 0; i < count; i++)
values[i * (rows + 1)] = 1f;
}
}
public float this[int aRow, int aColumn]
{
get => values[aRow + aColumn * rows];
set => values[aRow + aColumn * rows] = value;
}
public static Matrix operator*(Matrix a, Matrix b)
{
if (a.columns != b.rows)
throw new System.Exception("Can't multiply the two matrices, columns of first doesn't match rows of second");
Matrix r = new Matrix(a.rows, b.columns);
for(int i = 0; i < r.columns; i++)
{
for (int j = 0; j < r.rows; j++)
{
float v = 0f;
for (int k = 0; k < a.columns; k++)
v += a[j, k] * b[k, i];
r[j, i] = v;
}
}
return r;
}
public static Matrix Transpose(Matrix aMat)
{
Matrix r = new Matrix(aMat.columns, aMat.rows);
for(int i = 0; i< aMat.columns; i++)
{
for (int j = 0; j < aMat.rows; j++)
{
r[i, j] = aMat[j, i];
}
}
return r;
}
}
I haven’t really tested it, but it should be able to carry out any matrix multiplication you want. You can represent vectors by a 1xN or Nx1 matrix. Keep in mind when you multiply a matrix by a vector, the vector has to be a column vector (so 1 column and N rows). The matrix multiplication works with any compatible matrices, they don’t even need to be square. However the number of columns of the first has to match the number of rows of the second. So multiplying a 20x12 matrix with a 12x9 matrix would yield a 20x9 matrix as you would expect. Just to walk through the example, the 3 loops inside the multiply operator would be as following: The outer “i” loop would make 9 iterations(one for each column), the middle loop “j” would make 20 iterations (one for each two). The innermost “k” loop would make 12 iterations since 12 is the number of elements our dot product requires in this case. Of course for a 4x4 matrix they would all make 4 iterations ^^.