Thursday, May 31, 2018

Practical Scripting for the Animator

When I started using Maya, scripting in MEL was very much beyond me. I was an artist, harnessing technology as a tool but keeping a professional distance. At a point it became a secret source of pride. But as I kept on animating I realised that I was wasting a lot of time doing repetitive actions; in this case I was setting up locators to create custom spaces.

One day I decided that I'd had enough, and I started combing the internet for how to start writing a MEL script. Stumbling through writing a script for the first time was not easy, and I'm hoping that I can give some pointers to help you out. Don't waste time doing the same thing again and again and again. That's madness. Learn just a little bit of scripting and you can really streamline your workflow and focus on the thing we all love doing: basket weaving. I mean animation.

The first thing is the easiest: set up manually in Maya and see what commands pop up in the script editor; everything you do in Maya is a command that is used behind the scenes. Using echo all commands under options, can give you even more detail about what's running under the hood. There is always a direct correlation with your actions in Maya and what pops up in the script editor. In my example, I would create a group and constrain it to the parent object.
As I do this the script editor spits out:


So as I do each manual step I can see that:
1. The command to make a group, or at least the one the Maya menu is using.
2. How to rename that group, the original name of the empty group was Null1.
3. How to select my parent (-r means replace) and -add the child with MEL before....
4. Creating a parent constraint between the two with a default weighting of 1.
    Then I create a locator, and parent it under that group. 


    5. The command for creating a locator (the -p means position in this case, so it's at the origin)
    6. Our familiar rename command
    7. Select the parent second.
    8. Parent the locator under the group.
     
    Constrain that locator to the child object and bake it out (so it keeps the original animation of the child object).


    9. The selecting and parent constraining we learned from above.
    10. Selecting and baking the constraing. BakeResult has a lot of flags attached to it.  Simulation should have been turned off because this isn't a dynamic simulation. The -t is time, so the numbers with the colon in the middle is the time range. The other one that is important to consider that I cropped out on accident is -sm, for smart bake, you can have that on to preserve your keys or bake out every frame or number of frames.

    Then constrain the child object to that locator.


    11. We constrain the child object to the locator like above.

    And done! Except, it would only work for those specific names. It wouldn't work every time, so it'd be useless except in one very specific instance

    Which leads me to the second thing, learning to store information -- in this case, the names of objects. Strings are the go to way to store object names. You can have a string to store a single name, or a string array to store multiple names. Floats and integers will store numbers for you, should you need certain values again.

    So for example:
    string $someText = "someText";
    string $lastSelected[] = `ls -sl`;  (You can then get your first object with $lastSelected[0])
    int $wholeNumber = 10;
    float $decimalNumber = 10.5;  
    There's also vectors, but I don't really use them myself.

    There were other things that were a bit more complicated to figure out. To be honest a lot of the time I just Google "Maya mel thing I want to know," and that usually gets the ball rolling in the right direction. Below are some of the resources I've come across that are very useful in figuring out how to do what I wanted:

    • Maya MEL Commands - This is a list of all of the MEL commands, it has all of the relevant flags and examples of use. I use this most often!
    • MEL Scripting - This gives a pretty good breakdown of common mel commands and gives examples as to how they work. Also covers making UIs in MEL.
    • MEL How-To - Covers a lot of different questions and is a very good resource to see how things are broken down.
    • CGTalk - Either someone has already answered whatever question you have or they are willing to if you post.
    • HighEnd3D - Has many, many available MEL scripts to peruse for free.

    I also did a lot of looking at similar scripts and breaking apart how they did things and googling the commands I didn't know. MEL is a language so there is a structure and a logic to it.

    Most importantly, find someone who knows more than you. I don't know how many times I have banged my head against the wall, because one little thing wasn't right. Thankfully I had people I worked with who could tell me what I was doing won't, but even just asking in a forum like CGTalk should help you find the answers you need to make a script work.

    Now, I know some if you have read this and are still daunted by this technical language. Don't be! Don't script for scripting sake, script so you have more animation time, meaning, script with an idea in place. You need to have a goal to work towards with this stuff. So constantly analyze what you do, what your workflow is and see if maybe there's a place to automate some of it. It'll save you so much time in the long run and you can focus on the animation itself.

    I know there's also the fear of being pigeon-holed into a technical route if you reveal scripting knowledge. I know because I've been there, but really, in my experience, people are grateful, but not expectant. Also don't be afraid, if you feel you're being pushed in a certain direction, feel free to speak, your mental well being and desire for growth in certain areas should be a welcome discussion point with your boss. It should also be pointed out here that your job, as an animator, is to animate; script on your down time, or at home, or if you really need a tool, make sure the time writing is less than the time saved. Don't get tunnel vision and distract from your actual work.

     Before I sign off, here's a list of things that I find supremely useful:
    • Always end your lines with a semi-colon, it lets Maya know that command is finished. Likewise if you are using a command  within the context of something else (like defining a string) put tildes on either side.
     
    • objExists - Checks to see if anything with that name exists in a scene.

      objExists pSphere1;
     
    • getAttr - Returns the current value of any attribute.

      getAttr ( $object + ".visibility" ) ;
     
    • setAttr - Sets the attribute to whatever value is given.

      setAttr ( $object + ".visibility" ) 0 ;
     
    • For/In Loop - This lets you do the same thing for multiple objects in an array. In my example above, apart from the first object, any other object I select I would want to generate locators and constraints. The for/in loop allows me to do the same action again and again for multiple objects.

      for ($object in $objects){

      parentConstraint $object $parentObject; }
     
    •  If/Else - Good for toggling type hotkeys. If this condition exists, do this; otherwise do this.

      if(`objExits pSphere1`){
      select pSphere1;
      }else{
      polySphere -name pSphere1; } 

    • Tokenize - You can break up the name of an object based on an alpha-numeric character. I use it to try and to get namespaces, more often than not. In the example below, you can see I'm using the first section that comes out of the tokenize (the [0] means it's the first) because that's usually the namespace.

             string $object[] = `ls -sl`;
             string $storageBuffer[];
             tokenize $object[0] ":_" $storageBuffer;
             string $nameSpace = $storageBuffer[0];
     
    • whatIs can help you figure out the specifics of a command. Sometimes a command behaves strangely or inconsistently, you can use whatIs to find out what it actually is and if it's part of another command. For example, when you break connections on an attribute, CBDeleteConnection comes out. If you use this command, it didn't always work, because it's waiting for Maya to source the script it lives in on your hard drive. Using whatIs you can find exactly where it is and what commands it is actually using to break that connection.

      For instance! In the first example I used doGroup to make an empty group, using whatIs I was able to find that mel script in my maya bin folder and find that it was using the MEL command group. You can use group -em to make an empty group
     
    • Pretty well all commands come with flags to define what you want to do with them. For instance, if you look at keyTangent, the MEL command that deals with tangents, there's loads of flags. And a lot of them you can query too. For instance you can query the in and out angles of your tangents, if you're into that sort of thing:

      keyTangent -query -inAngle -outAngle pSphere.translateX ;

      And it should then return to you with two numbers. Usually you have "command -flags $object(s)ToActUpon".
    I really hope this is encouraging and not scary. It's not imperative to learn scripting to animate, but it sure can make it easier.

    Keep on keyframing!