If you don't understand how to manipulate matrices in Maya, have a look at this post first:
https://rigjuice.blogspot.com/2021/08/important-math-matrices.html
A big chunk of how matrices are useful in Maya is in achieving constraint like effects without heavy constraint nodes.
Let's talk about how the actual effects of constraints are uniquely useful over direct connection.
When trying to get an object to follow another, there is often a lot of messy context and complication that means a direct connection just won't cut it. If two hierarchies are spatially identical then direct connections from members of one to members of the other would usually be enough. But what if the hierarchies don't match? Perhaps you need a joint to follow the orientation of a control but the orientation of said control isn't coming form just that control's rotate values? Perhaps the parent above that control is also rotating, and maybe that parent has a different pivot position than the control, so you've gotta do a bunch of trigonometry to figure out how much rotation of that parent ends up being how much shift in the orientation of the control, and then add that to the rotation coming directly from that control with some math nodes and then who knows what else!
Or you can throw up your hands and say "Orient constraint!" [mic drop]
Such a shame there's no other way when things get that complicated...
Oh wait. Matrices.
This is super handy and I want to make sure nobody gets left behind, so I'll take it one step at a time.
Let's make a cube and... I dunno, a locator.
We want that cube to match the position of that locator, and we'll do it with matrices.
We'll take the matrix attribute of the locator, which provides information about the locator's local transform values. We can use a decomposeMatrix node to convert that matrix data into values that plug into the cube's transform attributes.
Let's focus on translation for now. We're basically emulating a Point Constraint here.
Well that was easy. Buuuut... both those objects were parented to the world - if they were in the same space, why not just use direct connection between their attributes?
Well, err... Yes. Quite. And you would in this situation just use direct connection.
We'll up the complexity in a moment, but first - you know, it sure would be nice if I could move the cube on top of it following the locator. Right now the cube is trapped going only where the locator is doing because it's transform attributes are taken up by the connection. Can't mess with them.
One solution is to put a group above the cube and direct the decomposeMatrix node's output into it instead. Now moving the locator moves that offset group. The cube underneath it comes along for the ride via inheritance, but its transform attributes are free for additional inputs.
Now that's a perfectly fine solution, but if you're using Maya 2020 or later, there's an even better solution that makes life ever so much sweeter. Behold the offsetParentMatrix attribute:
The addition of this attribute to all transform and joint nodes has been making Maya riggers the world over squeal with delight. This new matrix acts as an additional transform layer that sits above the transforms we access through the attribute editor/ channel box. It can be accessed via the attribute editor in either matrix or composition (transform attribute) form:
The advantages are two fold:
1) It means if you want to offset an object while keeping the transform attributes clean you can now just put your attributes into the offsetParentMatrix instead of wrapping the object in an extra group.
2) It means whenever you're doing this matrix tomfoolery, you no longer have to decompose the matrix before plugging in the resulting attributes, you can now just plug the matrix directly into the transform node!
Behold what this locator/cube setup looks like now!
Now that's a handsome looking node network. No decomposeMatrix node needed and no offset group needed. The cube follows, yet it's transform attributes are free for the messing with. I love it.
So that's the standard I'll be using for the rest of this post, but if you're using Maya 2019 or earlier, your best bet is to use a decomposeMatrix node like I showed earlier.
Alright, next complication then.
So this is a super ideal scenario. Like, improbably ideal. Two objects, occupying the same space. But what if they weren't in the same space?
Now the locator has an offset group above it, and that group has a translate X value of -5.
Now if we connect the locator's matrix to the cube's offsetParentMatrix, there will be an offset of 5 units!
Understand, the cube is still following the locator, but the locator's matrix contains its local transform data, and since the locator's transforms are stilled zeroed (it's the locator's parent that has the offset) the cube follows but doesn't match the locator's position:
But what if we don't want an offset? Then what of us?!
Not to worry. We've been getting the matrix information from the locator's matrix attribute. So the cube is following the locator's local position. We want the locator's world position. For that, all we have to do is use the locator's worldMatrix attribute instead. Like a constraint, the world matrix bypasses an object's hierarchy and just asks "Where in the world is Carmen Sandiego this object?"
And like that - complication overcome.
Well that's nice. We could use this instead of a point constraint, in fact we can use this instead of a point, orient, scale, or parent constraint.
This is one of the nicities of matrix based constraints. Because a matrix is translate, rotate, scale, and shear information all in one, we can connect them all with one matrix connection:
But perhaps you don't want it to effect all the transforms. Maybe you only want the cube to follow the rotation or the translation of the locator. What to do then?
We would intercept the matrix connection with a pickMatrix node
What's made this a pretty smooth process so far is that the cube has been in world space this whole. Let's complicate matters by putting it in a group and offsetting it by 10 in translateX.
But now the cube has an offset of 10.
-5 + 10 = 5.
-5 + 10 = 5
Well if what we want is a value that is always going to be the inverse of the parent's matrix, that's what the inverseMatrix attribute is for.
And the matrices we want to multiply are the locator's worldMatrix and the cube's parent's inverseMatrix. And the input order matters, so make sure the world matrix goes into slot 0 and the inverse matrix goes into slot 1.
No bother. Instead of using the inverse matrix, we'll just use the inverseWorldMatrix:
But there are more possible needs to consider, aren't there?
This is perfect if you want one object to follow another, as long as that's the case, this setup can handle whatever you throw at it. But often you want an object to be influenced by multiple driver objects. With a little more nodeling, we can make this happen.
Now plug that blendMatrix node's output into the multMatrix node. The multMatrix node was receiving locator1's worldMatrix before, but now it's receiving a new matrix generated by the blendMatrix node, which is - you guessed it - a blend of locator1 and locator2's world matrices.
Or you could use outside information - like the value of an attribute somewhere - to drive that weight and then you've got yourself a space blend or a space switch.
Naisu desu ne!
It can be tricky to think in terms of matrices at first, and again I reiterate: quite often you'll still just default to using Maya's usual constraint options. And that's fine.
But the more you use matrices, the more you'll see how often the same results can be achieved with way fewer connections.






No comments:
Post a Comment