Monday, November 28, 2005

Switching by object picking

Rigging
Solved the eye stretching problem with additional spurs.
Went through rig and renamed a lot of joints and controls.
Got ear controls working. Ear cluster selections can be hidden from the head control Enum switch, as well as activating and deactivating them. Used combination of IK twist and roll, and an added locator to move surrounding bones, in addition to cluster rotation.
Model fixes around eyes.
First pass skinning is done.
Got jaw working.
Added pupil size controls.
Planned improvements:
Jaw and whisker controls.
Head topology controls.
Controls for retractable claws.
Updated 2am 11/29: Added wire spheres for visible cluster hierarchy axes.

Scripts
Well, I had written a script today. earSelect.mel. But it's already obsolete.

I finally figured out how to make a self contained character which doesn't need external scripts for such things as selecting an object and that selects another object and deselects itself. I used this for ear cluster selection controls. The same process also helped me figure out how to make the foot axis switch work without having an extra "spare" channel in the expression. Essentially, I found that I could write an expression as a "global proc" and then run a script job that calls it, all within the .mb file. I also figured out how to turn the selection feature on and off. The current selection expression is completely brute force. I'm hoping I can figure out a more efficient way to state the expression.

This was one of those revelations that I couldn't find a single example of, other than using the Maya help file examples. I just put a couple of things together.

Planned improvements:
I still need to figure out how to make the object switch so I can use "undo". Right now, it hits "undo" and that actually calls the script again and contravenes the process of "undoing".

Updated 2am 11/29: Done. Undo works properly now.

Saturday, November 26, 2005

Stretchy Head

Rigging

I've finally figured out how to get my idea for a stretchy head which also allows some topological control, working. It's not perfected yet, but I'm getting closer. I can get pretty close to proper skin assignments on the initial smooth skin pass, so won't need tons of vertex reassignment.

Scripts

sphereAB //This makes two spheres used by makeStretchyChain, and locates the first at a selected bone, the second offset by a command line input. Can probably be used for other auto creation functions.
Plans for improvements:
Ability to set number of spheres.
addCrazyLoc //Makes a locator with the .name attribute so I can test out scripts that use it for naming new objects.
Plans for improvements:
Right now, this is character specific. I will make it so it can add a locator with the .name
attribute for other characters, or multiple characters. At that point, I'd have to update
the other tools to accommodate multiple characters.
spurBuilder //Creates 6 bone spurs for directing smooth skin assignments, and parents them to the selected bone or object. Command line radius from a selected parent bone or other object. This one has been a huge time saver. Auto-names with SPUR prefix and selected object's name.
Plans for improvements
Adjustable number of bones
Accommodation for compound names that have _L and _R in them.
Ability to automatically decide which character is being used in multiple character situations.

Friday, November 25, 2005

Catching up, part 2

Scripting

As part of my dual front self-training methodology, I'm writing scripts while working on my rig. This gives me a way to focus my energies, rather than working on generalized scripting tutorials.

When I find that I'm doing something repetitively, I write a script. Since I'm taking use of a character in a pipeline into consideration, a big part of my goal is control of object and node names.
This is a major reason I'm working on my own rigging script. If I get a character TD job, I'd like to bring in my tools and know what part of the script to alter to accommodate an existing pipeline.

I'm also finding that as I learn how to write tools of my own, it gives me an idea of what to look for in existing scripts: commands, methodologies, naming conventions and processes. I'm trying to make my scripts clearer for others to follow, and that means eschewing the convenience of short string names for more descriptive ones that can be followed from one process to another.

The scripts I've created so far, of course, duplicate the utility of more elegant ones that can be found on places like High End 3D. I'm avoiding even looking at what's in those scripts so I can learn to build my own instead of just copying what already exists. Most are difficult to follow anyway, because they have nice, user friendly interfaces and the origin of variables is somewhat obscured.

Here's what I've got so far:

Start script job //activates a script job for a continually used command by character controls
autoJoint //this is the first version of my foot pivot switch. I've since deployed a version of this as an expression.
clippingPlane //sets the clipping planes on all cameras from the defaults when the units are changed so you can actually see objects.
makeFootPivot //creates all of the objects which represent the various foot axes, aligns them to the joints and creates the attributes on the foot controller to switch them.
Plans for improvements:
Generalize to accommodate different character names
Use loops instead of discreet commands
Automatically create expressions
Create foot object space switching.
pivot switching expression //adapted the autoJoint script to an expression to avoid need for script job
alignObjects //my version of the "align objects" tool in Max. I wrote this to be able to discreetly control alignment of object in space and orientation and can call this within other scripts when building and orienting objects.
clusterer
//creates clusters on CVs in the order they were picked. Still needs work because of the way Maya represents multi-selection of CVs. Works now only if I pick CVs in reverse order.
syncLoc //creates a locator for each object selected, aligns it, then constrains the original objects to the locator synchronized to it.
Plans for improments:
Flag system to choose point, orient, point and orient, or parent
Command line entry to choose an object class. Currently each new locator is given the class "LOC"
renamer //this allows a selected group of objects to be renamed, with each new object having a number suffix (_1, _2, _3) added to the end.
renamerA //same as renamer, but letters are added to the end instead to avoid confusion with Maya's auto numbering scheme for duplicate objects (_A, _B, _C). At present, it only allows for renaming of 26 objects before it runs out of letters, but I haven't come close to renaming more than that yet.
Plans for improvements:
Combine renamer and renamerA with flag system
Add "prefix only" mode
geoConstraint //this is a tool that will constrain a group of selected objects to the surface of another object.
multiConstraint //this works like geoConstraint, only it constrains the multiple selected objects with a point, orient, or point and orient constraint. I'll probably combine the two with expansion of my flag system later.
syncLocParent //like syncLoc, only does a parent. This will be folded into syncLoc when I get to it.
stretchySkel //actually less functional than it sounds. This was the first script I created to speed up creation of a stretchy skeleton. All it does it connect the mult/divide node to the .tx of selected joints.
syncLocNoneg //this creates synchronized locators but doesn't constrain or parent anything to them. It has the additional function of parsing the object name and automatically giving the new locator the same name, but with object class changed.
makeStretchyChain //my current version of this creates a joint chain between two objects, aligns the axes of the joints, adds an IKSpline solver, adds the nodes nodes and connects attributes that make the chain stretchy. I have two versions of this: one uses joint translation and one uses joint scaling to make the chain stretchy. Command line options allow setting the number of joints, and the appendage name. Joints are sequentially suffixed with letters (_A, _B, etc.).

This last one took some time to evolve and trouble shoot. While I'd figured out how to make a stretchy chain manually several months ago, automating the process took some figuring out.

The development of the script proceeded in logical parts. This all started sometime Tuesday (11/22) when I was making all sorts of stretchy chains to test out various ideas on the head distorting thing. This is essentially something you'd only do on a cartoon character, but that's what I wanted to do right now. I haven't gone back to the head tweaking problem solving yet, and the chain idea is probably overly complicated for the results I want to achieve. But if it takes 10 stretchy chains to achieve the results reliably without compromising other controls, so be it. I needed a fast way to draft chains, and I'd have to make a script like this eventually if I want to have my very own rig building script, right? And I'm not about to let a little fact like the one that I just started learning scripting less than two weeks before, and that this might be overly ambitious at the moment, stop me, am I?

I'll start from the beginning.

It took a while to figure out how to build the joints where I wanted them.

First I thought I'd just build them evenly between two objects. This meant calculating world x y z euclidean coordinates between two points. I cobbled the xform part of the joint switching script to get the world space coordinates of the spheres, and just did simple math. The approach worked OK, but wasn't all that flexible. Sometimes the joints don't follow a straight line path.

I decide to build the joints along a curve. So first I had to build the curve. That became the first part of the script, still using the xform lines from the first version. The second part would have been easy if I knew what I was doing. In this case, the search for the right node took longer than usual, probably because I was trying to figure this out at 3am. I wasn't going to go to sleep until I figured this out.

The magic bullet was the pointOnCurveInfo node. I did some manual experimenting with it to find out how to get the info I wanted. Finally, I figured out how to use a percentage to get the position info out. I just added a loop that divided 1 by the number of joints, got the percentage and successively added each joint to the new position. Anyone reading this can tell I'm proud of the fact that I figured this out. To me, it was a profound revelation, because I can think of all sorts of uses for this tool.

Now...I'm sure I could have just found out the answer to this by dumpster diving existing code (this is not to say existing code is trash, it's just hard to find what you're looking for when you don't know exactly what you're looking for). But when you wrack your brain to figure something out yourself, you tend to learn more thoroughly, and along the way think of other places the information can be useful. Sometimes you find stuff that's totally irrelevant to the task at hand, that comes in handy later on.

The rest of the first draft of the stretchy joint code was pretty straightforeward. I just manually built the stretchy part in the interface, looked at the script editor, and translated that into loops and conditional statements. Couple of glitches plagued me: I was using specific object names for curves and nodes the script was creating. Problem was, on repeated testing of the script and diagnosing failures to get the desired results, new nodes and curves were created, and subsequent ones created by the script were getting suffix ascended. So the script would try to use the old ones, which were wrongly assembled. It finally occurred to me that this was happening, and I made an objExists check. My first use of that command, though I knew it existed.

Finally, I get it all working. Except that it doesn't work as well as my hand assembled versions. Examining the entrails, I found that the joints were oriented wrong. And when I used Jason Schleifer's jsOrientJointUI2 script to fix them, they worked fine.

I tried to deconstruct jsOJUI2 to see how it worked and to add that scripting to my script. My effort at cheating was resoundingly thwarted by the complexity of the script. I also knew, deep down, that if it worked in the interface but not my script, even though it almost worked in my script, I was missing something fundamental. So I posted on Schleifer's forum just before midnight Wednesday (11/23). I stayed up another three hours trying to figure it out, but I was just Wile E. Coyote-ing: losing sight of the goal through obsession.

Yesterday morning, before Thanksgiving Linner and the family gathering, I sat down and systematically broke the problem down. I copied and pasted portions of the script in the script editor and executed them. I checked the orientation by turning on the display of the rotation axes. I compared them to the joints built manually. I looked at the script editor as I made the joints. Well what do you know? After the first joint, subsequent joints have a command that aligns the joints. DUH! All I needed to add to make the joints align properly was a conditional statment in the joint construction loop: if ($counter >0)
{joint -e -zso -oj xyz -sao yup $jointname[($counter - 1)];}

What's the point of explaining all this? Well...documenting the learning process isn't just about what I did and when for me. What I learn by the process of goal, failure, tenacity and finally success took me down all sorts of roads that I saw all sorts of sights on. I know a lot more ways of doing something wrong now, and I saw solutions to problems that I've only vaguely started thinking about. But I expect that if I work as a character TD somewhere, I'm going to have to improvise and solve puzzles all the time.

Catching up, Part 1

This is where I'm at now.

Rigging
I've created my "switching pivot" control. A problem I've always thought needed addressing was that when a character walks, the foot pivots on either the heel or the ball of the foot. Most setups default to rotating around the heel so when the foot makes contact with the to in the air, it's simple to just rotate it down flat. But you don't change direction that way for the most part. When we change direction, we usually lift our heel a little and pivot on the ball of the foot.

The solutions I've seen seem inadquate. On my last Maya character, which I called "Alex", I had what now seems like the standard "swivel ball of the foot" control. The problem was, that if the character turned 180 degrees, I had to resynchronize the foot control with the ball of the foot. It was even worse at 90 degrees. This character was running all over the room. The foot pivot problem was most annoying when the foot lifted up. Synchronizing it added keys where I didn't want them, and made refining the animation much more time consuming.

Another thing about the foot pivot problem, is that when our foot is up in the air, it rotates around the ankle. Having it rotate around the heel looks unnatural, and compensating for it is, once again, time consuming.

This is a repeating theme in my rigging choices. Compensating for rotational pivots in the wrong place for the animation at hand and compensating for rotational hierarchies which make the extremities swing in an undesired arc not only are time consuming, but they extend the already labor and artistic intensive tasks in refining the animation.

So I created a pivot switching feature for the foot. This has evolved some in the last two weeks. I started by writing an automated system which executed a MEL script that was run as a script job. You would pick icons which represented the heel, ball and ankle. That would automatically switch the pivots. After testing this out on the character, I found that this was unsuitable because you had too many controls too close together. My current version has a pull down menu in the channel box which allows you to choose the rotational preference. This is animatable. When the pivot is switched, I have iconic representation on the foot with objects that represent the heel, ball and ankle pivots which can be seen at a glance. The icons are non-selectable. At present, I haven't figured out a way to color them for highlighting at the same time they are a "reference" object. I also haven't figured out a way to make the system work without keying the rotate pivot and rotate translation pivot channels, and having them visible. On top of that, the expression only executes if I have an active connection specified in the visible channel box. Even if I can't solve those problems, it's not too big an inconvenience. Just means that adjusting keys during the animation involves moving a lot more channels for the feet. But it all works, and that's what's important right now.

The foot also has a hierarchy switching mode. At present, it switches between "World", where the body moves and the feet stay stationary until you move them, and a "Body" mode, where the foot moves with the main COG control. So if a character does a flip, an animator doesn't have to manually keyframe the arc, they just have to worry about the placement of the feet relative to the body. As would occur naturally.

Another thing that I've wanted to add for a long time is a switch for the hand space. I now have a pull down menu in the channel box with 7 IK hand modes. I also have a pull down menu on the clavicle which isolates the rotation of the shoulder from the rest of the body. The hands can each be selected to rotate with the body, remain attached to the world, translate with the body and clavicle without inheriting rotation, ignore the clavicle but still move with the body, and nearly every combination of all these. In addition, the hand can be used in a semi-FK fashion by rotating the clavicle control. The clavicle control has been modified as a target, rather than rotation control for the clavicle itself. Move it up, the clavicle rotates up. Move it forward, the clavicle rotates forward. This method allows the clavicle control to be used both for rotating the arm from the shoulder FK style, and rotating the clavicle simulataneously. The switches are animatable and easily accessed from the channel box. There are 14 possible combinations between the hand and clavicle controls, but I'd imagine an animator would stick to 2 or 3 depending on their preference.

Plans for further improvements:
Stretchy switch to turn off the stretchy IK
Spline IK for the ability to give the arm a more "rubber hose" kind of shape, with adjustable hardness on the elbow. As I currently envision it, this control will also allow for the appearance of "successive breaking of the joints" in IK mode.
I think the FR rig allows for stretchy fingers. But I plan on devising my own system.

I've also created a pull down control for the head, to isolate the head rotation from that of the body. This makes it a lot easier to achieve overlapping action in the head without counter-rotation. The default is FK, but the switch is simple and animatable.

I'm currently working on some sort of system for distorting the head. So far, I have found that using a wrap deformer has too many pathologies, the main one being that it is additive to the joints. The character has long ears in this case, and the wrap deformer has worked against every method I've come up with for discreet control of the ears. I've also had problems so far in deploying wire deformers. I plan to continue trying to find a viable solution to this today, experimenting with the many deformation tools available in Maya.

Last, I successfully came up with a way to control the eyes no matter how much they're distorted. The pupil stays the same size and shape regardless of what happens with the topology of the eyeballs themselves. This was more challenging than I thought, but the solution I chose is working perfectly. I also figured out a way to make the eyelids conform to the eyeball when they're opened and closed, regardless of changes in the eyeball's topology.

Plans for further improvements:
I'd like to add controls to adjust the shape of the eyelids, since this character doesn't have eyebrows, to accommodate emotional states.

The blog begins

I decided to start this blog to document, among other things, my learning progress in Maya rigging. I think there's a kind of distrust of people who are self taught at anything, particularly when they have no education background in what they're teaching themselves. Probably for good reason, since it isn't easy. And too many people lie.

I'm learning Maya rigging and MEL scripting because, well, just being an animator isn't good enough anymore. At least not if I want to gain employment in Los Angeles, where I live and where the people who seem to be the best at everything tend to congregate. While I know something about rigging from years of experience with Softimage and Alias Poweranimator, there are a lot of new tools available these days, and MEL commands offer a whole new level of controls I can add to characters, using tools I'd never have guessed existed. I'm pretty excited about this.

I've put off learning MEL scripting because it's completely antithetical to artistic thinking. But now that I'm getting into it, it satisfies some part of my brain that enjoys solving puzzles. So does rigging a character. You figure out what result you're looking for, and work backwards. Breaking the problem into a series of smaller problems and solving them one by one.

The learning resources I'm using at this time are The Jason Schleifer Rigging Bundle and Mel Scripting for Maya Animators.

I'm not following these references sequentially. Instead I decided to start by actually rigging a character. The character, KrazyCat (kind of a "Bill The Cat"-esque character), is one I actually bought since I feel that modeling a character from scratch at this time is just a distraction from my ultimate learning goals. I've changed the model somewhat to make it more amenable to animation.

In this first pass, rather than starting by building a rig from scratch, I decided to start with a rigging tool called Final Rig. I rightly figured I could see what features existed in a modern rig, and modify it piece by piece with my own ideas. Eventually, when I've settled on the features I want in a rig, I'll build a new one from the ground up with my own built from scratch rigging script (for which I've already started writing the base scripts).

I started all this about two weeks ago, and wish I'd started earlier.