July 2017

I was so amazed the first time I learned about the script node. Now that I look at it, I feel like it is a necessity, for sure, but back before I had no idea that they, callbacks and scriptJobs existed, I often thought that it would be amazing to have a way of running code at different points of interaction with rigs (and any other maya scene). So when I finally learned about them, naturally, I tried to think of cool things I could do with them as, and today I will have a brief look at some of these alleged cool use cases and some not really cool ones.

Disclaimer: Raffaele over at the Cult of rig has some great videos that go over callbacks, script nodes and a great explanation of how they fit in the overall maya event loop. Once I saw those videos everything started making much more sense, when working with callbacks and script nodes, so I cannot recommend them enough. He goes over the use of script nodes to manage callbacks and I will not be going over that, so definitely have a look at his latest videos.

Additionally, this post will be mostly speculative since a lot of these ideas are just that – ideas that I have not yet tried, but sound like they might be cool.

Also, there are a few examples of unethical behaviour mentioned as potential uses of the script node, so I want to make it clear that I DO NOT encourage them, but instead I want people to be familiar with them, in order to be able to protect themselves.

Table of contents

script nodes in rigging

When I think about script nodes I instantly picture animators opening/referencing scenes and cool stuff happening without them having to touch anything, and yeah, I suppose that is probably the major use case scenario. I wouldn’t imagine myself needing a script node in my files, since I can easily run the code I want to run whenever I want to.

Rigging systems

That being said, though, say we have a rigging system, where we script most of the rig, but we still do certain things in the viewport as well, quite possibly through some cool custom UI we’ve built. That UI will very likely rely on some metadata inside of the scene and probably some message connections between nodes. Wouldn’t it be nice if this UI auto-populates itself and pops up ready to be directly used, without you having to touch anything? Sure, you can probably do that with just pressing a single button after the scene is opened, but I think having it happen automatically feels cooler.

Additionally, I know a lot of people have debug modes of their rigs, which take care of what I am about to say, but if you don’t it might be nice to have a script node remove the restrictions you have added for animators and turn on any diagnostics you have in the scene.

Analytics

Recently, I have been looking into running some minor analytics on rigs and I have to say I see why every marketing person out there praises analytics. It is an eye-opening experience seeing how many unitConversion nodes you have in the scene and maybe plotting that against the performance results you are getting to see if they are slowing you down (they probably are) and by how much (probably not much).

Again, this one is going to be purely speculative, but maybe we can gather some data on our own practices when rigging. Say for example, query the time spent working on a specific rig or maybe even run performance tests on opening or closing the file in debug mode and store that data over time.

script nodes in animation

So, even though, there might be some use cases for script nodes in rigging, I think they can be really useful for automating boring stuff for animators. Whether it is going to be related to building and loading certain UIs, creating certain connections between assets or similarly to the previous paragraph – analytics – we can use the script node to make animator’s and our work slightly easier, more intuitive and informative.

Attaching props

This is probably the best use case of the script node that I know of. I know different places and teams definitely have different approaches to this issue, whether it may be custom tools that are used to bring in and attach props or, god forbid, having all props in a character rig file and using switches to turn them on and off, it is a common aspect of pipelines. I think a nice solution are script nodes. Let’s imagine the following case.

Say we have a character that needs to have all kinds of different weapons, clothes and other wearable props. Let’s suppose all these are their own separate assets, so maintaining them is easier and nicer. The way script nodes would help us in this case is by executing a piece of code that would attach our prop to our character on bringing that prop in a scene where the character exists. That would be a nice and simple solution. Of course, it could lead to some issues, for example, having animators bring the prop in before the character or maybe have multiple instances of the character, so our prop does not know to which it should attach, but generally these issues are either solved or prevented by having some pipeline rules.

Building interfaces

This one is probably more appropriate for freelancers, free rigs and cases where the people working on a project don’t necessarily share a pipeline.

Animators often have to do a lot of animation in a short time. Anything we can do to help them out is going to be great for our production. A nice way we can do that is by giving them easy to use interfaces to speed up their workflow. I know a lot of animators use pickers, so maybe we can use script nodes to build them with all their jazz on the spot. Additionally, they might be like me and love marking menus. Wouldn’t it be great to be able to build it for them on the spot and maybe even show them a message, so they know how to bring it up? Then of course, clean up after ourselves when they close the scene, so we do not mess about with their other work.

script nodes in pipeline

Now even though script nodes can be quite handy for rigging and animation, I think where they really shine is in pipeline. Granted, pipeline would probably use scriptJobs to do most of the things I am going to mention, maybe small teams or even freelancers can sort of simulate a pipeline by using script nodes.

Analytics

I talked about analyzing our behaviour when rigging, but I think it is much more practical to actually analyze the working files of animators and lighters, as the data in there will probably be a bit more interesting. For example, we can run performance tests on certain scenes when opening/closing them and then at the end of a production identify problematic areas, so we can potentially have a look at improving them.

Additionally, this one feels a bit unethical, but if we are upfront about it, it might be cool to store some data on how people interact with our rigs. Create some callbacks on nodes and attributes we are interested in, and have a look at how they are being used. Then when closing the file save that data somewhere we can have a look at it, or in any other way send it to ourselves. We might just find that 50% of the control we are adding to rigs is not actually being utilized.

Licensing

How can we prevent our files from being used by people we do not want to use them? I think “do not let them have our files in the first place” is the reasonable solution, but maybe we cannot entirely prevent that. In cases like that, we can add a level of protection by using script nodes.

Since we can fire a script on opening a scene file, that means that we have some room for licensing our rigs. Now, while I am not entirely sure what the best way for forbidding access to a rig would be, I have a couple of ideas.

Inform us

This first option is not necessarily forbidding anyone from using our rig, but we might be able to setup a way of informing us of unauthorized access to our rig. For example, we can check if the user is unauthorized by looking for a specific environment variable that members of our team would have, looking up maya’s license or maybe even the OS username. If we find that the user should not be using our file we can send the information to ourselves by using a simple HTTP request.

I know this can easily be bypassed, but chances are it might just work in certain cases.

Obviously, this involves an amount of tracking users, which I really DO NOT encourage, but I could imagine certain people in certain cases might want to do that.

Break the rig

If the file is being opened as opposed to referenced we have the ability to break connections, delete files, etc. If that is the case we can easily destroy our rig on opening it, so people cannot even see it.

If it is being referenced though, we do not have that level of control. In cases like this it might be worth having an obscure way of breaking your rig, built into the rig itself. I do not think this could ever be bulletproof, but I think it is certainly possible to make it way too annoying for anyone to mess with it. That being said, it is likely that doing that is going to introduce some overhead in your rigs, so it is not an entirely too graceful way of going about it.

Close or hang maya

I feel like I am getting silly here, but I think that for people that really do not want anyone touching their rigs, they can certainly do a maya.cmds.quit(f=1) in the script node and be done with it. Additionally, if you would like to be extra nasty, I suppose you could do something along the lines of

import maya.cmds as mc

while True:
    mc.warning("All work and no play makes Jack a dull boy!")

Alternatively, if you do not want to be nasty I think the nicest way of denying access would be to just unload or remove the reference, but you would need to have a stable way of finding the reference node. If you cannot do that, you could also do a mc.file(new=1, f=1) to pop out of the scene.

script nodes security

So, escalating from the previous section, I am sure you could imagine that if we could hang and crash maya we probably can do much worse things. Since we are able to run python, even though we have a smaller than the default amount of packages included with maya, we are able to actually execute code entirely unrelated to maya. You know, create/read folders and files, run native OS commands, etc. What if we create and read files from the user’s machine that we really shouldn’t be? Additionally, there are included libraries in Maya that are making it trivial to send data over the internet. You can see where I am going with this.

I do not want to carry on mentioning unethical schemes, but I do want to raise your awareness about the extent to which script nodes can be used. Essentially, everything that is available to the user running maya is available to the script node and therefore to the person that published that file. Which leads us to the next point.

Protection

Now, depending on your OS, the ways that we can protect ourselves from malicious vary, but there are a couple of concepts that we can apply to all of them.

Careful when downloading files

The easiest thing we can do is to not use any files created by other people. Depending on what you are doing in Maya that might be okay, but I for example, very often open popular rigs to see how have they done certain things and how can I improve on top of them.

If you like me do occasionally load up files from the web, there is another check you could do. Open the .ma file with a text editor and check if there are script nodes in there. Since text editors can have a hard time with larger files, you can always write a small python function to check that for you. If the file is a binary file, though, you are out of luck and there is no way to check what is inside of it other than opening it.

Permissions

The obvious one. If the user running maya does not have access to a certain directory, maya doesn’t and hence the script node doesn’t. Please DO NOT run maya as a super user or administrator as that would obviously give maya access to anything.

The practical way of doing it I would say is to create a specific user which is going to run Maya and give it permissions only under a specific directory where you would store all your Maya work. That way, everything else is out of reach.

Firewall

Limit Maya’s access to the internet. That can be a reasonable solution, but Autodesk probably wouldn’t be happy with it, as that way you cannot sign into your Autodesk account.

Conclusion

As you can see script nodes can be really powerful in terms of use cases in a proper production or freelancing and also powerful in malicious ways. I like to believe, though, that people in CG are generally quite intelligent and nice, so therefore I can safely say I am not troubled by the potential exploits.

Rigging clothes of not very high res cartoon characters can get very tricky as with a lot of the designs intersections are inevitable. It can get very frustrating for animators to fix issues like that, and the easier we can make it for them the better. Today, I am going to have a quick look at a setup that can help with fixing small intersections, but can also be used to achieve a variety of effects. It is a nice simple tool that maya provides us – the softMod deformer – but they have not necessarily provided us with a great interface to interact with it, so we will have a look at a way to make it work a bit nicer for us.

Maya softMod deformer - demo

Essentially, what we have is a couple of controls, where one of them defines the origin of the deformation and the other one is actually deforming the geometry. The nice thing is that by placing the deformer after the skinCluster in the chain we can have the controls follow any of our rig controls, in order to be able to easily pick them up and deform our geo in world space.

tl;dr: You can connect your own matrices to the softMod deformer’s softModXforms attribute, in order to have your own controls driving the softMod deformation in world space after the skinCluster.

Figuring it out

When I was trying to figure out what matrices I need to plug to which attributes, I was having a hard time making sense of the available documentation on the subject. I found a few people online making use of the preBindMatrix attribute, but I could not get that to work properly, so naturally, I thought screw it, I am going to write my own softMod out of frustration.

After a couple of minutes of setting up the boilerplate code I was up and running, and it was a really simple effect that I needed, so the code was quite straightforward. I was having issues with the deformation not being accurate in world space though, so I had to account for that, which meant I would multiply by the worldInverseMatrix of the origin object I am using, then deform by the local matrix of the deforming object and finally multiply by the worldMatrix of the origin object in order to bring it back to world.

Doing that after having a look at making it work with the vanilla Maya softMod, though, made me think that I have seen similarly named matrices in the deformer attributes. Namely, the children of the compound softModXformspreMatrix, weightedMatrix and postMatrix. Connecting the proper matrices to these attributes, gave me the result I was looking for.

The reason I am saying this, is because I wanted to point out that is really helpful sometimes to just try and write your own node/deformer/plugin/script in order to understand what Maya is doing and why. I did this exact same thing when trying to figure out how to account for joint orientation in my matrix constraint post.

The actual softMod deformer setup

With that out of the way let us have a look at the graph.

Maya softMod deformer - node graph

So essentially, by making use of the softModXforms we are building exactly what I mentioned in the previous chapter, where we account for the world positioning of our deformer controls, by bringing back the deformation to local space, deforming our object and then placing it back in it’s world position.

Of course, these locators are there just so I can have a nice and simple example. In reality, the way this would work is that these locators would probably be replaced by two controls – one controlling the origin of the deformation and the other actually deforming the object. Additionally, exposing the falloffRadius attribute of the softMod deformer somewhere on these controls would be a good idea as well.

A nice benefit of having our own controls driving the softMod is that we can get rid of the softModHandle since it won’t be doing anything, which would result in a cleaner scene.

Using the tool in production

Now, I could imagine a couple of approaches for using this setup. The first one would be to build these into your rigs before passing them to the animators. Depending on the geometry, though, this could easily be an overkill if they are not used in every shot. If that is the case, the better approach would be to build some sort of an UI for the animators to create these into their scenes.

Additionally, while looking for info on this setup, I stumbled upon a few people having a riveted object be the origin control, so essentially achieving something similar to the infamous tweaker dorito setup.

Conclusion

Even though, the softMod is a very simple deformer, in cartoony productions I could imagine it being very handy for fixing intersections and giving the animators control over finer deformations.

During the week, I got a comment on the first post in my Maya matrix nodes series – the matrix constraint one – about using the wtAddMatrix node to achieve the multiple targets with blending weights functionality similar to constraints. I have stumbled upon the wtAddMatrix node, but I think it is the fact that Autodesk have made it very fiddly to work with it – we need to show all attributes in the node editor and we have 0 access to setting the weight plug – that put me off ever using it. That being said, when RigVader commented on that post I decided I will give it a go. Since it actually works quite nicely, today I am looking at blending matrices in Maya.

Disclaimer: I will be using the matrix constraint setup outlined in the post I mentioned, so it might be worth having a look at that one if you have missed it.

tl;dr: Using the wtAddMatrix we can blend between matrices before we plug the output into a matrix constraint setup to achieve having multiple targets with different weights.

Turns out, the wtAddMatrix is a really handy node. It gives us the chance to plug a number of matrices in the .matrixIn plugs of the .wtMatrix array attribute, and give them weight in the .weightIn plug. That, effectively lets us blend between them.

Blending matrices for a matrix constraint setup

So, now that we know we can blend matrices, we just need to figure out exactly what do we need to blend.

Let us first have a look at the simpler case – not maintaining the offset.

Blending matrices - matrix constraint with no offset

The group1 on the graph is the parent of pCube1 and is used just so we convert the world matrix into a relative to the parent matrix, without using the parentInverseMatrix. The reason for that is we do not want to create benign cycles, which Raff sometimes talks about on the Cult of Rig streams. Other than that, everything seems to be pretty straightforward.

Bear in mind, the wtAddMatrix node does not normalize the weights, which means that we could have all of the targets fully influence our object. What is more, you could also push them beyond 1 or negate them, which would result in seemingly odd results, but that might just be what you need in some cases.

Maintaining the offset

Often we need to maintain the offset in order to achieve the desired behaviour, so the way we do that is we resort to the multMatrix node once more. I am not going in detail, as there are already a couple of ways you can do that outlined in the previous post, but let us see how it fits in our graph.

Blending matrices - matrix constraint maintaing offset

The two additional multMatrix nodes let us multiply the local offset for the current target by the world matrix of the current target, effectively constraining the object but also maintaining the initial offset.

Now, however clean and simple it may be, the graph gets to be a bit long. What this means is, it is probably getting a bit slower to evaluate as well. That is why, I thought I would do a bit of a performance test to see if there still is any benefit to using this setup over a parentConstraint.

Performance

The way I usually do my tests is either loop a few hundred times in the scene and build the setup or build it once, save it in a file and then import the file a few hundred times and let it run with some dummy animation. Then I use Maya 2017’s Evaluation toolkit to Run a performance test, which gives us info about the performance in the different evaluation methods – DG, Serial and Parallel. Since, the results vary quite a bit, what I usually do is, run it three times and take the best ones.

In this case, I built the two setups in separate files, both with 2 target objects and maintain offset. Then I ran the tests on 200 hundred imported setups.

So here are the results.

Parent constraint
Playback Speeds
===============
    DG  = 89.8204 fps
    EMS = 20.1613 fps
    EMP = 59.2885 fps
Matrix constraint
Playback Speeds
===============
    DG  = 91.4634 fps
    EMS = 24.6305 fps
    EMP = 67.2646 fps

Bear in mind these tests are done on my 5 years old laptop, so the results you are going to get if you are to repeat this test are going to be significantly better.

As you can see even with the extended graph we are still getting about 7.5 fps increase by using the matrix constraint setup with blending matrices. Considering, we have 200 hundred instances in the scene (which is by no means a large number), that means we have about .0375 fps increase per setup, which in turn means that on every 26 setups we win a frame.

Conclusion

So, there we have it, an even larger part of the parentConstraint functionality, can be implemented by just using matrix nodes. What this means is we can keep our outliner cleaner and get a better performance out of our rigs at the same time, which is a total win win.

Thanks to RigVader for pointing the wtAddMatrix node as a potential solution, it really works quite nicely!

This post is a part of a three post series, where I implement popular rigging functionalities with just using maya’s native matrix nodes.

Rivets are one of those things that blew my mind the first time I learned of them. Honestly, at the time, the ability to stick an object to the deforming components of a geometry seemed almost magical. Although, the more you learn about how geometries work in Maya, the more sense rivets start to make. The stigma around them, though, has always been that they are a bit slow, since they have to wait for the underlying geometry to evaluate and only then can they evaluate as well. And even though that is still the case, it seems that since parallel was introduced the performance has increased significantly.

It is worth trying to simplify and clean rivets up, considering how handy they are for rigging setups like:
– twist distributing ribbons
– bendy/curvy limbs
– sticking objects to geometries after squash and stretch
– sticking controls to geometries
– driving joints sliding on surfaces

and others.

When I refer to the classic rivet or the aimConstraint rivet, it is this one that I am talking about. I have seen it used by many riggers and also lots of lighters as well.

The purpose of this approach is to get rid of the aimConstraint that is driving the rotation of the rivet. Additionally, I have seen a pointConstraint used as well, in order to account for the parent inverse matrix, which would also be replaced by this setup. Even though we are stripping constraints, the performance increase is not very large, so the major benefit of the matrix rivet is a cleaner graph.

TL;DR: We are going to plug the information from a pointOnSurfaceInfo node directly into a fourByFourMatrix node, in attempt to remove constraints from our rigs.

Disclaimer: Bear in mind, I will be only looking at riveting an object to a NURBS surface. Riveting to poly geo would need to be done through the same old loft setup.

Limitations: Since we are extracting our final transform values using a decomposeMatrix node, we do not have the option to use any rotation order other than XYZ, as at the moment the decomposeMatrix node does not support other orders. A way around it, though, is taking the outputQuat attribute and pluging it into an quatToEuler node which actually supports different rotate orders.

Difference between follicle and aimConstraint rivet

Matrix rivet - follicle and classical rivet differences

Matrix rivet - follicle and classic rivet graph

The locator is riveted using an aimConstraint. You can see there is a small difference in the rotations of the follicle and the locator. Why is that?

The classical rivet setup connects the tangentV and normal attributes of a pointOnSurface to the aimConstraint. The third axis is then the cross product of these two. But it seems like the follicle is actually using the tangentU vector for it’s calculations, since we get this difference between the two setups.

Choosing to plug the tangentU into the aimConstraint, instead of tangentV, results in the same behaviour as a follicle. To be honest, I am not sure which one would be preferable. In the construction of our matrix rivet, though, we have full control over that.

Why not follicles?

As I already said, in parallel, follicles are fast! Honestly, for most of my riveting needs I wouldn’t mind using a follicle. The one aspect of follicles I really dislike though, is the fact that it operates through a shape node. I understand it was not meant for rigging, and having the objects clearly recognizable both in the outliner and the viewport is important, but in my case it is just adding up to clutter. Ideally, I like avoiding unnecessary DAG nodes, since they only get in the way.

Additionally, have you had a look at the follicle shape node? I mean, there are so many hair related attributes, it is a shame to use it just for parameterU and parameterV.

Therefore, if we could use a non-DAG network of simple nodes to do the same job without any added overhead, why should we clutter our rigs?

Constructing the matrix rivet

So, the way matrices work in Maya is that the first three rows of the matrix describe the X, Y and Z axis and the fourth row is the position. Since, this is an oversimplification I would strongly suggest having a look at some matrix math resources and definitely watching the Cult of Rig streams, if you would like to learn more about matrices.

What this means to us, though, is that if we have two vectors and a position we can always construct a matrix out of them, since the cross product of the two vectors will give us a third one. So here is how our matrix construction looks like in the graph.

Matrix rivet - constructing the matrix

So, as you can see, we are utilizing the fourByFourMatrix node to construct a matrix. Additionally, we use the vectorProduct node set to Cross Product to construct our third axis out of the normal and the chosen tangent, in this case tangentV which gives us the same result as using the classic aimConstraint rivet. If we choose to use the tangentU instead, we would get the follicle‘s behaviour. Then, obviously we decompose the matrix and plug it into our riveted transform.

Optionally, similar to the first post in this series, we can use the multMatrix node to inverse the parent’s transform, if we so need to. What I usually do, though, is parent them underneath a transform that has it’s inheritTransform attribute turned off, so we can plug the world transforms directly.

It is important to note that in this case we are absolutely sure that the output matrix is orthogonal, since we know that the normal is perpendicular to both tangents. Thus, crossing it with any of the tangents, will result in a third perpendicular vector.

Skipping the vector product

Initially, when I thought of building rivets like this, I plugged the normal, tangentU and tangentV directly from the pointOnSurfaceInfo to the fourByFourMatrix. What this means, is that we have a matrix that is not necessarily orthogonal, since the tangents might very well not be perpendicular. This results in a shearing matrix. That being said though, it was still giving me proper results.

Matrix rivet - skipping the vectorProduct

Then, I added it to my modular system to test it on a couple of characters and it kept giving me steadily good results – 1 to 1 with the behaviour of a follicle or aimConstraint rivet, depending on the order I plug the tangents in.

What this means, then, is that the decomposeMatrix node separates all the shearing from the matrix and thus returns the proper rotation as if the matrix is actually orthogonal.

If that is the case, then we can safely skip the vectorProduct and still have a working rivet, considering we completely disregard the outputShear attribute of the decomposeMatrix.

Since, I do not understand how that shearing is being extracted, though, I will be keeping an eye on the behaviour of the rivets in my rigs, to see if there is anything dodgy about it. So far, it has proved to be as stable as anything else.

Conclusion

If you are anything like me, you would really like the simplicity of the graph, as we literally are taking care of the full matrix construction ourselves. What is more, there are no constraints, nor follicle shapes in the outliner, which again, I find much nicer to look at.

This matrix series has been loads of fun for me to write, so I will definitely be trying to come up with other interesting functions we could use matrices for.

This post is a part of a three post series, where I implement popular rigging functionalities with just using maya’s native matrix nodes.

Calculating twist is a popular rigging necessity, as often we would rather smoothly interpolate it along a joint chain, instead of just applying it at the end of it. The classical example is limbs, where we need some twist in the forearm/shin area to support the rotation of the wrist or foot. Some popular implementations utilize ik handles or aim constraints, but I find them as a bit of an overkill for the task. Therefore, today we will have a look at creating a matrix twist calculator, that is both clean and quick to evaluate.

Other than matrix nodes I will be using a couple of quaternion ones, but I promise it will be quite simple, as even I myself am not really used to working with them.

tl;dr: We will get the matrix offset between two objects – relative matrix, then extract the quaternion of that matrix and get only the X and W components, which when converted to an euler angle, will result in the twist between the two matrices along the desired axis.

Desired behaviour

Matrix twist calculator - desired behaviour
Please excuse the skinning, I have just done a geodesic voxel bind

As you can see what we are doing is calculating the twist amount (often called roll as well from the yaw, pitch and roll notation) between two objects. That is, the rotation difference on the axis aiming down the joint chain.

Limitations

An undesirable effect you can notice is the flip when the angle reaches 180 degrees. Now, as far as I am aware, there is no reasonable solution to this problem, that does not involve some sort of caching of the previous rotation. I believe, that is what the No flip interpType on constraints does. There was one, using an orient constraint between a no roll joint and the rolling joint and then multiplying the resulting angle by 2, which worked in simple cases, but I found it a bit unintuitive and not always predictable. Additionally, most animators are familiar with the issue, and are reasonable about it. In the rare cases, where this issue will be a pain in your production you can always add control over the twisting matrices, so the animators can tweak them.

Something else to keep in mind is to always use the first axis of the rotate order to calculate the twist in, since the other ones might flip at 90 degrees instead of 180. That is why, I will be looking at calculating the X twist, as the default rotate order is XYZ.

With that out of the way, let us have a look at the setup.

Matrix twist calculator

I will be looking at the simple case of extracting the twist between two cubes oriented in the same way. Now, you might think that is too simple of an example, but in fact this is exactly what I do in my rigs. I create two locators, which are oriented with the X axis being aligned with the axis I am interested in. Then I parent them to the two objects I want to find the twist between, respectively. This, means that finding the twist on that axis of the locators, will give me the twist between the two objects.

Matrix twist calculator

Granted, I do not use actual locators or cubes, but just create matrices to represent them, so I keep my outliner cleaner. But, that is not important at the moment.

The relative matrix

Now, since we are going to be comparing two matrices to get the twist angle between them, we need to start by getting one of them in the relative space of the other one. If you have had a look at my Node based matrix constraint post or you were already familiar with matrices, you would know that we can do that with a simple multiplication of the child matrix by the inverse of the parent matrix. That will give us the matrix of the child object relative to that of the parent one.

The reason, we need that is because that relative matrix is now holding all the differences in the transformations between the two objects, and we are interested in exactly that, the difference on the aim axis.

Here is how that would look in the graph.

Matrix twist calculator - relative matrix

The quaternion

So, if we have the relative matrix, we can proceed to extracting the rotation out of it. The thing with rotations in 3D space is that they seem a bit messy, mainly because we usually think of them in terms of Euler angles, as that is what maya gives us in the .rotation attributes of transforms. There is a thing called a quaternion, though, which also represents a rotation in 3D space, and dare I say it, is much nicer to work with. Nicer, mainly because we do not care about rotate order, when working with quaternions, since they represent just a single rotation. What this gives us is a reliable representation of an angle along just one axis.

In practical terms, this means, that taking the X and W components of the quaternion, and zeroing out the Y and Z ones, will give us the desired rotation only in the X axis.

In maya terms, we will make use of the decomposeMatrix to get the quaternion out of a matrix and then use the quatToEuler node to convert that quaternion to an euler rotation, which will hold the twist between the matrices.

Here is the full graph, where the .outputRotateX of the quatToEuler node is the actual twist value.

Matrix twist calculator - full graph

Conclusion

And that is it! As you can see, it is a stupidly simple procedure, but has proved to be giving stable results, which in fact are 100% the same as using an ik handle or an aim constraint, but with little to no overhead, since matrix and quaternion nodes are very computationally efficient.

Stay tuned for part 3 from this matrix series, where I will look at creating a rivet by using just matrix nodes.