::Drag and Drop Callbacks::

April 13th, 2011 by hamish download the zooToolBox

Building UI in maya is usually a fairly horrible task.  I have my own UI wrappers which make building maya less painful.  It actually makes it very similar to writing UI in toolkits like wxpython or pyqt – obviously without the ability to control painting.  And it also makes encapsulating UI really easy – which is a big deal.  Anyway if you’re interested there is a post here that goes into a bit more detail – or you can check out the code for something like the Skeleton Builder UI, or the up-coming picker tool.

Which is actually where the drag/drop functionality gets used.  So in this tool there is a canvas on which you can place “buttons” and arrange them in various ways.  These buttons can have somewhat arbitrary functionality, but by default they simply select objects.  The idea being that you can arrange them in the shape of your character such that picking the appropriate rig control is easy and intuitive (you’ve probably seen them before).  In viewport controls are great, but they can make the silhouette harder to read, and they’re sometimes hard to find which causes the animator to do more camera manipulation than is desirable.  Of course having to move the mouse/focus over to a picker tool isn’t ideal either but it definitely has its time and place in the toolset.

But again I digress.  So part of making the tool reasonably easy to use is to make it easy to arrange these buttons – and the easiest way to do that is to use a drag and drop paradigm.  Well, I guess technically the easiest way is to make it auto-magic, but that is a topic for a future post (and is an up-coming skeleton builder feature!  ;).

Anyway – so drag and drop.  I’ve never bothered with drag and drop in maya before.  Looking at the docs I figued it’d be straight forward enough.  And in hindsight it actually is straight forward – although when I was prototyping I was blocked by a horrible bug/shortcoming.

Currently I’m laden with maya 2009 – and the following doesn’t seem to apply to 2011 (not sure about 2010).  But in 2009 if you set a drop callback that returns nothing, or an empty list – the drop callback silently fails.  Thats right – no warning, no error, no exception, just silent failure.  In fact, for awhile there I figured perhaps drop callbacks hadn’t been implemented in 2009 for python.  It wouldn’t be the first widget to be incompletely exposed via python – look at the press command for the treeView widget (incidentally the tree widget wrapping in baseMelUI has a nice workaround for this)…

Just to be explicit – here is an example that fails:

def dropCB( * ): return []

By changing the drop callback to return [""] makes everything work as expected.

Anyway – hopefully this little nugget saves someone else a few tufts of hair.  Of course, after discovering this I found this page – which, while not talking python here would probably have put me back on track.

This post is public domain

::back in the saddle::

April 13th, 2011 by hamish download the zooToolBox

Its been awhile since I’ve done much in maya. I mean I’ve done bits and pieces here and there, but actual full time type work – its been awhile.  I’ve spent most of the last year doing a bunch of pipeline work only tangentially related to maya.  It was kinda fun and a nice challenge too, but its great to be back doing some actual production/tools work again.

I’ve even been animating!  Man, its been a long time since I’ve done that.  It shows too – it’ll take me awhile to get back to where I was.  But thankfully I work with some amazing animators who will whip me into shape.

This post is public domain

::Live event at the Dojo::

April 8th, 2011 by hamish download the zooToolBox

The guys at Rigging Dojo are putting on a live event with Jason Parks. Check out the details here.  I didn’t go to GDC, but I did see the notes/videos from Jason’s GDC talk.  He shows off some sweet eclipse features – I haven’t tried eclipse with python but it looks like it has a few features that wing doesn’t have (or maybe I just haven’t found them yet ;) ).

Anyway, it sounds interesting so you should definitely check it out!  If you’re not using an IDE to write tools with – you should definitely check this out.  For the longest time I wrote scripts in a text editor (I didn’t have much choice – MEL has no IDE) and when I started using wing a few years ago – holy cow!  Being able to set breakpoints and step through your code as it executes – and experiment with code inside a live, running script was a HUGE productivity booster.  I’ve not used a print statement for debugging in a long time.

Props to the Rigging Dojo guys for putting together great events for the community like this!

This post is public domain

::New comment system::

March 30th, 2011 by hamish download the zooToolBox

I’m trying out the Disqus comment system – I’m not quite sure whether it will be better or worse, but it’ll hopefully make it easier to leave comments without having to create an account on my site (it always annoys me when I have to create yet another account). Either way, hopefully it’ll make commenting and conversations around posts easier.

You can post comments using an existing google, twitter or facebook account so you no longer have to remember your account details specific to this site.

Anyway – please leave comments or send mail if you have an opinion either way!

This post is public domain

::Stupid Node Name Paths::

March 23rd, 2011 by hamish download the zooToolBox

I remember when every node name in maya had to be unique.  Made dealing with nodes just using their name really easy.  Then alias introduced name paths so you could have two nodes with the same leaf name as long as the node still had a unique path.  Its been a pain ever since.  Not a big pain mind you – just an annoying ache that keeps coming back over and over again.

Anyway I had an annoying bug with one of my tools the other day.  Basically I was passing in a node – lets say it was called “someNode“.  Anyway at the start of the function call it was totally valid, but by the end of the function it didn’t exist.  There were a couple of problems that teamed up to make it extra annoying.  The first is that objExists will return True if any node with the given leaf name exists.  So by the end of the function – objExists( “someNode” ) was returning True even though any other command would throw a RuntimeError.

As it turns out the function was creating a new node with the same leaf name.  So as soon as the new node was created, the name of “someNode” immediately changed to “|someNode“.

Now I know what you’re thinking – “Dude if you’d just use pymel you wouldn’t have had this drama!“.  And you’re totally right.  If thats the way you roll, good for you.  But I expect you know my stance on pymel already so I won’t go into it.  Honestly this exact case is probably the best reason to commit to pymel.  Those who have already made the transition to it possibly don’t even know what I’m talking about.

Anyway – the fix is easy of course.  And there are a bunch of ways you can go with it.  I went the route of casting the “someNodeobject to an MObject at the start of the function, but I guess you could also detect the name clash before creating the new node and modify its name accordingly – which I guess is the only option you have if you’re using mel.  But it was a frustrating half hour of my life that I’ll never get back!  ;)

This post is public domain

::Tech Artist Interviews::

March 12th, 2011 by hamish download the zooToolBox

Reading over Rob’s latest post here I came across the following interviews with various technical artists – I presume they all presented talks at GDC this year.  If you’re a technical artist (or aspiring technical artist) you should watch these interviews.  My favourite so far is the interview with Bronwen Grimes.  I have the good fortune of working with Bronwen from time to time at Valve.  She has some great bits of advice and tid-bits of wisdom in her interview so you should definitely take the time to watch.

This post is public domain

::I’m still alive!::

March 1st, 2011 by hamish download the zooToolBox

End melodrama.

Seriously though – its been awhile since I last posted. I’ve been kinda busy of late. Life has been a bit of a roller coaster of late, but all is well. I’ve been doing a lot more tool type work in maya, so there is newness to share. So enough belly-aching, lets get on with sharing the love.

First up is a new tool – Pose Sym which is a pose mirroring tool. This is a general purpose pose mirroring tool, but its also integrated into Skeleton Builder. That is to say, you can use it with your own rigs, but Skeleton Builder makes it drop dead easy to use because it all gets setup when the rig gets built. If you have your own rigging tools however, it should be really easy for you to integrate it into them as well. I’ll write up some documentation for the tool in the near future.  Its not terribly straight forward what the settings do if you have to set things up manually, so stay tuned.  Also there are some known bugs with mirroring on single controls that should be addressed shortly.

The other reasonably obvious tool is the Skin Weight loading tool. I’ve blogged about various bits of this tool before, and its been in use for a long time now, its just taken me awhile to get around to cleaning it up to include in the toolbox. Its basically a tool that will save and load skin weights by either position or index to a file. Loading by position is really fast – in fact it defaults to loading by position because it is so fast. And the best part is you don’t even need to worry about what file is being used (although you can easily tell it what file you want to use if you need to).

I’ve also enabled some UI in the Skeleton Builder UI which should make it easier to generate initial weighting information for characters.  It uses a “volume” approach, but the volumes are just bits of geometry which make it easier to tailor the “volumes” to tricky areas.  Anyway – I’ll cover this in some more detail in a future post as well.

There are also another other couple of smaller improvements. I added stretchiness to the limb rigs – both arms and legs. Its basically the same implementation as I had in zooCST (well very similar anyway).

I added both a new skeleton part, the “Satyr Leg” and a corresponding rig for it. The satyr leg rig is stretchy as well.

Anyway thats about it. So download it and try it out and as always, spread the news to friends and other industry folks if you find the tool useful! And post comments if you have any suggestions or whatever.

Cheers!

This post is public domain

::horrible subprocess hanging bug::

February 9th, 2011 by hamish download the zooToolBox

I just got bit by this horrible “bug” (I’m not sure if its a bug or just a limitation that isn’t flashed loudly in your face whenever you use the “feature”) – which luckily, has a workaround here.

Basically what happens is if you open a subprocess and capture the stdout using subprocess.PIPE, when the stdout gets to be more than 64k of data, python just hangs forever.  Its nasty to figure out – but the workaround isn’t too bad.

Although I might add – if you do use the tempfile.TemporaryFile workaround described in the above link, make sure to do a tmpFile.seek( 0 ) before doing a tmpFile.readlines()…  This wasn’t obvious (at least to me).  My workaround looks like this:

with tempfile.TemporaryFile() as tmpFile:
	proc = subprocess.Popen( cmdStr, cwd=workingDir, shell=True, stdout=tmpFile.fileno() )

	proc.wait()
	tmpFile.seek( 0 )
	lines = tmpFile.readlines()

This post is public domain

::Merry Christmas!::

December 24th, 2010 by hamish download the zooToolBox

Maybe not here in the states, but it is in some parts of the world.  MERRY CHRISTMAS everyone, have a safe and awesome holiday season, and have an awesome time ringing in the new year!  See you all in 2011!!!

This post is public domain

::skeleton builder 101: part3::

December 7th, 2010 by hamish download the zooToolBox

This is the third post in a series of posts on the Skeleton Builder tool – it’ll be focusing on the class the defines how to rig a skeleton part.

The base class for defining a rig part is called – inventively – the RigPart class.  So any given rig part can be associated with any number of skeleton parts.  Each RigPart class has a class variable called SKELETON_PRIM_ASSOC that defines which skeleton parts it “knows” how to rig.  This variable is just a tuple containing the actual skeleton part classes the rig knows how to work with – You may notice that the existing parts use an unusual piece of functionality to get these classes (ie SkeletonPart.GetNamedSubclass) – I’ll talk more about that below.

For example, one of the rig parts is a simple control chain.  Now if you wanted, you could have this rig part associated with every single skeleton part.  Its not – but there’s no reason it couldn’t be.  After all, the rigging code simply takes a bunch of joints and their children, creates a control for each joint, and then parent’s it to the control that controls its parent joint if one exists.  Ie the rigging code will work on any hierarchy of nodes – and will thus work on any type of skeleton part.  By default however, the control chain is only setup to work on the Arbitrary Chain part.

So anyway, writing rigging code for skeleton builder is super easy – its little more than writing the rigging code in whatever fashion you want (you can even write it in mel – although you’ll need to hook up a tiny bit of glue code in python to make skeleton buidler aware of it).  Once your rig code is written skeleton builder will automatically put all nodes created by the rig into a “container”.  I don’t actually use container (coz they suck*) nodes, I instead use set nodes.  But these containers contain all the nodes used to define that piece of the rig.  So once a rig part is built, you can always go back and see exactly what nodes are involved in that part, delete them if you want, or whatever else.

You can also query existing rig parts in the scene, just like skeleton parts.  A rig part knows about all the nodes that make it work – but it also knows which ones of those nodes are controls, and a few other useful things like “placer” nodes – which I’ll talk about in a bit.  So for example, if you’re writing some code to rig up an arm and you want to know what rig part is above the arm in the hierarchy, just ask the arm skeleton part for its parent part, and then ask that part for the rig part that controls it.  Obviously rig parts don’t really have a strict hierarchy in general, so asking a rig part for its parent doesn’t make sense – but joints in the skeleton obviously have hierarchy, and you can make queries of the skeleton from within your rig code should you need to.

So placer nodes.  Placer nodes are just locators nodes that can be used as “markup”.  So for example the legs can create them for users to define where the foot roll pivots are, heel pivots, toe pivots etc…  They can also be used to help define alignment on end joints for chains like fingers or arbitrary chains.

Rig parts can also be nested.  For example just say you wanted to build a bunch of functionality on top of a simple FK spine.  You could create a new rig part that creates a basic FK spine and then adds stuff on top of it.  Skeleton Builder will then organize the parts so they’re nested into containers properly – so inside the new spine container you’ll see another container for the basic FK spine.

Now skeleton part rigs don’t need to be animator puppet rigs – they can be anything.  In fact one of the most useful things to do with skeleton builder is define “helper” parts – like for example you could define your own “pectoral deformation helper” part which rigs itself up so that it drives proper pectoral area deformation in your character.  This sort of part need not be even seen by animators – although again, if you wanted to expose a control to the animator for whatever reason, you could.

So whats with the use of GetNamedSubclass?  So this is basically a dependency issue.  The skeleton builder modules should be independent where possible.  The SKELETON_PRIM_ASSOC is a tuple of class objects, so to keep the modules independent you need some way of getting the class object without actually importing the skeleton part you want to add an association to.

When you import skeletonBuilder, all the modules get imported based on their script names.  The SkeletonPart’s metaclass then tracks any subclasses that get defined and implements the GetNamedSubclass on the SkeletonPart class so you can get a part class by name, or iterate over all available part classes.  The RigPart does the same thing.  The GetNamedSubclass returns None if it cannot find the named class.  This way you can even delete a skeleton part script and the rig parts work fine because there isn’t a hard dependency between the skeleton part script and the rig part script.

Anyway thats the overview of the rigging class – next post I might see if I can go into some actual code – maybe walk through defining a new skeleton part and a rig part (hint: its really easy).

*Container nodes almost don’t suck – they’re actually a cool concept, but they’re implemented in this kinda shit way.  For a start, any node in a container doesn’t quite act the same way in the channel box, which pisses off animators or anyone else who has to work with attributes.  They also don’t quite work with the outliner and a bunch of other UI.  So great idea in theory, but lots of little implementation failures.  Autodesk don’t really do details.

This post is public domain