Matrices
Must be viewed with Firefox
There are 3 areas in which the layout of matrices is different
in each case:
(1) mathematically, (2) in OpenGL/DirectX, (3) in source code (memory).
Lots of programmers spend a lot of time figuring it out (and still not getting it), so I hope this helps.
(1) Matrices mathematically
Mathematically the layout of a 4x4 matrix
M is:
$\left[\begin{array}{cccc}{m}_{\mathrm{11}}& {m}_{\mathrm{12}}& {m}_{\mathrm{13}}& {m}_{\mathrm{14}}\\ {m}_{\mathrm{21}}& {m}_{\mathrm{22}}& {m}_{\mathrm{23}}& {m}_{\mathrm{24}}\\ {m}_{\mathrm{31}}& {m}_{\mathrm{32}}& {m}_{\mathrm{33}}& {m}_{\mathrm{34}}\\ {m}_{\mathrm{41}}& {m}_{\mathrm{42}}& {m}_{\mathrm{43}}& {m}_{\mathrm{44}}\end{array}\right]$
where m_{rc} stands for the element m of matrix
M at row
_{r} and column _{c}, for example
m_{23} stands for the element in matrix M
at row 2 and column 3.
For example, in this matrix M:
$\left[\begin{array}{cccc}0.32& 3.04& 0.82& 3.17\\ 5.01& 3.98& 8.83& 9.83\\ 8.88& 6.44& 4.32& 2.43\\ 9.64& 3.23& 4.04& 9.28\end{array}\right]$
element m_{23} = 8.83, m_{14} = 3.17,
m_{41} = 9.64, m_{22} = 3.98,
m_{44} = 9.28, m_{51} = doesn't exist.
(2) Matrices in OpenGL/DirectX
Each axis (
X, Y, Z, W) in a matrix in OpenGL is laid out
in (or shall we say "interpreted as") columns,
not rows, that's why matrices in OpenGL are said to be "columnmajor".
On the contrary, Microsoft's DirectX treats each row, not column, as an axis,
that's why matrices in DirectX are said to be "rowmajor".
For example, the X axis in the above matrix is
read/interpreted
by OpenGL as:
$\left[\begin{array}{cccc}0.32& 5.01& 8.88& 9.64\end{array}\right]$
which mathematically equals to
$\left[\begin{array}{cccc}{m}_{11}& {m}_{21}& {m}_{31}& {m}_{41}\end{array}\right]$
by DirectX as:
$\left[\begin{array}{cccc}0.32& 3.04& 0.82& 3.17\end{array}\right]$
which mathematically equals to
$\left[\begin{array}{cccc}{m}_{11}& {m}_{12}& {m}_{13}& {m}_{14}\end{array}\right]$
One more example, the Z axis in the above matrix is
read/interpreted
by OpenGL as:
$\left[\begin{array}{cccc}0.82& 8.83& 4.32& 4.04\end{array}\right]$
which mathematically equals to
$\left[\begin{array}{cccc}{m}_{13}& {m}_{23}& {m}_{33}& {m}_{43}\end{array}\right]$
by DirectX as:
$\left[\begin{array}{cccc}8.88& 6.44& 4.32& 2.43\end{array}\right]$
which mathematically equals to
$\left[\begin{array}{cccc}{m}_{31}& {m}_{32}& {m}_{33}& {m}_{34}\end{array}\right]$
(3) Matrices in source code (memory)
A 4x4 matrix in C/C++ is usually stored as either
a) An array of numbers (typically floats):
float arr[16];
The advantage of this approach is that since OpenGL requires the matrices to
be sent to it as an array of numbers, you don't have to do any extra
work/conversion since
your matrix is already stored as an array of numbers (floats) in your source
code (memory).
b) As 16 variables whose names are usually mnemonics of the
elements of a matrix represented mathematically as m_{rc}:
float m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42,
m43, m44;
So for example m34 is a var with a mnemonic name which conveniently
suggests that it stands for the element at row 3 column 4.
The advantage of this approach is that the elements of the matrix from
source code are called the same as in matrices represented mathematically (in
math books), but the disadvantage is that you obviously need to convert the
16 vars of the matrix to an array before sending the matrix/data to
OpenGL since as stated before, OpenGL requires matrices to be sent as an array
of numbers.
Since people mostly favor the first approach let's explore it.
Let's take a 4x4 matrix with random numbers for its XYZW axes (W
isn't really an axis but you get the point):
float arr[] = {9.15, 23.9, 20.3, 0.4, 0.3, 0.72, 4.32, 0.88, 14.2, 38.0, 50.5,
29.3, 4.42, 22.7, 39.9, 18.2};
In memory (source code) we refer to each element of this matrix by its array
index which ranges from 0 to 15,
for example arr[0] = 9.15, arr[1] = 23.9, arr[16] = doesn't exist.
Since OpenGL interprets the columns, not the rows, of a matrix as the
XYZW axes here's how OpenGL views the array arr as a matrix:
Axis X 
Axis Y 
Axis Z 
W 
9.15 
0.3 
14.2 
4.42 
23.9 
0.72 
38.0 
22.7 
20.3 
4.32 
50.5 
39.9 
0.4 
0.88 
29.3 
18.2 
 which corresponds to the arr indices: 
Axis X 
Axis Y 
Axis Z 
W 
arr[0] 
arr[4] 
arr[8] 
arr[12] 
arr[1] 
arr[5] 
arr[9] 
arr[13] 
arr[2] 
arr[6] 
arr[10] 
arr[14] 
arr[3] 
arr[7] 
arr[11] 
arr[15] 

That's why, to OpenGL axis Y = [0.3, 0.72, 4.32, 0.88] whose indices
in our float array arr are 4, 5, 6, and 7 accordingly. So
if you wanna change the values of the Y axis from our array arr
to say [10.0, 12.3, 9.41, 15.0] you
must be careful to use the correct array indices:
arr[4] = 10.0;
arr[5] = 12.3;
arr[6] = 9.41;
arr[7] = 15.0;
Now that we changed the values of the Y axis from our array arr,
the above matrix/array looks like this in source code (memory):
float arr[] = {
9.15, 23.9, 20.3, 0.4,
10.0, 12.3, 9.41, 15.0,
14.2, 38.0, 50.5, 29.3,
4.42, 22.7, 39.9, 18.2};
And OpenGL views it like this:
Axis X 
Axis Y 
Axis Z 
W 
9.15 
10.0 
14.2 
4.42 
23.9 
12.3 
38.0 
22.7 
20.3 
9.41 
50.5 
39.9 
0.4 
15.0 
29.3 
18.2 
The same logic applies to the other axes. It _is_ quite confusing and
takes quite some time to remember and get used to these nuances.
Bonus: translate (multiply) a vector by a translation matrix
Translation matrix:
Axis X 
Axis Y 
Axis Z 
W 
arr[0] = 1 
arr[4] = 0 
arr[8] = 0 
arr[12] 
arr[1] = 0 
arr[5] = 1 
arr[9] = 0 
arr[13] 
arr[2] = 0 
arr[6] = 0 
arr[10] = 1 
arr[14] 
arr[3] = 0 
arr[7] = 0 
arr[11] = 0 
arr[15] = 1 

*


=

vec4 result 
x + arr[12] 
y + arr[13] 
z + arr[14] 
w 

Notice a few points:
 w of vec4 must be equal to 1.0 because arr[12], arr[13]
and arr[14] are multiplied by it and added to x, y, z respectively which
is all there is to translation.
 observe the values of the gray, blue and red cells in the matrix
so that after multiplication each field in vec4 will be equal to its own
value plus arr[12], arr[13] or arr[14] accordingly.
 arr[12], arr[13] and arr[14] are input fields which control how much vec4
will be translated in the x, y and z directions accordingly.
Exercise
Translate vector (1.5, 0.3, 0.5, 1.0) by x=1.2, y=2.3, z=0.7
Mathematical solution:
$\left[\begin{array}{cccc}{m}_{11}& {m}_{12}& {m}_{13}& {m}_{14}\\ {m}_{21}& {m}_{22}& {m}_{23}& {m}_{24}\\ {m}_{31}& {m}_{32}& {m}_{33}& {m}_{34}\\ {m}_{41}& {m}_{42}& {m}_{43}& {m}_{44}\end{array}\right]*\left[\begin{array}{c}x\\ y\\ z\\ w\end{array}\right]=$
$\left[\begin{array}{cccc}1.0& 0.0& 0.0& \mathrm{1.2}\\ 0.0& 1.0& 0.0& \mathrm{2.3}\\ 0.0& 0.0& 1.0& \mathrm{0.7}\\ 0.0& 0.0& 0.0& \mathrm{1.0}\end{array}\right]*\left[\begin{array}{c}1.5\\ 0.3\\ 0.5\\ 1.0\end{array}\right]=\left[\begin{array}{c}1.0*1.5+0.0*0.3+0.0*0.5+1.2*1.0\\ 0.0*1.5+1.0*0.3+0.0*0.5+2.3*1.0\\ 0.0*1.5+0.0*0.3+1.0*0.5+0.7*1.0\\ 0.0*1.5+0.0*0.3+0.0*0.5+1.0*1.0\end{array}\right]=\left[\begin{array}{c}2.7\\ 2.6\\ 1.2\\ 1.0\end{array}\right]$
Programming solution using column major notation like OpenGL:
General idea:
$\left[\begin{array}{cccc}{\mathrm{arr}}_{\mathrm{[0]}}& {\mathrm{arr}}_{\mathrm{[4]}}& {\mathrm{arr}}_{\mathrm{[8]}}& {\mathrm{arr}}_{\mathrm{[12]}}\\ {\mathrm{arr}}_{\mathrm{[1]}}& {\mathrm{arr}}_{\mathrm{[5]}}& {\mathrm{arr}}_{\mathrm{[9]}}& {\mathrm{arr}}_{\mathrm{[13]}}\\ {\mathrm{arr}}_{\mathrm{[2]}}& {\mathrm{arr}}_{\mathrm{[6]}}& {\mathrm{arr}}_{\mathrm{[10]}}& {\mathrm{arr}}_{\mathrm{[14]}}\\ {\mathrm{arr}}_{\mathrm{[3]}}& {\mathrm{arr}}_{\mathrm{[7]}}& {\mathrm{arr}}_{\mathrm{[11]}}& {\mathrm{arr}}_{\mathrm{[15]}}\end{array}\right]*\left[\begin{array}{c}{v}_{\mathrm{[0]}}\\ {v}_{\mathrm{[1]}}\\ {v}_{\mathrm{[2]}}\\ {v}_{\mathrm{[3]}}\end{array}\right]$
Actual code: