One of the nice things in Maya is being able to make interfaces for tool using Qt and Qt Designer. Unfortunately not everything in Qt has a corresponding UI element in maya, even for some things that you think there would be. One most glaring omissions is that a Qt float spinbox doesn't get mapped to a maya float field.
While recreating the Comet Joint Orient tool over to python I ran into this issue while trying to replicate the world up and tweak vector fields. If you just want to get the value from a float spinbox you can by routing its information into something maya does know how to talk to, usually a line edit, using Qt signals/slots mechanism. However the comet version of the tool has buttons that set the field to a given preset vector and I couldn't get away with only reading the values. The obvious solution to that is to try creating float fields in maya and add them to the Qt interface.
In order to add new elements to the interface we need to know which layout to we want to put things in. For this tool we have two layers of nested layouts in Qt Designer, horizontal layouts for each row of elements and a vertical layout that hold all the horizontal layouts. If we take the Show Axis button for example and ask it what layout its in we would expect something like JointOrient|verticalLayout|horizontalLayout1. Lets see what we get.
Wait a minute were is our horizontal layout? So it turns out when you have nested layouts maya decides to only see the parent layout. This obviously causes us a problem when we are trying to find a specific layout, so what do we do. Interface as seen in Qt Designer
The answer to this problem is to organize our interface using widgets instead of layouts, at least in the places where we want to add things after loading the ui file. Once we have a widget we can set it to have a horizontal layout for the things we add.
Now with our widget layout lets try the same thing that we did with the show axis button. Make a button inside the widget to look for. We are expecting something like JointOrient|verticalLayout|widget.
Alright so now we have a horizontalLayout but why didn't our widget show up in the path? Whats going on is that maya doesn't see the widget, but since it sees the top layout in a widget we can still get what we want. Since we have a reference to the layout from our place holder button we can just delete the button and use the reference as the parent for the new elements we add.
I've created an updated tools reel that you can watch here or on my demo reel page.
So last time we looked at making some utility nodes that we can use in our scripts. Today we'll look at how to actually use them and in doing so we'll look into how pymel handles attributes.
If your coming from mel or maya.cmds the syntax you're used to to access attributes will look this.
In pymel we can get an attribute in the same way as maya.cmds.
However due to pymel representing everything as a PyNode object we have a few other ways to get attributes.
The .attr method looks pretty similar to getAttr except that you call it as a method on a PyNode. The common reason to use this is when you don't know what attribute you want when writing your code. You might be getting which attribute you want at runtime from either an interface or a function.
Using the short hand syntax is convenient when know what attribute you want from the start. You can use either short names or long names of any attribute including attributes you have added yourself. I usually use this way because it makes my code easier to type and read.
The third way of getting an attribute is using node constructors. I've listed two ways to use method pm.PyNode and pm.Attribute. Both of these return the same thing an attribute object. In fact the .attr and short hand syntax also return attribute objects.
Having these attribute objects lets us easily keep track of the attribute we want no matter what else if going on in our scene. We can rename or change the parent of the object it is attached too and the attribute object will still point to the correct place.
In order to use our attribute there are a few methods to know.
Now .get and .set should be pretty self explanatory, they let you find out or change the value of the attribute.
If you want to change connections to an attribute you have a choice in syntax either long form or short form. For making connections I generally use the short form because its faster to type, but if you don't do a lot of scripting you may want to use the long from so you remember what you are doing.
When disconnecting connections I always use the long from. This is a little bit preference for me because I like to be more verbose when I'm getting rid of something and also because the .disconnect methods has a few options that the short hand syntax doesn't.
When building a rig utility nodes like mulipyDivide or reverse are a handy way of setting up functionality of controls. But after you've setup an IKFK blend for what feels like the hundredth time you start looking for a way to automate connecting up all those attributes.
If you go to the pymel docs and search for how to create these nodes you probably wont find what you where hoping for. While the latest docs have information on the nodes themselves there aren't any good examples like there are for most of the other pymel commands.
Since the docs aren't helping lets go back to Maya and look at what is output to the script editor when we make these nodes by hand. Open up the hypershade or node editor and make some of the nodes we want. You should see something like this.
Looking at these they are all made with the shadingNode command. If we go back to the pymel docs we can find a command that matches up in rendering/shadingNode. The examples are still pretty sparse but essentially we use the command like this.
For [NODETYPE] we enter what node we want as a string, in our case 'reverse' or 'multiplyDivide'. [NODECLASSIFICATION] is needed to tell maya where to put this node in the hypershade. We use as asUtility=True since we are making utility nodes, if you are making a light or shader you should use asLight or asShader respectively following the docs. So when we fill those things in our code will look like this.
The command returns a pynode which contains the node made which we can store in a variable in this case utility. With our node safely in a variable we can use it however we want.
Now that we have our utility nodes how do we hook it up?
To do this we have to look into pymel's attribute system which I'll be getting into next time.
I've been meaning to do this for awhile but I've gone back and reorganized my maya scripts site. There are now folders that group things into different categories and some of the files have been renamed to be more descriptive. I've also started adding some newer things I've worked on. The wiki page over at bitbucket explains what the folders are.
I had someone ask if they could use my unicycle from my short film. Since I probly wont have too many more uses for it why not just release it to everyone. There is a pretty comprehensive readme included that should explain the complicated parts. and I would recommend reading the suggested usage section before animating with it. I 'm releasing this under a creative commons license.
Here is a new character I'm working on. Its fanart for Kerbal Space Program based off of Gene Kranz from the Apollo era mission control
I'm going use him to practice writing rigging scripts, now I just have to decide how I want those scripts to work.
So I'm going back to siggraph this year as a student volunteer again, and this time I have more stuff to show while I'm there. Not only do I have my short film and the start of a TD reel, but a visualization I programed is going to be displayed outside of the Emerging Technologies and Art Gallery room. How cool is that!
hey look a screenshot
So all the booths in that room have QR codes next to them that people can scan with their phones and I took that data and tried to figure out where people are moving to. The screen shot is just using random data to run since the conference hasn't started yet but I imaging the real thing should look just like that but only more awesome because it will be at siggraph!
Its written in Processing which I hadn't used before but was pretty easy and fun since its just a flavor of Java with more graphics going on. I had fun doing it and it was a nice review since I got to use some programing concepts I haven't used since sophomore or junior year at ISU.
So I've graduated from VFS in Digital Character Animation and have a film to show for it. Its kinda bittersweet to leave I'm glad to be done and all but I'm gonna miss my classmates and Vancouver. Also this means I have to go and find a job somewhere now, there's no going back to school a third time for me.
Up next is a quick trip down to LA and San Francisco to see some friends and see if theres a city I would rather live in so I can focus my job search some.
I wrote this tool so I wouldn't have keep doing the same things over and over when making my blend shapes.
Its pretty easy to add new stuff just make a new subclass and make sure to implement 3 methods, then add a button to the right side for it. Its on my maya scripts bitbucket as blendshapetoolkit.py
The things the tool does are.
The first part I wrote because I wanted my blendshapes to keep the cylindrical nature of the helmet.
It has the option to select only the verts that I want to affect
In order to keep things organized it moves the newly created shape to the next spot.
Put a new material on the object with the option to only affect certain faces
For symmetrical meshes mirrors the shape node and moves it to -x
Adds the shape to the blendshape node of the target object
not shown in the video are the ability to rearrange the order and to save and load the list.