As I mentioned in the last post, I wanted to wrap up the “boring stuff” before moving on. So just a touch of arithmetic and then we’ll get into how to find world matrices, and how to convert from world to local space or any other arbitrary space.
Now in normal algebra as you may recall, the order of multiplication doesn’t matter. Ie a*b == b*a. But when you’re dealing with matrices the order is critical. Math folks refer to this property as commutativity. Normal algebra is commutative, while matrix algebra is non-commutative. This is important when we’re trying to do things like decompose a matrix as you saw in the last post. We knew that the transformation matrix M was equal to the scale matrix S multiplied by the rotation matrix R like this:
M = S * R
So to get the scale on the other side so we can find the value of R, we need to put S-1 on the left of both sides of the equation like so:
S-1 * M = S-1 * S * R
The important thing to note here is that we’ve made sure to add the inverse scale matrix to the left of both sides of the equation. This is important because if we added it to the right side of each equation, we wouldn’t be able to solve it. S * R * S-1 is not the same as what we have done above.
However, one cool thing about inverse matrices is that it doesn’t matter whether they’re on the left side or right side, the result is still the identity matrix. Ie:
S-1 * S == S * S-1
So on the right side of the equation the S-1 and the S multiply together to form the identity matrix I. And we know that anything multiplied by the identity matrix is just itself, which leaves us simply with exactly what we were after.
S-1 * M = R
The rotation matrix R.
Now you may be wondering at this point what about adding matrices together? Or subtracting them or dividing them? Well, as far as I know, when it comes to matrices in 3d, multiplication is all that matters. I’m not aware of any function that requires you to add two matrices together, and division can be thought of as multiplying by the inverse. Kinda weird, but thats how it goes. So anyway this “order matters” property is all I wanted to point out with the algebra. Its a small thing, but its super important. Now lets move on to finding an object’s world matrix.
Finding a the world matrix for a transform is easy. Its a simple matter of multiplying together all the local matrices of the object’s parents. Now as always the order here is important, and to get a world space matrix, you rather intuitively multiply together all the local matrices from the top of the hierarchy to the bottom. So if you have a hierarchy like this:
objA +objB -+objC
Then the world matrix of objC can be found by doing matA * matB * matC. Easy huh? Now if you’re working in maya, maya caches the world matrix for each transform. An object already knows both its local matrix, and its world matrix (also the parent matrix and inverses of them all). So you don’t need to know how to do this in general if you’re in maya, you just query one of these matrix attributes. But now you know whats going on. This knowledge will come in handy below – so bear with me.
What about if you want to get the position of an object in the space of another? Well lets extend the above hierarchy a little bit to look like this:
objA +objB -+objC +objX -+objY --+objD
Now just say we want the position of objD to be the mirror image of objC in world space. Ie when the position of objC is x=10 in world space, we want the position of objD to be -10 in world space, no matter what the parent’s are doing. Obviously you can do this with constraints, but thats not the point. In this case using a constraint is certainly possible, but its a bit of a pain and requires a bunch of setup. So lets learn how to do this with some matrix math, and then we’ll have the choice of doing this using constraints – or an expression, or a quick maya node (python makes it SUPER easy to write your own nodes – maybe a topic for a future post?).
So the first thing we want to do is get the world matrix for objC – because thats what we want mirrored, the world space tx.
import maya.cmds as cmd from vectors import Matrix matA = Matrix( cmd.getAttr( 'objA.matrix' ) ) matB = Matrix( cmd.getAttr( 'objB.matrix' ) ) matC = Matrix( cmd.getAttr( 'objC.matrix' ) ) worldC = matA * matB * matC
Now remember from the first matrix post that the position in a 4×4 matrix is the first 3 values of the bottom row (or the first three values of the last column if you’re in blender). And to mirror the x position we simply do this:
worldD = worldC worldD[ 3 ][ 0 ] = -worldD[ 3 ][ 0 ] #mirror the x position
This gives us the world space matrix for objD – but to apply it back to the object we need to make it a local matrix. This is easy enough to do, we simply multiply the world matrix by the inverse world matrix of objD’s parent. Lets take a step back and see how this works.
As we saw above, the world matrix of a transform is found by multiplying the local matrices of each of the parents together. Lets write this down another way.
worldX = matA * matX worldY = matA * matX * matY worldD = matA * matX * matY * matD #lets do a little bit of substitution worldD = worldY * matD
So as you can see, the world matrix of D is the world matrix of its parent, Y multiplied by the local matrix of D. This last line gets us to the interesting part. So the whole aim of this is to find out matD (the local matrix of objD). Lets see what this looks like with some code.
worldY = matA * matX * matY matD = worldY.inverse() * worldD
As you can see, worldY is the world matrix of objD’s parent. So to get the local matrix of objD, we multiply its world matrix by the inverse of its parent’s world matrix. Sounds confusing but hopefully the above cleared things up. Does that make sense?
Thats about it. Its pretty easy really isn’t it? If you’re in maya you can set an object’s matrix using the xform command, or if you just care about translation you can just get the position from the matrix and set the translation directly.
Anyway I hope that all makes sense. Again, please leave feedback in the comments and spread the word!
This is post 3 in the matrix series.
This post is public domain
This entry was posted on Sunday, September 26th, 2010 at 13:08 and is filed under main, tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.