Rigging

This category contains posts about all things rigging, but mainly about the core concepts of it.

I am super excited to finally be writing this!

The platform at talk.bindpose.com is now live and open for everyone! There probably are some bugs as it’s still rough around the edges, but most importantly we can start using it!

So head over there to register and start asking, learning and talking about the cool rigging topics you are interested in!

A screenshot of the first post on talk.bindpose.com
A screenshot of the first post on talk.bindpose.com

Thank you

Firstly, I really want to thank everyone who subscribed and now registered to use the website. If we want to have an online rigging community we all should do our best to make sure it’s alive and kicking. So again, thank you to all who supported this endeavour!

The platform has been running hidden for about a week now with no more than 5 people on it and already I have found out ideas that are beneficial to my rigs! Big thanks to those who weren’t scared of the blank page and came in early on to get some content running!

I have talked about why I wanted to create this place previously – here and here – so I don’t want to repeat myself, but I want to share some ideas of what I want this place to become.

Sharing ideas

Most importantly, I wanted to have an active rigging community, so I can pick the brains of people way smarter than me and learn as much as I can directly from them.

That being said, the idea of sharing my knowledge as well has always been an exciting one for me and that is why I have started the blog as well. The thing with a blog is that it is quite one-sided, so it is nice for showing and sharing ideas, but not great for starting a conversation and hearing different opinions on them.

Getting feedback

Having opinions that are never challenged is dangerous. Going through your rigging career without checking your premises would put you in a disadvantage to people who do. In an industry like ours everyone knows how important feedback is. Therefore, I wanted to have a place where people are welcome to criticize my ideas and more importantly, a place where I can easily see that criticism.

Just chatting and lurking

Additionally, I really like rigging, but it’s a niche topic, so finding people to talk to is tricky. And I do really want to talk to people about it, even outside of my professional interest!

I tend to spend a big portion of my free time reading (lurking) through Hacker News and various subreddits about things that interest me. I’d like to be able to do the same with rigging.

Sharing tools

I don’t know about you, but I always get excited about people sharing their tools. Granted most of the time it’s things that pretty much everyone writes for themselves and they often have horrible interfaces, so I rarely if ever use those tools, but even just seeing them is inspiring. The fact that there are so many people out there working on these things and sharing them is kind of cool.

That being said occasionally there are things that are just insanely cool like the Cosmos launcher or ngSkinTools.

My hopes are that if we have a place where people share their tools, we have a place where we can always look for references when building our own ones and hopefully inspiration. I would really like to see more cool tools and I feel like talk.bindpose.com can help!

Additionally, if you are trying to sell your tools, it would be handy to have a place where you know riggers hang out. And if your tool is any good, people will be happy that you posted it.

Conclusion

All in all, I think if we have all that, it will inevitably lead to us improving as riggers, while having fun hanging out with like-minded people!

So head over to talk.bindpose.com to become a part of that place!

Again, thanks to all who supported this!

Firstly, I want to thank everyone who signed up for talk.bindpose.com. I know in today’s internet everyone seems to be trying to get your email and I myself am always very aware of subscribing to anything, so it is much appreciated!

Since I posted the page the other day, I have had about 30 people sign up, which is not an overwhelming number, but to me it says there will be at least 30 people to chat with and exchange ideas when I am stuck somewhere. Additionally, there will be at least 30 people to share and discuss cool rigging stuff with. When I put it this way, it feels like a lot! So, again, thank you!

That being said, any online community would need a bit more than that in order to be sustainable, as we are all too familiar with places that look dead and how unappealing that is. Unfortunately, that has been the fate of many good discussion boards, not only about rigging and computer graphics, but about anything really. Therefore, once the platform is live, we will need to make it grow a bit more in order for it to keep going.

If you have any tips and/or ideas on how best to maintain an online community for riggers like that and make sure it keeps going strong, please share them as comments here or hit me up on email or Twitter.

Additionally, if you have been a part of such online communities that have for one reason or another died, you might be able to point out some of the mistakes and I would be very interested in hearing those as well!

Roadmap

With the numbers out of the way, I want to share what I have in mind in terms of steps for creating the platform and kicking it off.

The way it is going to work is, as soon as I have a proper working solution (which should not be very far off) I am going to gather a bunch of people, from the ones who have subscribed, to give it a test and see if there is anything terribly broken. If that’s not the case then we are going to seed it with some initial information (questions, answers, sharing interesting resources, etc.) just so nobody other than me is faced with the big empty when they come for the first time.

That’s where I’ll need some help. I have some ideas about things I would like to have posted on the platform, but the point of the community is to have variety. So, I would really appreciate it if you have any ideas for specific rigging tips, questions, shares, etc. you would like to see and share them, so I can crack on and make sure we have a variety of content to start with.

Distant future

On top of sharing cool ideas and asking/answering questions, I have a few other notions for features that a platform like ours should have once it has been established.

Job board and freelance area

To begin with, I think it would be really handy if we have a job board and a freelance area. The reason for that is, again, similar to the whole reasoning about the platform. There are other huge places which try to do this, but I think the more narrowed down it is (rigging only) the better. That way, we can rate the jobs and make sure riggers do not have to settle for neither bad employers nor terrible rates, as of course, that affects all of us. I would imagine it would be really easy for companies to find people this way as well.

Workplace information

While we are on the job topic, it might be cool to share information about people’s workplaces. Since our industry is very fast paced and often people have shorter contracts, it would be amazing to be able to read about the work environment at all those other potential places you could work at through a rigger’s perspective.

Rigging challenges

Additionally, I think it would be so much fun if we do some rigging challenges. One of my teammates for my final university projectZeno Pelgrims – started a really cool online place for lookdev challenges – shaders.xyz and it looks amazing! Wouldn’t it be nice to set up a similar rigging challenge, where we all have to rig the same asset and then we all share our processes? It seems to me, this would be the ultimate way for learning from each other.

I am sure that for every one of these ideas, you guys probably have 10 more and I am looking forward to talking with you about them once the platform is live!

Conclusion

For the time being, while I am working on the website, I will be taking time off writing here, as unfortunately, there is only so much spare time. I think it will be well worth it, though!

Once again, I’d like to thank everyone who signed up! If you haven’t done it already, please reconsider it – talk.bindpose.com.

tl;dr: After chatting with a few people about it, I have decided to start an online place just for riggers to communicate with each other easily. Head over to talk.bindpose.com to show your support for the idea by subscribing.

The why

A couple of weeks ago I asked riggers on Twitter where do they go when they have rigging questions, as I was struggling with something that I could not find information about and was wondering how do other people tackle that. I have to say I wasn’t very satisfied by the replies as I hoped there is a place online where riggers hang out a lot and you can easily ask and pick their brain (think StackOverflow for rigging).

People there suggested Twitter, Google and some forums, which are all great, but the main issue I have with these is that that they are obviously not rigging specific, so it is very easy for good and useful information to get lost among all the noise. Another big issue is that some of them are so distracting that it would be a shame to have to open them up when you are actually focused on working.

As a guy who grew up in the times where there was an active discussion board or forum for everything, I find the lack of good and consistent source of information and communication about rigging disappointing.

That same week, in my newsletter I asked whether people would be interested in an online place, dedicated to rigging, where they can ask, learn and share stuff. I had quite a few riggers positively respond, so I decided I will crack on with it and create that place.

The how

As I mentioned above I was hoping there was a StackOverflow-esque place with elements of Reddit and Hacker News in there, but obviously, all about rigging. Now since, all of these are immense platforms, when I say similar to them, I mean similar in the effect of making it easy for people to communicate about a topic they are passionate about. That is what I am aiming for. Additionally, you will find that the design I have in mind is almost 100% based on these three websites, just because I find them incredibly easy and straightforward to use, which I do every day.

I have been working on the platform since then and I am feeling very positive about it, as just looking at it, I can imagine how helpful it will be to me and hopefully to other people interested in rigging.

The when

Even though I have some minor web development experience, and I have dabbled with it through the years, I am by no means an expert, so everything I do I double and triple check to make sure I do it right. On the other hand, I do not want to spend too much time on building this initial version as I have no idea if people would even find it useful. The fact that I am so eager to see it live, also makes me speed up the process a bit more, so I have already made a fair amount of progress.

With all that in mind, I decided I will roll out a landing page where people can actually subscribe, so I can see if there is as much value in something like this as I had thought and make sure that what I am building is going to be useful.

The where

For now I have decided I will host the website here on bindpose, until it grows a bit, so I can use the great rigging minds on the internet to actually come up with a proper good name for it, as I am sure you all know, that is the hardest bit of creating anything.

So, head over to talk.bindpose.com to subscribe to the list if you would like to see an online place for riggers come to life.

Today, I am going to share a really quick tip of achieving an uniform spacing along a curve.

Disclaimer: If you are not familiar with using the API, worry not, we are looking at a very simple example and I will try to explain everything, but it also might be a good idea to get some understanding of how it all functions. A good place to start is Chad Vernon’s Introduction to the API.

Very often in rigging we need to use curves. In quite a lot of these cases we need to get uniformly distributed positions along that curve. A simple example is creating controls along a curve. Chances are you would want them to be as uniformly distributed as possible, but in order to get that only using the parameter along the curve, you would need a perfectly uniform one that also matches the actual curvature. To get that you would need to do a lot of rebuilding, inserting knots and tweaking.

For another tip on rigging with curves have a look at my post about getting a stable end joint when working with IK splines.

I suppose that if you are doing it by hand then you can easily tweak the position along the curve and eyeball the distances between them to be roughly equal, but it sounds like too much hassle to me and also, more often than not, you would want to have that automated as I could imagine it being integral to a lot of rig components.

Let us have a look then!

The issue

So, I am sure everyone has run into the situation where they’ve wanted to create a few objects positioned uniformly along a nurbsCurve or a nurbsSurface, but they get this.

Getting an uniform space along a curve - example of non-uniform spacing on a nurbsSurface

Notice how larger the gap is between the joints on the left-hand side than on the right. The reason for that is that the distance between the isoparms is not equal throughout the surface, but the parameter difference is. What that means is, no matter how much we stretch and deform the surface, the parameter difference between the spans is always going to be the same – .25 in our example (1.0 / spansU).

Getting an uniform space along a curve - example of non-uniform spacing on a nurbsSurface with drawover

That discrepancy between the parameter space and the 3D space is what causes these non-uniform positions.

Getting uniform positions along a curve

So now that we know that, we can figure out that the way to get a reliable position is to find a relationship between the 3D space and the parameter space. That is where the API’s MFnNurbsCurve comes handy.

The 3D space information that we are going to be using is the length of the curve, as we know that is an accurate representation of distance along the curve. If you have a look at the available methods in the MFnNurbsCurve class, you will find the following one findParamFromLength. Given a distance along the curve this function will give us a parameter.

Example

Let us consider the following curve.

Getting an uniform spacing along a curve - example curve with non-uniform CVs

Let us position some joints along the curve using distances only based on the parameter.

for i in range(11):
    pci = mc.createNode("pointOnCurveInfo")
    mc.connectAttr("curve1.worldSpace", pci + ".inputCurve")
    mc.setAttr(pci+".parameter", i * .1)
    jnt = mc.createNode("joint")
    mc.connectAttr(pci+".position",jnt+".t")

All we do here is iterate 11 times and create a joint on the curve at the position of parameter equal to iterator * step where the step is 1.0 / (numberOfJoints - 1), which is .1 in our example.

Getting an uniform spacing along a curve - Example of non-uniform spacing on a curve using just the parameter

As expected, the non-uniform distance between the CVs results in an also non-uniform spacing of the joints.

Let us try a different approach then. We will get a reference to an API instance of our curve, and using the above mentioned function we will get parameters based on actual distance along the curve, hence getting an uniform distribution.

from maya import OpenMaya as om

def getDagPath(node=None):
    sel = om.MSelectionList()
    sel.add(node)
    d = om.MDagPath()
    sel.getDagPath(0, d)
    return d

crvFn = om.MFnNurbsCurve(getDagPath("curveShape4"))

for i in range(11):
    parameter = crvFn.findParamFromLength(crvFn.length() * .1 * i)
    point = om.MPoint()
    crvFn.getPointAtParam(parameter, point)
    jnt = mc.createNode("joint")
    mc.xform(jnt,t=[point.x,point.y,point.z])

So, the getDagPath function takes a name of a node and returns an MDagPath instance of that node, which we need in order to create the MFnNurbsCurve instance. The MDagPath is used for many other things in the API, so it is always a good idea to have that getDagPath function somewhere where you can easily access it.

Notice we are passing the curve shape node, as if we are to use the curve4 transform we will not be able to create the MFnNurbsCurve instance.

Having that MFnNurbsCurve, we iterate 11 times and following the same logic for getting a position along the curve as before – iterator * step – we get the parameter at that position, using the findParamFromLength method.

Now that we know the parameter we could still use the pointOnCurveInfo as we did before, but considering we are already working in the API we might as well get all the data from there. So, using the getPointAtParam method we can get a world space position of the point on the curve at that parameter.

Notice however that we are first creating an MPoint and we are then passing it to the getPointAtParam function to populate it.

And here is the result.

Getting an uniform spacing along a curve - example of uniform spaced joints along a curve using the mfnNurbsCurve from the Maya API

Using the same approach to get uniform positions on a surface

So, all that nurbsCurve business is great, but how can we apply the same logic to a nurbsSurface. Unfortunately, the MFnNurbsSurface does not have any method resembling the findParamFromLength one, but luckily we can always create a curve from a surface.

So in order to get uniform spacing along a nurbsSurface what I usually would do is create a nurbsCurve from that surface using the curveFromSurfaceIso node and using the described method find the accurate parameters and use those on the surface itself.

While writing this I realized that maybe the same approach can be used to actually get an uniform representation of the surface by getting curves from the surface and using them calculating the new, uniformly spaced CVs of the surface. Seems like we might loose a lot of the curvature of the surface, but it also seems promising, so I will definitely look into it.

Conclusion

Using curves and surfaces is something that I did not do a lot of in the beginning of my rigging path, but obviously they are such an integral part of rigging, that it is very important to be able to work with them in a reliable and predictable fashion. Thus, this tip has helped me a lot when building bits of my rigging system and I really hope you find it valuable in your work as well.

Additionally, I would like to reiterate who powerful of a tool the API is and I would definitely suggest anyone who is not really familiar with it to take the plunge and start learning it by using it. The major benefits are not only functional ones (like the one described in this post), but also performance ones, as the API is incredibly faster that anything to do with maya.cmds.

So, painting skin weights. It is a major part of our rigging lives and sadly one of the few bits, together with joint positioning, that we cannot yet automate, though in the long run machine learning will probably get us 99% there. Untill then though, I thought I would share some of my tips for painting skin weights with maya’s native tools, since whenever I would learn one of these I felt stupid for not finding it out earlier as, more often than not, it was just so simple.

I am sure a lot of you are familiar with these, but even if you learn just a single new idea about them today, it might boost your workflow quite a bit. Additionally, I know that a lot of you are probably using ngSkinTools and literally everyone I know who works with it says they cannot imagine going back. So I am sure that some of the things I am going to mention are probably already taken care of ngSkinTools, but if you, like me, have not had the chance to adopt it yet, you might find these helpful.

I am going to list these in no particular order, but here is a table of contents.

Contents

  1. Simplifying geometries with thickness and copying the weights
  2. Using simple proxy geometry to achieve very smooth weights interpolation quickly
  3. Duplicate the geometry to get maya default bind on different parts
  4. Copy and paste vertex weights
  5. Use Post as normalization method when smoothing
  6. Move skinned joints tool
  7. Reveal selected joint in the influence list
  8. Some handy hotkeys
  9. Average weights
  10. Copy and paste multiple vertex weights with search and replace
  11. Print weights

So with that out of the way, let us get on with it.

Simplifying geometries with thickness and copying the weights

This one comes in very handy when we are dealing with complex double-sided geometries (ones that have thickness). The issue with them is that when you are painting one side, the other one is left unaffected, so as soon as an influence object transforms the two sides intersect like crazy. That is often the case with clothes and wearables in general.

The really easy way to get around this is to
1. Make a copy of the geometry
2. Remove the thickness from it (when having a good topology it is as simple as selecting the row of faces which creates the thickness and deleting it together with one side of the geo)
3. Paint the weights on that one
4. Copy the weights back to the original geometry

Painting skin weights tips - Using a one sided proxy geometry when working with thickness

Now, a really cool thing that I had not thought of untill recently is that even if I have started painting some weights on the double sided geometry to begin with I can also maintain them, by copying the weights from the original one to the simplified one before painting it, so I have a working base.

That means, that if I have managed to paint some weights on a double sided geometry that kind of work, but the two sides are not behaving 1 to 1, I can create a simplified geo, copy the weights from the original one to the simplified and then copy them back to get the 1 to 1 behaviour I am looking for.

Using simple proxy geometry to achieve very smooth weights interpolation quickly

This one is very similar to the first one, but I use it all the time and not only on double-sided geometries.

Very often there are geometries that have some sort of a detail modeled in them that make it hard for weight painting smooth weights around it.

Consider the following example. Let us suppose that we need this geometry to be able to stretch smoothly when using the .translateX of the end joint.

Tips for painting skin weights in maya - Using a simple geometry to copy weights to models which are hard to smooth weights for.

Doesn’t look great with default skinning, but also if I try to block in some weights and smooth them, it is likely that maya won’t be able to interpolate them nicely. To go around it, I’d create a simple plane with no subdivisions so I can have a very nice smooth interpolation from one edge to the other.

Tips for painting skin weights - Using a simple plane without subdivisions to achieve a smooth weights interpolation for copying to complex geometries.

Copying this back to the initial geometry gives us this.

Tips for painting skin weights - Smooth skinned complex geometry using weights from a simple plane.

Very handy for mechanical bits that have some detail in them and also need to be stretched (happens very often in cartoon animation).

Duplicate the geometry to get maya default bind on different parts

So, very often I have to paint the weights on a part of a geometry to a bunch of new joints while I still need to maintain the existing weights on the rest of it. More often than not, I would be satisfied with maya’s default weights after a bind, but obviously if I do that it will obliterate my existing weights.

What I do in such cases is make a copy of the geometry and smooth bind it to only the new joints. Then I select the vertices on the original geometry that comprise the part I want the new influences in and I use the Copy skin weights from the duplicated one to the selected vertices. If the part is actually separated from the rest of the geometry that should do it, but if it s a more of an organic shape, there is going to be some blending of the new weights with the ones surrounding them.

I could imagine, though, that having the ability to have layers and masks on your skin weights would make this one trivial.

Copy and paste vertex weights

I am guilty of writing my own version of this tool just out of the ignorance of not knowing that this exists. Basically what you can do is select a vertex, use the Copy vertex weights then select another one (or more than one) and use the Paste vertex weights command to paste them. Works cross-geometries as well.

A cool thing about the tool that I wrote to do this is I added a search and replace feature that would apply the weights to the renamed joints. For example if I am copying a vert from the left arm and I want to paste it on the right I would add “L_” to “R_” to my replacement flags.

Use Post as normalization method when smoothing

So, I have met both people who love and who hate post. I think the main reason people dislike it is because they don’t feel comfortable with their weights being able to go above 1.0, but I have to say that sometimes it is very handy. Especially for smoothing. Everyone knows how unpredictable maya’s interactive smoothing is, and that’s understandable since in a lot of cases it is not immediately obvious where should the remaining weights go to.

Smoothing on post is 100% predictable which I think is the big benefit. The way it works is that it smooths out a joint’s influence by itself, without touching any of the other weights. That means that the weights are not normalized to 1.0, but instead of verts shooting off in oblivion post normalizes them for our preview. That is also why it is not recommended to leave skinClusters on Post as the weights are going to be normalized on deformation time which would be slower.

So more often than not my workflow for painting weights would be to block in some harsh rigid weights, then switch to Post and go through the influences one by one flooding them with the Smooth paint operation once or twice.

Move skinned joints tool

I am not sure which version of maya did this tool come in, but I learned of it very recently. Essentially you can select a piece of geo (or a joint) and run the Move skinned joints tool, then you can transform the joint however you like or you can also change the inputs going into it without affecting the geometry, though, you’d have to be careful to not change the tool or the selection as that would go out of the Move skinned joints tool. Ideally any other changes than just moving/rotating them about should be ready to be ran in the script editor.

I would not recommend using this for anything else than just testing out different pivot points. Doing it for actual positioning in the final skinCluster feels dirty to me.

Reveal selected joint in the Paint skin weights tool influence list

Only recently I found out what this button does.

Paint skin weights tool - reveal selected joint in influence list

It scrolls the list of influences to reveal the joint that we have selected, which is absolutely brilliant! Previously, I hated how when I need to get out of the Paint skin weights tool and then get back inside of it, the treeView is always scrolled to the top of the list. Considering that the last selection is maintained, pressing that button will always get you back to where you left off. Even better, echoing all commands gives us the following line of MEL that we can bind to a hotkey.

artSkinRevealSelected artAttrSkinPaintCtx;

Some handy hotkeys

I have learned about some of these way too late, which is a shame, but since then I’ve been using them constantly and the speed increase is immense. I hate navigating my mouse to the tool options just to change a setting or value.

  • CTRL + ALT + C – Copy vertex weights
  • CTRL + ALT + V – Paste vertex weights
  • N + LMB (drag) – Adjust the value you are painting with
  • U + LMB – Marking menu to change the current paint operation (Replace, Add, etc.)
  • ALT + F – Flood surfaces with current values

For more of these head on to the Hotkey editor, then in the Edit hotkeys for combobox go for Other items and open up the Artisan dropdown.

From here on I have added some of the functionalities that I have written for myself, but sadly the code is very messy to be shared. Luckily, it is not hard at all to write your own (and it will probably be much better than mine), but if you are interested, do let me know and I can clean it up and share it at some point.

Average weights

This one I use a lot. What it does is, it goes through a selection of verts and calculates the average weights for all influences and then goes through the selection once more and applies that average calculated weight. Essentially, what this results in is a rigidly transforming collection of verts. Stupidly simple, but very useful when rigging mechanical bits, which should not deform. Also I have used it in the past on different types of tubings and ropes where there are bits (rings, leafs, etc.) that need to follow the main deformation but not deform themselves.

Copy and paste multiple vertex weights with search and replace

In addition to the above mentioned copy and paste vertex weights, I have written a simple function that copies a bunch of vertex weights and then pastes them to the same vertex IDs on a new mesh. It is not very often that we have geometries that are copies of each other, but if we do this tool saves me a lot of time, because I can then just skin one of them, copy the weights for all verts and then paste them to the other geometry using the Search and Replace to adjust for the new influences.

Comes in particularly handy for radially positioned geometries where mirroring will not help us a lot.

Print weights

Quite often I’d like to debug why something is deforming incorrectly, but scrolling through the different influences can get tedious especially if you have a lot of them. So I wrote a small function that finds the weights on the selected vertex and prints them to me.

This is the kind of output I get from it.

#####################################
joint2 : 0.635011218122
joint1 : 0.364988781878
#####################################

As I said, there is a lot of room for improvement. It works only on a single vert at the moment, but I could imagine it being really cool to see multiple ones in a printed table similar to what you would get in the component editor.

What would be even cooler would to use PySide to print them next to your mouse pointer.

Conclusion

Considering that we spend such a big chunk of our time on painting weights we should do our best to be as efficient and effective as possible. That is the reason I wanted to share these, as they have helped me improve my workflow immensely and I hope you would find some value in them as well.

IK splines are a big part of a rigger’s toolset. They come in super handy for anything that needs to behave similarly to a rope. Funnily enough, that behaviour is often desired in many parts of the body and is also often preferable to a ribbon, mainly because ribbon’s stretch is not always desirable. Examples include spines, soft limbs, tentacles, some cases with lips and eyebrows, etc. Additionally, IK splines are a necessity in prop rigging, so we definitely need to have a stable way of setting them up. That is why today I am looking at a quick tip on going around the issue where the end joint does not sit at the end of the spline when stretched or deformed a bit more extremely.

The issue

If you have ever used a spline IK you have probably noticed an annoying stability issue at the end of the chain. Basically, when the chain is stretched or deformed a lot, our joints become longer and it is harder for them to assume the proper positions and rotations along the spline in order to follow it correctly. Effectively, as we stretch the spline it is almost as if the joint chain becomes with lower resolution than needed.

Here’s an example of the issue. Notice how the end joint has trouble sitting at the end of the chain.

IK splines - end joint issue

Depending on the amount of joints in the chain this issue will be less or more pronounced. Since I very often have two layers of control on spline setups where the lower resolution one drives the higher one so the animators have a lot more control than a single one, I also need to provide the fix for both layers. So, let us have a look at it.

The setup

Depending on the way the spline is driven you will have to adapt the setup, but I think it will be fairly straight-forward how to do that.

Essentially, all we do is we create another joint chain with just 2 joints, where the base is rooted at the end of the spline (essentially driven by whatever drives the end of the spline) and it aims at the second to last joint of the chain. Effectively, giving us this.

IK splines - end joint issue fix

Stretching

You’ll notice that I haven’t added any stretch to that aimed joint. I have found that most of the time I really do not need it. It seems to me that in order for that to become an issue, the chain needs to be stretched quite a bit, which is not very often the case. If you know, though, that your spline IK setup would be stretched a lot, it might be a good idea to plug the distance between the end point of the spline and the second to last joint of the chain into the translateX of the tip of the aimed joint chain.

Up vector

Depending on the result you would like to see from the setup you have a few different choices for the up vector of the aimConstraint. If you want it to behave exactly like the rest of the chain behaves, you can use the up axis of the last joint in the chain to be the up vector. I would usually suggest going that way, as then however you decide to twist the chain the additional joint will always be following that. Other options may include, the joint we are aiming at, the base of the chain (if we do not want any twist) or whatever drives the end of the chain, so we get the full twist out of it.

Additional potential issue

If you have another look at any of the GIFs above you’ll notice that at a certain pose of the CV, not only the last joint is flying off, but also the second to last one goes past the end of the spline. That is caused by the exact same issue I mentioned above. Our fix will not behave amazingly when this happens as the aimed joint will have to pop in order to aim at the opposite direction.

To be honest, similarly to the stretching bit I mentioned above, I haven’t had issues with this mainly because the chains are rarely stretched or deformed that much. That being said, there is a potential solution, which seems quite heavy, but I suppose if the functionality is needed the cost is irrelevant.

What you would do to completely go around this issue is having a second spline IK chain with the exact same joint chain but in reverse. You would also need to use a reverseCurve before the ikHandle, as well. Essentially, we are duplicating the setup but in reverse, so the problematic area is not only the end of the initial chain but it is also covered by the base of the new one and we know that the base of the IK spline behaves correctly. Therefore, all we need to do after that is paint the weights using both joint chains and smoothly blend them somewhere in the middle.

I have to say that I have never actually used this setup, but I have only tested it out, so if you manage to get it to work or not I would be happy to hear about it.

Conclusion

I really like how in rigging there is almost always a solution and coming up with these solutions is always so much fun. By no means is this fix bulletproof, but most of the time it would do the job. I hope it helps you with building your own spline IK setups, since they are just so useful.

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.