Tristan Elliott
Posted on October 5, 2024
Table of contents
Resources
My app on the Google play store
My app's GitHub code
Why use matrix multiplication?
- Spinning cube UI demonstration
- So as it turns out, if we look at the documentation for this open gl cube. One major component is matrix multiplication. Well, actually the entire 3d cube animation is basically just matrixes and manipulating them.
The actual code:
- So here is the code we are going to look at:
/**
* matrixMultiply
* // temporary array array1 array2
* [ 0, 1, 2, 3 ] [ 1, 0, 0, 0 ] [ 1, 0, 0, 0 ]
* [ 4, 5, 6, 7 ] [ 0, 1, 0, 0 ] [ 0, 1, 0, 0 ]
* [ 8, 9, 10, 11 ] [ 0, 0, 1, 0 ] [ 0, 0, 1, 0 ]
* [ 12, 13, 14, 15 ] [ 0, 0, 0, 1 ] [ 0, 0, 0, 1 ]
*
*
*
* */
// [location in temporary array] = index x index + index x index
// [0] = 0*0 + 4*1 + 8*2 + 12*3
// [1] = 1*0 + 5*1 + 9*2 + 13*3
// [2] = 2*0 + 6*1 +10*2 + 14*3
// [5] = 1*4 + 5*5 + 9*6 + 13*7
void matrixMultiply(float* destination, float* operand1, float* operand2)
{
float theResult[16]; // Temporary matrix to store the result
// Perform matrix multiplication for each element in the 4x4 result matrix
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
// Calculate the dot product for the (i, j) element in the result matrix
theResult[4 * i + j] = operand1[j] * operand2[4 * i]
+ operand1[4 + j] * operand2[4 * i + 1]
+ operand1[8 + j] * operand2[4 * i + 2]
+ operand1[12 + j] * operand2[4 * i + 3];
}
}
// Copy the result into the destination matrix
for(int i = 0; i < 16; i++)
{
destination[i] = theResult[i];
}
}
- I won't go into the details of the mathematics of matrix multiplication(you can google that yourself). However, the short answer is that we need to multiply the columns by the rows.
- This leads us into our first hurdle, of how do we represent a matrix? The answer, is just to use an array (underwhelming but effecting). So the variable of
float theResult[16];
is how we represent a4x4 matrix
. Which admittedly is hard to imagine, so I created this visual:
* [ 0, 1, 2, 3 ] --------rows
* [ 4, 5, 6, 7 ] |
* [ 8, 9, 10, 11 ] |
* [ 12, 13, 14, 15 ] |columns
- When dealing with arrays we want to represent a matrix, this is the proper mental model to have. Column one holds the indexes of
0,4,8,12
and row one holds the indexes of0,1,2,3
.
Breaking down the key points of the code
- We can start with the two parameters:
float* operand1 and float* operand2
. Which technically are float pointers but for those uninitiated ,In C++, pointers and arrays are closely related. The name of an array can be used as a pointer to its initial element.
(Stroustrup, Bjarne. The C++ Programming Language. Addison-Wesley, 2013, p. 179.) So those float pointers are actually the two arrays we want to multiply - then we have the
float theResult[16];
, which is another array that holds 16 floats and will temporary hold our array values. - next is the nested for loops:
for(int i = 0; i < 4; i++){
for(int j = 0; j < 4; j++){
}
}
- These loops are how we are navigating around the
matrix
. If you are curious about the number 4. we are looping from 0-3(4 loops) because the matrix is 4x4. If the matric was 5x5 then we would loop from 0-4. we use
j
to navigate the columns andi
to navigate the rowsInside of the for loops we have 2 problems,
1) navigating the theResult array
- We have to accurately navigate the row and then make a jump to the column and we do so with this:
theResult[4 * i + j]
. The 4 is how we accurately navigate the columns. This number would change depending on out matrix
2) doing the actual multiplication
- This section is a little confusing (I did not do a good job explaining it):
theResult[4 * i + j] = operand1[j] * operand2[4 * i]
+ operand1[4 + j] * operand2[4 * i + 1]
+ operand1[8 + j] * operand2[4 * i + 2]
+ operand1[12 + j] * operand2[4 * i +3];
-
Now, I want to stress not to memorize this code but instead try to grasp its broader understanding. When doing matrix multiplication we must do these four things:
- 1) navigate the array:
theResult[4 * i + j]
- 2) navigate the columns:
operand1[4 + j]
- 3) navigate the rows:
operand2[4 * i + 1]
- 4) multiply and add:
+ operand1[12 + j] * operand2[4 * i +3];
- 1) navigate the array:
Ultimately, what we need to do is to take the results of the first column times the first row and put the results inside of the result array. Know that
operand1[4 + j]
represent the columns andoperand2[4 * i + 1]
represents the row
Conclusion
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.
💖 💪 🙅 🚩
Tristan Elliott
Posted on October 5, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.