When you dive into apples documentation of matrix3d you will find a short definition "Specifies a 3D transformation as a 4 x 4 matrix." following by the function definition in code:
matrix3d(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m31, m33)
Unless you're a math god you probably think to yourself: "I find the lack of documentation quite disturbing" followed by the question on how to build the really hot Superman stuff on left. The described approach is not meant to be mathematical or complete - I just want to fill a little documentation gap.
Some Linear Algebra
Every complex transformation could be seperated into three basic transformations:
Since this works vice versa these three basic steps could be composed into a giant omnipotent transformation matrix. So far so good, but how do I get from my basic steps to that wild parameter list that matrix3d needs? Let's start with the most simple matrix we have in mathmatics (for making my life easier I'm using Sylvester for matrix math calculations).
The Identity Matrix
identityMatrix = $M([ [1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1] ])
This matrix actually does nothing! Nil! Null! Nada! No pixels get harmed! I divided this matrix in two sections. The red section is the area were you will describe the Rotation and Scale. The yellow area is were you describe the Translation. The other parameters are rarely used in real life except for really weird LSD style FX demos.
We start with creating a scale matrix by multiplying the identity matrix with a scaler (a number).
scaleMatrix = indentityMatrix.multiply(s)
The Scale Matrix
scaleMatrix = $M([ [s,0,0,0], [0,s,0,0], [0,0,s,0], [0,0,0,s] ])
Since we don't want to transform the translation coordinates we rip off the last scale and replace it with 1:
scaleMatrix = $M([ [s,0,0,0], [0,s,0,0], [0,0,s,0], [0,0,0,1] ])
The Rotation Matrixes
Rotation can happen around three Axis X,Y,Z let's say around the degree values a,b,c. The corresponding matrixes to describe this transformation are:
rotationXMatrix = $M([ [1,0,0,0], [0,Math.cos(a), Math.sin(-a), 0], [0,Math.sin(a), Math.cos( a), 0], [0,0,0,1] ]) rotationYMatrix = $M([ [Math.cos( b), 0, Math.sin(b),0], [0,1,0,0], [Math.sin(-b), 0, Math.cos(b), 0], [0,0,0,1] ]) rotationZMatrix = $M([ [Math.cos(c), Math.sin(-c), 0, 0], [Math.sin(c), Math.cos( c), 0, 0], [0,0,1,0], [0,0,0,1] ])
Each matrix describes a rotation around one axis.
The Translation Matrix
translationMatrix = $M([ [1,0,0,0], [0,1,0,0], [0,0,1,0], [tx,ty,tz,1] ])
The translation matrix leaves the most pixels but add the values tx, ty and tz to the final vector result.
The fun part
Yes math can be funny. Each of this matrix can be used in a composition. So if I want to rotate something around all axis and then translate it some pixels then you just multiply the matrixes and that's it:
tM = rotationXMatrix .x(rotationYMatrix) .x(rotationZMatrix) .x(scaleMatrix) .x(translationMatrix)
Finally you apply it to the image:
s = "matrix3d(" s += tM.e(1,1).toFixed(10) + "," + tM.e(1,2).toFixed(10) + "," + tM.e(1,3).toFixed(10) + "," + tM.e(1,4).toFixed(10) + "," s += tM.e(2,1).toFixed(10) + "," + tM.e(2,2).toFixed(10) + "," + tM.e(2,3).toFixed(10) + "," + tM.e(2,4).toFixed(10) + "," s += tM.e(3,1).toFixed(10) + "," + tM.e(3,2).toFixed(10) + "," + tM.e(3,3).toFixed(10) + "," + tM.e(3,4).toFixed(10) + "," s += tM.e(4,1).toFixed(10) + "," + tM.e(4,2).toFixed(10) + "," + tM.e(4,3).toFixed(10) + "," + tM.e(4,4).toFixed(10) s += ")" document.getElementById('darth-vader').style['-webkit-transform'] = s
The first thing is - if you google for linear transformations and you find examples of those matrixes and you wonder why they differ a little from the webkit matrix. The webkit matrix is transponed - so simply transpone it and it should work. The second thing is that CSS does not allow scientific numbers (like 123e-15) as parameters - so you have to use toFixed(numberOfDigits) to normalize them.
Tweet or push it on Hackernews