Modular Rigging

List of Terms

DAG (Directed Acyclic Graph)

The central data structure in Maya is the DAG, or Directed Acyclic Graph. It is what is known to almost all programmers as a "tree". Much of the data you are interested in is expressed as nodes of data on this tree. Each node has a type. Each one has a parent node ( except for the root node ), and each node may have an arbitrary number of children. There are hundreds of types of nodes, and at least in theory, any node can be the parent or the child of a node of any type. The DAG is guaranteed to be a tree. So there are no cycles in it. If you visit the nodes using an orderly tree walking algorithm you can visit every node, and you won't have to worry about infinite loops. Not all of the data is stored in the DAG, but vertices, meshes, transforms, and a model's skeletal system are stored in the DAG. (from gamedev.net)

Dependency Graph:

The other data structure, far scarier, is the DG or Dependency Graph. Like the DAG, this is a set of nodes that refer to each other, but here there are no restrictions. DG nodes can refer to any other node, and cycles are possible. This is where the textures, materials, and animation information is stored. Technically the DAG is a subset of the DG, but getting data out of the DG is somewhat more complicated than getting stuff out of the DAG, so it's convenient to think about nodes that are in the DAG, and then all the other nodes. (from gamedev.net)

Message Attribute

A message attribute is a dependency node attribute that does not transmit data. Message attributes only exist to formally declare relationships between nodes. By connecting two nodes via message attributes, a relationship between those nodes is expressed. Message attribute connections can be traversed in the same manner as any other connection in the dependency graph.(from Maya help)

Metadata

"information about information"

Parametric Animation

Parametric animation is an animation technique used in computer software, such as in computer games, that blends two or more separate animations together to form a new animation. This new animation is constructed in real-time by the game engine, and is not stored in a separate file like a regular animation. The technique was first used in an early build of theHalf-Life mod, Team Fortress 2, and it not only heavily reduces artist workload during game development, it provides for much smoother animation as well. (Wikipedia)

Traversal (Explicit)

Ex. 'PV constraint connected to Ik handle'

'Elbow joint located at (x,y,z)

Traversal (Semantic)

Analogous to MEL/Python 'listRelatives'

Ex. "I am a character" (attribution)

"Here are my arms" (node connection)

(wywait) I've realised I will reach the point soon where I will need to start creating the scripts for dealing with the manipulation and management of the rigs. I think this is what you call the semantic traversal of the rigs through the metanodes. My idea is to create classes for each metanode type, creating methods specific to that metatype. Then, through inheritance an object can access methods from its parent class. So for instance, if I select a hand controller and assign it to the variable hand_ctrl using something like "hand_ctrl = getMetaType()", I could then run hand_ctrl.fkIkSwitch() which is specific to this class or I could run hand_ctrl.getMetaParent() which it inherits from its parent class. Am I approaching this correctly?

(wywait)

Could someone explain semantic traversal please?

(davidHunt)

This is the most important thing to clarify right away. Because it's much more important to understand why it's worthwhile to use this technique than it is to build the mechanics with network nodes and string>message attribute connections.

Semantic Traversal is the notion of searching the animation scene for particular objects using terminology that is meaningful to humans. This is opposed to Explicit Traversal which is to search the scene using technical language and terminology native to the animation scene. Your example: "hand_ctrl = getMetaType()" is very good one and I can tell you understand the technique already. I'll explain anyway just in case anyone finds it useful.

A pseudo code example of Semantic Traversal might look like this:

Code:

leftElbowControl = getRigControl(metaParent, "left", "elbow")

Inside the function getRigControl it does all the Explicit Traversal necessary to find the object of that side and type in the rig that is tracked by the input metaRoot. The advantage of working this way are many:

Less duplicate code.

Code can be reused more easily.

Easier to change the underlying rig structure later.

Bug fixing is easier because the Explicit Traversal lives in only one place.

Tools that operate on the rig don't break as often.

You can use whatever mechanics you want to for tracking nodes on your rigs which can be used by your Semantic Traversal functions. In the metaRigging example we have built a standardized metadata node network out of metaNodes which are simply network nodes with a standard set of custom attribtes added. We constructed our own DAG hierarchy in the DG and make custom connections to objects in the scene that we want to expose to our code. There are different metaNode types created for each rig component, each with their own additional standard attributes that the code can expect to find when it interacts with the scene.

Next question:

Quote:

I understand, or at least I think, that your game characters have different joints for the root joint and the base of the spine but I'm sure this isn't the only situation that may arise where one object could be the potential metaChild of multiple metaParents. I guess what I'm trying to get my head around is how to structure this flow of information through the metaParent/metaChild relationship.

Very good question, I can tell you understand the technique in great detail. They asked this question in Tokyo when I taught the Masterclass there last November.

Yes, you are correct in your assumption that we have a top root joint in our game skeletons above the pelvis. You can still use the same techniques without this extra joint, it just takes a bit of bending the rules to your will. Just be sure that the core Semantic Traversal function "getMetaRoot()" still works. The way it works now is to check for a connection to .metaParent and recursively crawl up the DAG until it is found, or else return a blank string which you can check for on the other end.

If you need to override the .metaParent connection on the root joint then you might go ahead and do something like this: add another message attribute to the root joint (maybe .metaRootJoint) for connection to metaRoot. Then be sure to modify your getMetaRoot() function accordingly (check for both attributes). In fact, I had started to implement something like that in the Masterclass example material...

Next question:

Quote:

My second question relates to MPR, python and pymel. [...] My idea is to create classes for each metanode type, creating methods specific to that metatype. Then, through inheritance an object can access methods from its parent class. So for instance, if I select a hand controller and assign it to the variable hand_ctrl using something like "hand_ctrl = getMetaType()", I could then run hand_ctrl.fkIkSwitch() which is specific to this class or I could run hand_ctrl.getMetaParent() which it inherits from its parent class. Am I approaching this correctly?

YES! This is the next logical extension of what we have done in metaRigging. As Seth mentioned, we are already doing R&D along those lines. Seth has some amazing ideas along those lines which I'll let him elaborate on if he has time.

My main recommendation here would be to play around with different configurations of metaNodes, connections and Semantic Traversal functions. Remember that there is no right way to do it. It can be done in many different ways and each way has its own advantages and disadvantages. If you figure out something cool let us know and we may end up using it too.

Resources

Maya API White Paper