I drew some custom maps based off the maps in the 5e starter set. The Thunder Tree map comes with roofs to be used as tokens on top of it and versions with and without webs.
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.
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.
If you want the finished version of this script you can find it here: https://bitbucket.org/jhultgre/maya-scripts/src/b2b5a7c61c7c56a4ed02624e75c2efb5538e8ad0/tools/jointOrient.py?at=default
The ui file can be found here: https://bitbucket.org/jhultgre/maya-scripts/src/b2b5a7c61c7c56a4ed02624e75c2efb5538e8ad0/ui%20files/jointOrient.ui?at=default
Or go to the maya scripts link in the sidebar for all of my maya tools.
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.
If you want more information on attributes check out the article in the pymel docs.
If you want to see an example of using attributes you can look at a simple script I made to setup a blend attribute for a selection of constraints.
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.
Unicycle rig by Joe Hultgren is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported 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.