Joint Orient UI using qt designer and maya elements
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.

 win_name = pm.loadUI(uiFile='path/to/ui/file')
# get buttons in interface
buttons = [x for x in pm.lsUI(type='button') if win_name in x]
print next(x for x in buttons if 'show_axis' in x).getParent()
# Result
JointOrient|verticalLayout
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.
PictureInterface as seen in Qt Designer
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.

 win_name = pm.loadUI(uiFile='path/to/ui/file')
# get buttons in interface
buttons = [x for x in pm.lsUI(type='button') if win_name in x]
print next(x for x in buttons if 'world_placeholder' in x).getParent()
# Result
JointOrient|verticalLayout|horizontalLayout_5
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.
 win_name = pm.loadUI(uiFile='path/to/ui/file')
# get buttons in interface
buttons = [x for x in pm.lsUI(type='button') if win_name in x]

# get location for where world vector goes and get rid of placeholder
world_placeholder = next(x for x in buttons if 'world_placeholder' in x)
world = world_placeholder.getParent()
pm.deleteUI(world_placeholder)

# make floatFields and buttons using normal ui commands
pm.text(label='World Up Dir:', p=world)
world_x = pm.floatField(v=1.0, p=world, pre=2)
world_y = pm.floatField(v=0.0, p=world, pre=2)
world_z = pm.floatField(v=0.0, p=world, pre=2)
pm.button(label='X', p=world, c=set_world_x)
pm.button(label='Y', p=world, c=set_world_y)
pm.button(label='Z', p=world, c=set_world_z)
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.
 # mel
getAttr cube.translateX;
# maya.cmds
cmds.getAttr('cube.translateX')
In pymel we can get an attribute in the same way as maya.cmds.
 pm.getAttr('cube.translateX') 
However due to pymel representing everything as a PyNode object we have a few other ways to get attributes.
 # .attr method
mycube = pm.polyCube()[0]
mycube.attr('translateX')

# short hand method
mycube.translateX
mycube.tx

# node constructor method
pm.PyNode('cube.translateX')
pm.Attribute('cube.translateX')
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.
 myattr = mycube.translateX

# get and set values
myattr.get()
myattr.set(4)

# set and break connections
myattr.connect(mysphere.translateY)
myattr.disconnect(mysphere.translateY)

# short hand for connections
myattr >> mysphere.translateY
myattr // mysphere.translateY
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.
 # disconnect a certain connection
myattr.disconnect(mysphere.translateY)

# disconnect all connections
myattr.disconnect()

# disconnect all inputs
myattr.disconnect(inputs=True)

# disconnect all outputs
myattr.disconnect(outputs=True)
If you want more information on attributes check out the article in the pymel docs. 
http://download.autodesk.com/global/docs/maya2014/ja_jp/PyMel/attributes.html

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.
https://bitbucket.org/jhultgre/maya-scripts/src/default/shelf%20tools/setupConstraintBlend.py
 
 
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.
 shadingNode -asUtility reverse;
shadingNode -asUtility multiplyDivide;
shadingNode -asUtility vectorProduct;
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.
 import pymel.core as pm
pm.shadingNode('[NODETYPE]', [NODECLASSIFICATION]=True)
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.
  utility = pm.shadingNode('reverse', asUtility=True)  
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.
jh_unicycle.zip
File Size: 290 kb
File Type: zip
Download File

 
 
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!
Picture
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.

Shrinkwrap: 
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

Arrange:
In order to keep things organized it moves the newly created shape to the next spot.

Materials:
Put a new material on the object with the option to only affect certain faces

Mirror:
For symmetrical meshes mirrors the shape node and moves it to  -x

Blendshape:
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.