Template Based Rigging

June 22nd, 2006 by Helge Mathee - Viewed 23479 times -




When creating rather complex hierarchies, there are some things you wouldn’t essentially want to deal with. Those tasks include:

  • Making sure all objects follow a valid naming scheme
  • Giving objects the correct icons / wirecolors / looks
  • Setup position- / rotationlimits based on the objects’ types
  • Putting objects into groups based on their types
  • Changing names of sides when duplicating in symmetry
  • … and so many more

To deal with these things one of my favourite ideas comes into play: Automation.

To explain a little bit what complexity we are dealing with, here’s a screenshot of some rig in the schematic view in different zooms:

A. Object templates

As you can see in the lower part of the image, there is naming convention applied to all objects in the hierarchy. The naming convention looks like this:

prefix_name_suffix

In this example the prefix can only be “m”, “l” or “r”, but it could be anything depending on your implementation. The suffix is used to determine the type of object we are dealing with, in the example the greenish objects have the “JNT” suffix, which stands for joint, a bone in a chain. Note that all objects have correct naming and the reason is that they have been created using templates. Here”s the idea:

Use one scripted command to create every object in a rig, using a template to define its attributes. This function would look like something similar to this (pseudo-code):

function makeElement(prefix,name,suffix,parent)
{
    1. check if the object already exists
    2. check if the prefix is valid
    3. check if the suffix is valid
    4. create the element as a child of the given parent
    5. apply all attributes based on the suffix
    6. return the created element
}

Not only will all objects obey the template rules, there are also some additional advantages to this method. Turning the workflow around, by having to know the name for an object before you create it, rather than naming it after it has been created already (we are all lazy, aren’t we) makes sure that rig-elements get the correct names, as you will not be able to create an object which already exists. Furthermore every object created by such a function can be re-created, as all of the information how to create the object is inside of its name. When you find an object called m_global_SRT which is a child of the object m_global_BUF you know how you can re-create it: You just call the function like this: makeElement("m","global","SRT","m_global_BUF");

This means you can analyze the hierarchy quite easily and regenerate parts of a rig in a simple manner. Which brings us to the next type of templates.

B. Hierarchy templates

Templates for a full hierarchy are something like a script which describes how to generate the hierarchy, relying on object templates for each of the objects. There are some additional steps to do here though, as the objects might contain additional modifications. I am assuming that the helper functions to apply those modifications already exist in our rigging-toolset ;-) so I am not implementing anything here.

So a template for a simple hierarchy containing a hip and and a chest srt controller could look like this:

1
2
3
4
5
function makeHipAndChest(parent)
{
    hip = makeElement("m","hip","SRT",parent);
    chest = makeElement("m","chest","SRT",hip);
}

Tweaking the functions a little bit, we can end up with something similar the code below:

function makeElement(prefix,name,suffix,parent)
{
    1. check if the object already exists
    2. check if the prefix is valid
    3. check if the suffix is valid
    4. check if the suffix is SRT and if so, create a buffer object for it, using the same prefix and name but a "BUF" suffix
    5. create the element as a child of the given parent or of the buffer
    6. apply all attributes based on the suffix
    7. return the created element
}
1
2
3
4
5
6
7
function makeHipAndChest(parent)
{
    hip = makeElement("m","hip","SRT",parent);
    transform(hip,[0,0,0,0,90,0,1,1,1]);
    chest = makeElement("m","chest","SRT",hip);
    transform(hip,[0,5,0,0,0,0,1,1,1]);
}

Simple enough, the example hierarchy looks like this:

The transform method is representing one essential modification done to the object in the hierarchy, well, its transform. But there are some more things to look at. Stuff like expressions, constraints, added custom property sets etc… should be persisted, as they are essential to a rig. What is important for the functionality as well is to be able to recreate a hierarchy changing parts of the naming scheme, for example make a left arm and then a right one, or prefix the name of each object created with “upper” or “lower” to specialize the naming of those objects. Using a function such as “makeElement” which is based on names will make this quite difficult though. To explain this in more detail, imagine the following scenario:

We created a simple hierachy of a camera and an interest, where the camera has a direction constraint to the interest. The camera is called “m_Camera_CAM” and the interest is called “m_CameraInterest_POS”. Now, if we call our function to create the camera, which could look like this:

1
2
3
4
5
6
7
function makeCamera(parent,newPrefix,newName)
{
    prefix = newPrefix ? newPrefix : "m" // if there is a newPrefix, use that, otherwise use "m"
    makeElement(prefix,newName + "camera","CAM",parent);
    makeElement(prefix,newName + "CameraInterest", "POS",parent);
    makeConstraint("DIR","m_Camera_CAM","m_CameraInterest_CAM");
}

If we would call the function with the following parameters makeCamera(parent,"l","hero") we would end up with two objects called m_heroCamera_CAM and m_heroCameraInterest_POS with no constraint, because the makeConstraint function is based on the old objects’ names. To deal with those things we have to introduce a remapping scheme. It could look like this:

1
2
3
4
5
6
7
8
9
function makeCamera(parent,newPrefix,newName)
{
    prefix = newPrefix ? newPrefix : "m" // if there is a newPrefix, use that, otherwise use "m"
    element = makeElement(prefix,newName + "Camera","CAM",parent);
    remappingTable [ "m_Camera_CAM" ] = element.name; // store the current name of the element to be able to remap
    element = makeElement(prefix,newName + "CameraInterest", "POS",parent);
    remappingTable [ "m_CameraInterest_POS" ] = element.name;
    makeConstraint("DIR",remappingTable["m_Camera_CAM"],remappingTable["m_CameraInterest_CAM"]);
}

Alright – now we can rebuild hierarchies persisting their attributes by using object templates, adding local modifications such as transforms etc, constraints and expressions can be stored by remapping their inputs using the remappingTable etc…

With this we can now build a library of rig elements and recreate them easily, while still being able to change prefix and specialize the name. Moreover the rig parts can be recreated anywhere in the existing hierarchy, as the function takes the base parent as an input argument. What is really interesting about this approach though, is that you can write a function to auto generate rigging-part-functions by just analyzing what somebody rigged manually. Put simple: Rig manually -> Create a rigging function out of it -> Re-use the function to create the rig part multiple times !

To finish up the theory and the talk about “how nice it would be”, here’s an implementation of my own which I put together while rigging a couple of characters…

Documentation
Addon (This is often saved as XML, just rename the file to “mt_rigz.xsiaddon”.)
Movie (Camtasia Capture 56 MB Techsmith Codec)

If anybody pushes this a lot further, and is allowed to share any of it, I’d love to get some feedback in this blog!

Enjoy!

6 Responses to “Template Based Rigging”

  1. Robert Moodie says:

    Great stuff, Helge

    Let me have a look and get back to you…

  2. Michal Doniec says:

    Thank you very much for this Helge. It”s great concept (tools making tools) and your implementation is very good starting point especially for people like me, who aren”t that skilled at scripting. I have very little problems expanding the library of functions using framework you provided and learning a lot while playing with it.

  3. Andy Moorer says:

    Helge”s work creating toolsets and automation for riggers on a recent film was incredibly valuable, at times the process of rigging felt like I was always moving from one tool Helge wrote to another. His work with others there helped a small team of generalists rig hundereds of characters in a very short time. I”m particularly excited to see the idea of analyzing and recreating rigs built manually, that”s huge. Helge doesn”t your head ever ache? And when do you manage to find time to sleep?

  4. Helge Mathee says:

    thanks to all of you. I am glad you enjoyed the article. Lately I am always trying to put out examples and well commented code so people can experiment on their own. And Andy, Life is something that happens when you can”t get to sleep.

  5. Carlos Valcarcel says:

    Wow, very interesting and usefull post. Thanks for sharing!

    Object templates based on naming convention is a wonderfull idea. And the ability to analyse, modify and/or recreate rigs is very nice to keep the conventions (naming, iconography, grouping, keyable params, etc) consistent as they are beeing updated.

    I will surely study it more in depth and integrate it in my rigging toolset.

    Thanks again!

  6. Serguei K. says:

    Very interesting stuff, I”m looking forward to exploting this as soon as I get a moment of free time.
    Thanks!