This section of chapter four will take a detour to concentrate on some of the issues involved in creating a MEL-based user interface for a facial rig. This is not to be confused with the curve based UI introduced ear- lier. This interface is an extra layer of control that will really help make the rig easy, fast and efficient.
For all but the most simple productions, animators will constantly be posing the creature’s face over and over again. Giving the animators a
library of poses to choose from can really speed things up. Posing the face becomes as simple as clicking a button. Having the ability to save a specific pose will enable animators to create a collection of their most used poses. This collection or ‘pose library’ can then be saved to disk and shared amongst the studio.
Systems like these are employed in many major productions. Unfortu- nately, Maya does not natively provide a way of creating pose libraries. Of course, MEL will save the day by allowing us to program our own solution. Using a pose library can be very useful, but learning how to program one will open up a world of new possibilities. Programming a pose library involves, what I believe, to be the most overlooked feature in MEL, file input/output.
Zuckafa’s Pose Library UI
As with every application building endeavor, it will help us to plan out exactly how the program should work before you even start coding. Throughout all of the MEL coverage in this book, I have been preaching about how important it is to plan everything out. In addition to pseudo code, you may find that a flowchart can help you in the planning phase. Check out FIGURE 4.146 to see the flowchart that describes the pose li- brary functionality of the facial UI MEL script.
Figure 4.146.
At the top of the chart, we have our user interface. This is a MEL win- dow that contains, among other things, two buttons for saving/loading poses. The pose library works like this:
1. The user opens up Zuckafa’s scene file and sources the facial UI. This brings up the window that contains all of the controls for Zuckafa’s pose library system.
2. The user then loads Zuckafa’s pose library by clicking on the ‘Load Pose File’ button. This brings up a dialog box that asks the user to find the pose library file. If no pose library currently exists, the user can start a new one by simply opening an empty text file.
3. With a pose library (or empty text file) loaded, the user can then start saving poses to the open file. To do this, the animator poses Zuckafa’s face (using the curve controllers) and then hits the ‘Save Pose to File’ button. A dialog box will prompt the user to enter a name for the pose and specify an icon to represent it. A new button is created and added to the custom library tab.
4. The user can now click this new button to put Zuckafa’s face into the recorded pose FIGURE 4.147 . The user can continue adding poses in this fashion to build up a library of available poses. When the anima-
tor closes down the program, the poses are still saved in the text file on the hard drive. This text file can be re-opened at a later date, or shared amongst the studio.
Figure 4.147.
If the user attempts to save a pose before he has loaded a library, the program should return a warning. Error checking like this is essential to ensuring that the system is stable enough for a production environ- ment.
File Input/Output (I/O)
Up until now, all of the MEL scripts covered in this book have worked on some user-defined data or selection. They all follow the same for- mat. That is, the user selects an object(s) and then executes a script. The script performs some action or series of actions on that object. This completes a specific task. It may be that this is all the functionality you may ever need. Indeed, other books that are solely dedicated to MEL scripting do not even include coverage of file input/output because they consider it to be something only used in the most specialized of circumstances. Other books consider file I/O something that is perhaps too difficult or extraneous to cover.
I couldn’t disagree more. File I/O can be used in rigging systems, ren- dering systems, animation pipeline scripts and much more. To top it off, it is not difficult to implement. There is no doubt, reading and writ- ing files can be tricky, but the benefits far outweigh the time it takes to learn.
This section will provide a nice introduction to reading and writing files. By the time we are done here, you will see exactly how to create your own custom file format for storing any information you want. This section will also show you how to write a parser to read a custom file format. In this way, we will build a system for saving and retrieving libraries of facial poses. By the end of this section, you will be in love with Maya’s file I/O capabilities.
File Formats
You are already familiar with several different file formats, even if you do not know what they are. Windows applications use tons of different file formats to store all sorts of data, whether it be pictures, text, mu- sic or video. Maya itself supports two native file formats, .mb and .ma which stand for ‘Maya Binary’ and ‘Maya ASCII’. A file format is simply a way of storing a specific type of data. Of course, Maya’s formats are used for storing the information from a Maya scene file.
Whenever a programmer builds an application that saves out data, he/ she must be aware of exactly how that data is to be formated. The for-
mat of a file describes the way data is organized in the file. File formats are very specific and must be carefully prepared. Knowing the order with which data is arranged in a file enables the programmer to write code that will read the data and use it appropriately. The order that the data appears in a file is the file’s format.
The pose library system that we are building will be capable of writing out an ASCII text file that contains the exact translation and rotation of each of Zuckafa’s facial controller curves. In this way, the file system records the facial pose to the hard drive. In order to read this pose li- brary file, we must specify exactly how we want the data to be arranged in the file.
This brings up the problem of exactly what constitutes a pose? For the program are going to develop, a pose consists of three main pieces of data.
1. The name of the pose: The program works by creating a button, inside the window, for each pose. This allows the animator to simply hit a but- ton to pose the face. The name of the pose is simply the name used for the button and will appear below the button’s icon in the window. For example, a pose might be named happy, sad, angry etc...
2. The location of the icon to represent the pose: This is simply the directory path that tells the program where the image for the button is located on the hard drive. A typical directory path might look like this, ‘C:/Documents and Settings/UsersName/My Documents/maya/6.0/prefs/ icons/ZUCKAFA HAPPY.xpm’. This is the path to the image that will be used as an icon for the ‘happy’ pose. Happy.xpm is an image file with a pic- ture of Zuckafa looking happy. An .xpm file is a cross platform compat- ible picture format that Maya uses for all of it’s icons.
3. The translate and/or rotate values of each controller curve: The last piece of data that must be stored is the actual pose itself. This is com- prised of a series of values that represent the translate and rotate values of each of Zuckafa’s controller curves.
All three of these pieces of data combine to create a single pose. A se- ries of poses will combine to create a pose library. When we write this data out, it will be stored in an ASCII text file. To verify that a pose file contains what it is supposed to, you can open it up with any ASCII text editor (like Mel Studio, Notepad or Emacs). If you want to see an exam- ple of a very advanced file format, try saving and opening a Maya ASCII (.ma) file in a text editor. The first lines of an .ma file look like this: //Maya ASCII 6.0 scene
//Name: test.ma
//Last modified: Tue, Feb 01, 2005 04:43:23 PM requires maya “6.0”;
currentUnit -l centimeter -a degree -t film; fileInfo“application”“maya”;
fileInfo“product” “Maya Unlimited 6.0”;
...
Notice that each piece of the file tells something about the file. When you open a Maya ASCII file in Maya, a program will read through this file and effectively rebuild your scene from scratch. This is how you are able to return to a scene that looks exactly like it was before you last closed it.
We can learn how file formats, in general, work by observing the con- tents of an .ma file. If you have ever tried to open a Maya 6.0 file using
version 5.5 or less, you will notice that Maya returns an error and will not let you continue opening the scene file. This is not uncommon as most applications have some sort of protection to prevent people from opening a file that may not work on their current version. Newer feature additions and enhancements cause this incompatibility issue.
You can see how the Alias engineers have prevented this backwards incompatibility issue by observing the contents of an .ma file. Line four of the .ma file specifies what version of Maya is required to open the file. If the current version is less than the required version number found in the file’s fourth line, an error is returned.
Notice that on line five, the .ma file specifies the scene units (centime- ters). The program that reads .ma files will look for exactly this informa- tion on exactly line five. Because the .ma file format follows strict rules, the program will always find the information it expects on the exact line it expects. The .ma file continues on in this manner describing the saved scene file for the program to rebuild.
Just like an .ma file, our file will hold text information to describe data. Instead of a scene file, ours is a pose file. Our file format is much more simple but it uses the same basic concept. When arranged into it’s text file, a pose file can look like this:
happy
C:/Documents and Settings/User/.../icons/Happy.xpm setAttr mouthIntensity.tx 1;setAttr jawOrient.tx 0; ... sad
C:/Documents and Settings/User/.../icons/Sad.xpm
setAttr mouthIntensity.tx .5;setAttr jawOrient.tx .25; ... This particular pose file contains two poses, happy and sad. Notice that each pose includes the three components mentioned earlier (name of pose, location of icon, position of controller curves). Each of these com- ponents is on it’s own line in the file. This is important as our system will read every three lines in the file as a single pose. As the program reads through the file, it will create a button for each pose. The first line rep- resents the name of the button. The second line is used to add a picture icon to the button. The third line is used as the actual command that the button will execute when pressed. This is why the MEL command, ‘setAttr’ (setAttr means ‘set attribute’), is used. We want the button to set the attributes of the controller curves on Zuckafa’s facial rig to match the recorded pose.
This is a simple format, but it must be fully understood in order to make sense of the next part of this section where I explain the actual MEL that will make all of this happen. I hope that as you begin to understand file formats, you try and augment this one to create a format that is more robust. Perhaps you could add a character check to ensure that a pose library is not loaded for the wrong character. Or maybe you could add a line to the format that specifies which animator created the pose. The possibilities are endless.
Getting Started With the Interface
This project, like all of the scripts in this book so far, is all included in one single MEL script file. I could have split up the procedures into separate files, but I did not feel this would be necessary. In the interest of simplicity, I’ve kept them all together. Whenever you start a project like this, recall that it is absolutely essential to have the code for the interface at the bottom of the script file. This is because the interface contains the buttons which call all of the other procedures. If the proce-
dures are declared after the interface code (in the script file), the code will generate an error when sourced.
A procedure must be declared before it is called.
So to start off with, let’s quickly cover the new UI code. The user inter- face for this script incorporates a new layout called the pane layout (paneLayout). A pane layout is a handy way of splitting up a window into separate panes. Through the use of the ‘-panesize’ and ‘-configu- rations’ flags, the user can specify how the window should be split up and what size the panes should be. Panes are a great way of sectioning a window into individual pieces.
The pane layout is the first child of the window. To start off this script, make a generic window and placed the pane layout directly under- neath it.
global proc zuckafaFacialUI () {
if (`window -q -ex creatureUI`) deleteUI creatureUI; window -w 650 -h 600 -title “Facial GUI” creatureUI; paneLayout -paneSize 3 100 30 -configuration “top3” ...
“facialPaneLayout”; showWindow creatureUI;
}
This window code must be encompassed by a global procedure. This will enable us to embed the UI directly into a Maya scene file. This will be covered later.
The first line in the procedure should be familiar. This ‘if’ statement prevents multiple iterations of the same window from being created at the same time. If the window named ‘creatureUI’ already exists, the if statement evaluates to true and the window is deleted. Then the rest of the procedure procedes to rebuild it.
The second line in the procedure uses the window command to create a window with a width of 650 pixels and height of 600. This should make the UI large enough for most monitor resolutions. The window is given a title of ‘Facial GUI’ and a name of ‘creatureUI’.
The third line is the interesting one. This creates the pane layout. The ‘-panesize’ flag can be used to specify the size of a pane. In this case, we want the third pane to have a width of 100 percent and a height of 30 percent. Notice that I did not specify the size in pixels but rather in percent. The panes in a pane layout will automatically resize to accom- modate the size of the parent (in this case the window is the parent). This is especially important for this interface because the animator may wish to resize the window to accommodate his/her workspace.
The ‘-configuration’ flag specifies the type of configuration as described in the MEL command reference. The “top 3” configuration makes three separate panels, two of which rest on top of the third. There are fifteen other configurations that can be used with the pane layout. Refer to the MEL command reference when you need to choose one. The ‘top3’ configuration was needed for this particular instance because it will en- able us to organize the facial user interface into three separate sections. These three sections are:
1. A viewport that looks through a camera that is facing Zuckafa’s face. 2. A viewport that looks through a camera that is facing Zuckafa’s curve controllers.
3. A place to house the pose library.
If we source and run this program now, we will get a window that is separated into three different sections FIGURE 4.148. If you try to scale the window, the sections will also scale to accommodate the window.
Figure 4.148.
That is all fine and dandy but we want these sections to actually house some useful stuff. In the case of the top two sections, they need to actu- ally look through a Maya camera and display an openGL viewport. MEL has a really easy way of doing this. The ‘modelPanel’ layout will display what is called a ‘modelEditor’. This is a UI element that behaves exactly like a Maya viewport. We can even specify what camera we want it to ‘look through’. Add the following lines of code below the pane layout: // THIS IS THE FACIAL INTERFACE PANEL
modelPanel -cam “faceCam” -menuBarVisible 0 -l ...
facialInterfacePanel; setParent..;
// THIS IS THE FACIAL CAMERA PANEL
modelPanel -cam “UICam” -menuBarVisible 0 -l facialCamPanel; //Set the heirarchy back one level
setParent..;
These two modelPanel commands create a Maya viewport inside each of the two top panels FIGURE 4.149. The camera that each of the view- ports looks through is specified by the ‘-cam’ flag. I had to make sure to include the ‘faceCam’ and ‘UICam’ in the Zuckafa rig scene file. These cameras are pointed at the face and the UI respectively. I also tacked on the ‘-menuBarVisible’ flag to say that I did not want the menu bars to be visible. With the menu bar, the animator could potentially mess the viewports up so that they would not look through the correct cameras anymore. This can easily be avoided by simply hiding the menu. Ani- mators are a pesky breed, they will try everything they can to screw up your hard work.
Figure 4.149.
columnLayout ;
rowColumnLayout -nc 6; //Key Face Button
button -bgc .1 .8 .1 -c “keyFace;” -label “Key Face”; //Key Mouth Button
button -bgc .1 .8 .1 -c “keyMouth;” -label “Key Mouth”; //Reset Face Button
button -bgc .94 .035 .164 -c “resetFace;”-label “Reset Face”; //Reset Mouth Button
button -bgc .94 .035 .164 -c “resetMouth;”-label “Reset Mouth”; //Load Pose File Button
button -label “Load Pose File...” -c (“loadPoseLibrary”); //Save Pose to File Button
button -label “Save Pose to File...” -c (“addPoseToLibrary”); setParent..;
The use of the column and rowColumn layouts should be nothing new. The rowColumn layout is given six columns as specified by the ‘-nc’ flag (-nc is -numberOfColumns in long form). Each column has it’s own but- ton. Each of these buttons call their own procedures. These buttons pro- vide the core functionality of the user interface FIGURE 4.150. Of course, these procedures need to be declared before we can call them. When we are done with our dissection of the user interface code, the rest of this chapter will be dedicated to covering these procedures. After all of the buttons, the setParent command sets the hierarchy back to the