I believe multiplication operator in Matrix3D has a bug.
mat and m2 are swapped. It should be like this:
return Matrix3D(
mat[0] * m2[0] + mat[1] * m2[4] + mat[2] * m2[8] + mat[3] * m2[12],
mat[0] * m2[1] + mat[1] * m2[5] + mat[2] * m2[9] + mat[3] * m2[13],
mat[0] * m2[2] + mat[1] * m2[6] + mat[2] * m2[10] + mat[3] * m2[14],
mat[0] * m2[3] + mat[1] * m2[7] + mat[2] * m2[11] + mat[3] * m2[15],
mat[4] * m2[0] + mat[5] * m2[4] + mat[6] * m2[8] + mat[7] * m2[12],
mat[4] * m2[1] + mat[5] * m2[5] + mat[6] * m2[9] + mat[7] * m2[13],
mat[4] * m2[2] + mat[5] * m2[6] + mat[6] * m2[10] + mat[7] * m2[14],
mat[4] * m2[3] + mat[5] * m2[7] + mat[6] * m2[11] + mat[7] * m2[15],
mat[8] * m2[0] + mat[9] * m2[4] + mat[10] * m2[8] + mat[11] * m2[12],
mat[8] * m2[1] + mat[9] * m2[5] + mat[10] * m2[9] + mat[11] * m2[13],
mat[8] * m2[2] + mat[9] * m2[6] + mat[10] * m2[10] + mat[11] * m2[14],
mat[8] * m2[3] + mat[9] * m2[7] + mat[10] * m2[11] + mat[11] * m2[15],
mat[12] * m2[0] + mat[13] * m2[4] + mat[14] * m2[8] + mat[15] * m2[12],
mat[12] * m2[1] + mat[13] * m2[5] + mat[14] * m2[9] + mat[15] * m2[13],
mat[12] * m2[2] + mat[13] * m2[6] + mat[14] * m2[10] + mat[15] * m2[14],
mat[12] * m2[3] + mat[13] * m2[7] + mat[14] * m2[11] + mat[15] * m2[15]);