this is your rig on sugarcubes

Posts Tagged scripting

The second half of the work I did was to automate the process of moving data around between Motion Builder and Maya, and to make tools for the animators that lightened their loads when it came to exporting and retargeting animations. I was also responsible for a batch conversion pipeline.

On the project there were animations in Motion Builder FBX files that were intended for reuse, which meant loading and retargeting multiple animations across multiple characters. This is a case (if only minimal edits are required) where the HIK system in Maya can be used to blast through conversions and free up animators for other work. Also, as many of the original animations were in single FBX files as Takes and the new decision was to have one file per animation (allowing multiple animators to work on the same character without file collisions in the version repository), the multi-take Motion Builder FBX files would need to be split in batch.

The Maya Human IK system as of Maya 2012 is usable and has a lot of good benefits. Much of what they say works out of the box really does, provided you stick within the system: the ability to retarget animations between characters of differing sizes and joint placements works very well, and the fidelity of those animations stays high. If you rename or reorient bones but still have a Characterization in place for both characters, the transfer will still work out. However, there were also significant downsides:

The Motion Builder to Maya one-click scene send did not work as expected 100% of the time. When transferring from Motion Builder to Maya, I often found that while the Characterization would transfer over the rig itself would not be properly connected, and many times did not even come in at the right position in the Maya scene. Baking the keys down to the skeleton, transferring, and regenerating the rig on the Maya side does work. You lose the editability of having less keys, but you get a one-to-one transfer between the two programs this way and the Characterization makes rebuilding and rebaking the keys to the rig a one-click process.

On the Maya side you lose a lot of the features you’d expect. For example, the animators complained about not having foot roll controls. Regular Maya constraints don’t behave the same way you’d expect, and adding onto an HIK rig can be trickier than building on top of a regular Maya rig. The strangest thing was that you can’t zero controls. If you want to return to the “stance” pose, you have to change the input to the skeleton, then key the rig at the frame you want to have zero’d, and finally go back to having the rig control the skeleton. Editing curves on the HIK rig can be frustrating, as both the FK and IK objects are used to control the final position of joints and the different Human IK modes for posing and interaction pull at the body parts in different ways; often animators were baffled about which controls were causing jitters or other issues, and it was usually a control for a body part much higher up the hierarchy. Lastly, the HIK controls and skeleton don’t have the same orientations as the bones they’re based upon. If you’ve set up your skeleton in Maya properly with behaviour-mirrored arms and legs, you’ll find that you have to pose HIK-rigged characters’ limbs separately anyway. (I only had time to look into these issues for a moment, as I had a lot on my plate; if there are easy solutions that were overlooked I’d love to know what they are.)

I had a look at the system and the commands it used when I walked through the Characterization and retargeting processes, and determined at the time that Python was not the way to go for the retargeting pipeline itself. I found in tests that it was more work to get the MEL functions behind the HIK system working from Python than it was to write MEL wrapper functions and call out to them from Python when necessary. It was also more efficient to use the MEL functions as they were, as opposed to pulling them apart to find the necessary node connections to set up the system on my own.

There’re a few lists of functions available online already (as I discovered on [insert blog link]). Here’re the ones I ended up using.

HIKCharacterizationTool, HIKCharacterControlsTool — These bring up their respective windows / docked panels. I found that not having the relevant window open made the functions that depended on the window being open fail, so keep that in mind when running HIK commands in batch.

getCurrentCharacter() — Returns the name of the current character as a string.

hikBakeToSkeleton — Bakes the keys from the rig or from another character being used as a retargeting source to the skeleton. I used this function when exporting from Maya to the game engine.

characterizationControlRigDelete() — Completely removes the control rig from the scene and sets the source for the character back to its skeleton.

setRigLookAndFeel(name, look number) — There are a few different looks for HIK rigs. In batch I found it nice to set the one I preferred before saving files out for animation fixes.

mayaHIKgetInputType — Returns 0 if input type is Stance Pose, 1 if input type is skeleton or control rig (I guess this means “self”), and 2 if input is another character.

mayaHIKsetCharacterInput(character, input character) — For retargeting, allows you to set the input of one character to be another in the scene.

characterizationCreate() — Creates a new Characterization node. You can rename the node and then make the UI recognize the new name with the following command.

characterizationToolUICmd — Useful for setting the current character name: characterizationToolUICmd -edit -setcurrentcharname [name]

setCharacterObject(object name, character name, characterization number, 0) — I don’t think I’ve seen this documented elsewhere, but this does the connecting during the Characterization phase from your joints into the character node. It appears the connections are specific and need to be fit into particular indices in a message attribute array, so the “characterization number” is something you need to figure out ahead of time if you’re doing a large number of these in batch. Some important numbers:

Ground

0

Left Thigh

2

Left Calf

3

Left Foot

4

Left Toe

118

Right Foot

7

Right Toe

142

Right Calf

6

Right Thigh

5

Pelvis / Center of Motion

1

Left Clavicle

18

Right Clavicle

19

Left UpperArm

9

Left Forearm

10

Left Hand

11

Right UpperArm

12

Right Forearm

13

Right Hand

14

Neck Base

20

Head

15

The nice thing about this is that once you know all the numbers, you can slide them into attributes on the joints in your skeleton and use that data to apply characterizations later on.

Going forwards, if I were to use the same tools again in another production (and in cases where animation needs to be transferred between two differing skeletal hierarchies, it would make sense), I think I’d pull the code apart a bit more and have a look at how the connections are made at the lowest level, then rewrite a chunk of this code in Python.

One more thing: using the standard functions, sometimes the UI will take a bit to catch up. Unfortunately, this means that functions which take inputs from the relevant UI will fail in situations where running them manually will work fine. EvalDeferred didn’t fix this issue for me every time, possibly because of how Qt and Maya are connected together and how they both do lazy updates at different times. I haven’t delved much into PyQt and Maya’s Qt underpinnings just yet, but the updating behavior is something for further study. In the interim, I found that using the maya.utils.processIdleEvents function to make sure all events were taken care of after doing major steps in the characterization or baking processes helped the UI catch up.

It’s been a while since I’ve done anything in MEL. I try to avoid MEL when I can; after two years of doing the majority of my Maya tools and scripts in Python (with the last year being pure Python), switching gears to work in MEL and losing the object-oriented nature of Python (along with its wonderful string and array manipulation tools) makes me feel like I’ve got a hand tied behind my back.

Still, MEL’s importance will continue for some time and there will be times when it’s necessary to hack out a bit MEL code. I wanted to make a quick tip note about something I’m embarrassed to say I didn’t know until a few days ago that might help you with your MEL scripts.

I use the whatIs command often to track down the source of built-in scripted functionality. Calling it on a function that exists in default MEL scripts will tell you in which script that function lives and where to find it; afterwards, you can break it apart and use the pertinent parts in your own script.

However, what I did not know is that whatIs can also tell you about in-memory variables. Here’s an example:

If you run the code you’ll see that it returns a string with the type of the variable you checked. Quite handy, since you can use it to check types of default global variables. But even handier is what happens when you use it on a variable that has not yet been created:

whatIs "$someWonderfulVariable";

This will return the string “Unknown”. If you, not unlike my recent self, are trying to determine in your or someone else’s code whether a required variable has been created, this is the way to check.

In other news, my new job begins on Tuesday. I’m extremely excited and I’ll post more about it once I’ve gotten situated there.

Also, if you’re Canadian, elections are happening on Monday! An interesting notion is the thought of voting for a non-Reform party candidate in your riding whose projections are highest instead of voting for the party or a leader you’re usually inclined to do, with an eye towards unseating the current Reform government and getting Harper out of there. Two websites on this very thing:

Three posts in three days! I don’t actually have as much time as It appears I do; the iPhone WordPress app is very useful.

I’m finally at a good place with my rigging library of COFFEE functions that now when I code out a set or rig steps, things are behaving as I expect. I’ve recreated the “Wipix Leg” in code (if you’re not familiar with it, it’s a method for making a stable IK solution without the 90 degree pole vector flip trick in used in Maya), and I’m now at a point where I have to do some rig redesigning. In other words, I’m no longer fighting the code misbehaving– now I’m back to working on conceptual stuff.

I do plan on releasing some of what I’ve learned either for free here or on a DVD at some point down the line, with my function library.

One thing I found out that really put a thorn in my side is that my constraint code was made useless by changes to the Constraint tag in R11. By cleaning up how the tag works, Maxon has rendered the tag completely useless when working from COFFEE. I’m not sure whether Py4D will be able to do what’s needed; I won’t be able to begin porting my rig to Python until the whole thing is finished. However, because you can get selected objects as arrays through Py4D (and not through COFFEE) maybe there will be better constraint code workarounds in my future.

Also nice to discover was that the Wipix Leg works just fine in Blender. Stable leg IK was the one thing for which I didn’t have a setup I liked in Blender, but that problem is now sorted. Still thinking I’ll be using Blender for my short film because of it’s speed of use. I can build that leg from scratch in Blender in twenty minutes; it takes significantly longer in both C4D and Maya.