::serialization fun!::

October 29th, 2011 by hamish download the zooToolBox

I’ve been tinkering around with this little project for awhile now.  I’ve always wanted to try to write a simple little serialization format.  I know there solutions already out there – and in fact pyYAML seems to do everything mine does WAY better than I’ve managed.

But thats not the point.  The point is I wanted to try and do it myself as an exercise. Its kinda tricky writing a nice serialization format and it was actually a fun little project.

Anyway, so what does it do?  Well, I wanted a text based serialization format that was easy to read and on the odd occasion hand edit.  You could write them by hand too if you’re feeling masochistic, but I strongly discourage it.  Having an easily readable, text based serialization format is terribly helpful for the occasions that you just want to crack the data open in an editor and see what the hell is going on.

Of course, you want to be able to write out interesting data too.  Which is obviously why pickle is incredibly appealing.  But pickle files are basically impossible for us mere mortals to read.  Plus they can also be abused by bad programmers (bad meaning incompetent or malicious).  I had a case recently where one of our tools was being hellishly slow.  So I spent a heap of time in a profiler trying to figure out why.  Turned out this particular tool, which was storing out data in pickle files, was pickling a database abstraction object.  The mere act of unpickling the file would cause a bunch of database activity.  In this particular case the tool was unpickling lots of these files which ended up taking a long time.  It took awhile to even bother looking at file loading as the culprit because the files themselves were only a few hundred bytes.

This is an easy mistake to make inadvertently in a language like python.

Pickle is amazingly cool.  Its also a VERY powerful tool to put in the hands of noobs and can sometimes cause headaches.

Anyway enough talking, lets look at some codez!

import os
from maya import cmds
import sobject

objToSerialize = sobject.SObject()
objToSerialize.sceneName = cmds.file( q=True, sn=True )
objToSerialize.currentSelection = cmds.ls( sl=True )
objToSerialize.someRandomDict = { 'data': os.getenv( 'USER' ), 'cwd': os.getcwd() }
objToSerialize.subObj = subObj = sobject.SObject()
subObj.interestingNumbers = range(3)
subObj.cyclicReference = objToSerialize

Kinda pointless data, but basically the objToSerialize object will be able to serialize itself to disk in a nice human readable way. The above code serialized to disk looks like this:

42035216:
	sceneName(str):c:/somePath/someFile.ma
	currentSelection(list):
		(str):pSphere1
		(str):pCube1
	someRandomDict(dict):
		(str)data(NoneType):None
		(str)cwd(str):c:\Users\macaronikazoo\Documents\maya\scripts
	subObj(*):42035376:
		interestingNumbers(list):
			(int):0
			(int):1
			(int):2
		cyclicReference(*):42035216

Thats fairly readable, right? Hardly a Dan Brown novel, but certainly easy enough to digest should you need to go poking around. And obviously if you need to get this information back into python, its as simple as passing either the string data to the Unserialize class method, or passing a filepath to the Load classmethod. Like so:

objToSerialize.write( '~/sobject_test_file.txt' )
unserializedFromFile = sobject.Load( '~/sobject_test_file.txt' )  #unserialize from file
assert objToSerialize == unserializedFromFile

Anyway – if you’re interested in taking a look at the code, feel free to! Its right here.

This post is public domain

::A Tidier Toolbox?::

October 25th, 2011 by hamish download the zooToolBox

I’ve been wanting to tidy up the toolbox for a LONG time now.  I’ve been slowly chipping away at the task the last few months. I think its finally in a decent enough shape to release.  So here it is.

So whats new I hear you ask?  Well…

  • Complete animation library re-write: It finally does what I’ve always wanted it to do – saving out both local space animation data AND world space animation data.  Which isn’t useful all the time, but sometimes it can be a real lifesaver.  Plus because the tool works based on selection, you can load part of the clip in worldspace and the rest in local space.  The tool still works and looks exactly the same, but under the hood things are much nicer.
  • XferAnim is also a complete re-write to slot in better with the new anim clip.  They both share a lot more code now.
  • Easier install: There are no longer dagMenuProc scripts that you have to rename.  The toolbox should setup the dagMenuProc automatically when it loads.  There is even an option that will attempt to setup the toolbox to auto-load on maya start (although I haven’t tested this on very many setups yet so its hard to know how robust this feature is).

So basically now all you should need to do is unzip the toolbox to your maya/scripts folder, startup maya and run the zooToolbox MEL command.

Enjoy!

This post is public domain

::Skeleton Builder Retrospective::

October 15th, 2011 by hamish download the zooToolBox

A recent g+ post from Christopher Evans prompted me to revisit the shortcomings of Skeleton Builder – my most recent public attempt at writing a rigging framework. I’d link to the g+ post, but sadly, its not public. I think in general Skeleton Builder is a really useful framework – it has certainly made me a more productive rigger in every single way. But its far from perfect, and often analyzing a project’s failures is the best way to learn so here we go.

Of course to look at failure we need to understand the initial goals first. Skeleton Builder (SB) is my second attempt at writing a rigging framework. Not an auto-rigger, although it is an auto-rigger.  But the part of the code I’m most interested in analyzing is the framework part. I’ll go into the difference in a bit. With SB I wanted to solve a bunch of problems.

  1. Skeleton construction and joint alignment. I wanted to make it easy to construct arbitrary skeletons without burdening the user or the riggerwith joint alignment problems. I wanted consequent rigging code to be able to make guaranteed assumptions about joint alignment.
  2. I wanted every skeleton part and every rig part to be introspectible from code. I wanted this so that rig parts could ask questions of other existing parts. This would allow them to be easily re-purposed and extended. It would also allow richer animation tools to be built upon them.
  3. I wanted to be able to write a bunch of common code for a “limb” and have it re-used by biped arms, biped legs, quadruped legs, arachnid legs etc…  If not done via inheritance, then at least provide the same interfaces.
  4. I wanted very little overhead to actually use the framework. I wanted to make it really easy to port existing rigging code over to use the SB framework.
  5. And lastly I wanted to write a procedural UI to the framework so that non-technical users could use it and so rig coders didn’t need to write UI.

So those were the major goals.

The first was was a mixed success. While the tool makes it really easy to build skeletons without having to worry about alignment for most things, its not immediately obvious to users that this is the case. Ideally the alignment would change in real-time as they’re making skeletal adjustments. Also joints like wrist joints still needed to be oriented manually. This wasn’t terribly obvious to users either, which is fair enough. As an end user when you see everything being automated, you don’t really stop to think whether there is anything you might need to pay attention to. So the tool should have made more of an effort to point out user intervention is required in this case.

The second point was also a mixed success.  SB has a bunch of helper functions in it to make coding space switching super easy.  Setting it up was generally a single line of code per control, or if you weren’t picky you could even use the  “auto space switching”. Space switching is amazingly useful and in fact, usually when I forget to put it on a control, I eventually hear back from an animator – “hey, can I get space switching on control X please?”.

Anyway the problem with space switching is that it is a confounding factor when you need to sort rig controls hierarchically. Space switching provides a way to effectively change the hierarchy. So without some way of taking this into account when you need to sort controls hierarchically, this can be a problem for a tool writer. So that in my opinion is a failure and I’m not even quite sure what the best solution is.  I mean its easy enough to write a function that takes space switching into account when doing a hierarchical sort, but how does a tool writer KNOW that they need to do this?

So lets go back to the bit about rigging frameworks vs auto-riggers.  Well the difference is basically architecture vs construction.  The framework is the environment the rigging code is written within.  When I started writing SB, I focused only on the framework side.  I had a pretty good idea what sort of functionality would be required, so I wrote that first.  Once I was happy with that, I took it out for a test drive by trying to write some actual rigging code using it.  This in turn pointed out some missing features in the framework which in turn caused me to re-write the actual rigging code etc…  This iteration cycle went on for a little bit and eventually out came the current incarnation of SB.

Basically a good auto-rigger should be built upon a good rigging framework.

Thats my brief analysis on the shortcomings of SB.  In general, like I said at the top, I think it has been very successful.  Its made me personally enormously more productive than I would been and it has been an amazingly enabling force for users of the tool as well.  But like I said, analyzing the failures is usually more instructive than analyzing the successes.

This post is public domain

::Coming soon::

October 6th, 2011 by hamish download the zooToolBox

I am still alive! Work is crazy at the moment so I haven’t had time to do much else.  But I have been chipping away at a few things.  I have a couple of posts half written that I will flesh out over the coming month.  And I actually have slowly been chipping away at the re-organization of the toolbox.  It’ll be a much cleaner install and hopefully it’ll be easier to leverage functionality contained within.

Anyway I’ll post more about it when I actually manage to ship it.  For now though, stay tuned.

This post is public domain

::the importance of rig encapsulation::

August 16th, 2011 by hamish download the zooToolBox

Being able to write good animation tools relies on being able to easily make queries about a rig. Animation tools often need a high level understanding about how a rig works for many reasons. But obviously you want to maintain a loose coupling between the two. You want rigging to have the freedom to be able to change the way the rigs work without having to worry about breaking animation tools. Conversely you don’t want animation tools to be hamstrung by the lack of ability to encapsulate the complexity of the rig.

For example, is there a way to query the FK controls from a given IK control and vice-versa? What about pole vector controls? Is there a way to ask which controls have space switching? If so can you query what the spaces are? What about which controls are affected by a given space switch? Given a joint can you get a list of the rig controls that drive it? You get the idea.

Animation tools are basically a layer that build on top of the rig layer. If the rig layer isn’t rock solid, then animation tools will be unstable or feature restricted or both.

Having some sort of programmatic interface to encapsulate the implementation details of your rig features is incredibly important if you want to be able to write useful and robust animation tools. Without this sort of high level rig API you’ll most likely make it difficult or impossible to write the sort of tools that will enable your animators to be more productive.

So if you’re writing a rigging system, try taking a break from it and building some animation tools. Exercise that rigging API you’ve been spending so much time on. Better yet, use all the animation tools you write as part of your unit testing to validate changes made to your rigging API. Remember, as a rigger your customers are both your animators and anyone who might write animation tools.

This post is public domain

::more on OO rigging and animator tools::

July 21st, 2011 by hamish download the zooToolBox

Following on from the previous post I thought I’d talk a bit about how you could implement a tool which would display a bunch of actions that are supported by the currently selected rig parts.

Now there are a bunch of different ways you can do this… This is just one way that seems (to me) like a good combination of rigor and ease of coding.

In Skeleton Builder, each rig part is encapsulated in a class that derives from RigPart.  The next step is to create an interface class which defines two methods – switchToFk and switchToIk.  Our rig part class will inherit from both RigPart and this interface class and will implement these two methods.  Our code ends up looking something like this:

import typeFactories
import baseRigPrimitive
class IkFkSwitchable(object):
  __metaclass__ = typeFactories.interfaceTypeFactory( baseRigPrimitive.RigPart.__metaclass__ )
  def switchToFk( self ):
    '''this method should implement the logic to switch to FK mode'''
    pass
  def switchToIk( self ):
    '''this method should implement the logic to switch to IK mode'''
    pass

class Leg(baseRigPrimitive.RigPart, IkFkSwitchable):
  #the code to implement this rig part goes here
  ...
  def switchToFk( self ):
    #implementation of this method goes below...
    ...
  def switchToIk( self ):
    #implementation of this method goes below...
    ...

As you can see here, the Leg rig part class implements the logic for switchToFk and switchToIk (otherwise an exception gets thrown). Now we can write a simple UI with a “switch to Fk” button and a “switch to Ik” button, something like this:

import rigPrimitives
import maya.cmds as cmd
from baseMelUI import *

def getSelectedSwitchableParts():
  '''
  returns a list of all RigPart instances that have at least one of their members
  selected
  '''
  selectedSwitchableParts = []
  selectedRigParts = rigPrimitives.getPartsFromObjects( cmd.ls( sl=True ) )
  for rigPart in selectedRigParts:
    if isinstance( rigPart, IkFkSwitchable ):
      selectedSwitchableParts.append( rigPart )

  return selectedSwitchableParts

class UserToolLayout(MelHLayout):
  def __init__( self, parent ):
    MelHLayout.__init__( self, parent )
    self.UI_fkButton = MelButton( self, l="switch to FK", c=self.on_pressFk )
    self.UI_ikButton = MelButton( self, l="switch to IK", c=self.on_pressIk )

    #this useful method sets up a scriptjob parented to the uI that triggers the given
    #method when the scene selection changes.  So this will update the UI when the user
    #changes the selection
    self.setSelectionChangeCB( self.on_selectionChange )
    self.on_selectionChange()  #call this to init the UI

    #make sure to call this so the form layout gets setup properly
    self.layout()

  ### EVENT HANDLERS ###
  def on_selectionChange( self, *a ):
    #need to explicitly cast here because of a bug in setEnabled
    selectedSwitchableParts = bool( getSelectedSwitchableParts() )
    self.UI_fkButton.setEnabled( selectedSwitchableParts )
    self.UI_ikButton.setEnabled( selectedSwitchableParts )
  def on_pressFk( self, *a ):
    for rigPart in getSelectedSwitchableParts():
      rigPart.switchToFk()
  def on_pressIk( self, *a ):
    for rigPart in getSelectedSwitchableParts():
      rigPart.switchToIk()

class UserToolWindow(BaseMelWindow):
  WINDOW_NAME = "ikFkSwitcherTool"
  WINDOW_TITLE = "Ik Fk switcher tool"
  DEFAULT_SIZE = 300, 45
  DEFAULT_MENU = None

  def __init__( self ):
    UserToolLayout( self )
    self.show()
    
UserToolWindow()

So this super simple little tool will update itself on selection change. It will let the user know whether the selected rig part can be switched from Fk to Ik or vice-versa.

Obviously you could make this a hell of a lot smarter. For example, you could inspect the rig parts, see which interfaces they implement and display the appropriate UI. You could also do things like have the IkFkSwitchable interface class define a getIkFkMode() method which would return whether the rig part is in Fk or Ik mode. This way you could only enable the appropriate button to make it even more obvious to the user the range of available actions.

Anyway hopefully you get the idea.

This post is public domain

::yay for g+::

July 17th, 2011 by hamish download the zooToolBox

Never managed to get into facebook. Within hours of signing up I had friend requests from all sorts of crazy people that I either barely knew, or knew but certainly wasn’t keen or comfortable sharing various aspects of my life with etc… I’m sure the story is familiar. So it just didn’t take with me.

Anyhoo, g+ seems like its solved all of these problems in a way that makes complete sense. And its google. I manage all my photos with picasa because its just bloody easy. And I LOVE gReader. So anyway, hopefully it’ll be awesome. If you’re not using it, try it out. Look for macaronikazoo!

This post is public domain

::object oriented rigging in Skeleton Builder::

July 17th, 2011 by hamish download the zooToolBox

Skeleton builder is a neat framework for writing rigging code, but its also a useful tool for writing runtime tools as well.  I figured I’d go over an example of this because its not terribly obvious until you actually get in there and write some code. And even then, its not terribly obvious until you read all the code written in baseRigPrimitive…

Writing a tool to do seamless Ik/Fk switching on an arbitrary rig is basically impossible.  After all, your particular limb setup might be a simple biped leg, a 5 jointed spider type leg, or a quadruped leg or any other crazy scenario.  Writing a single function to deal with all these possibilities, especially when you factor in the different ways these rigs could be implemented is basically impossible.

But writing the logic to do the switch for any of them in isolation is generally dead easy.  This is the sort of problem that object oriented programming was invented to solve.  In Skeleton Builder the way I solve these problems is like this.

In Skeleton Builder you write rig primitives. Each rig primitive is written to rig a particular sub-section of a skeleton and the code to do so is implemented in its own class.  So using the above examples I would have 3 classes: BipedLegRig, SpiderLegRig and QuadrupedLegRig.  Now on each one of these classes, lets define a switchToIk() method and a switchToFk() method.  So the switching logic for each rig type can be implemented independently on each of these classes.

Your code will look something like this:

import rigPrimitives

class SpiderLegRig(rigPrimitives.RigPart):
  #this class variable defines the alias' for the controls. controls are accessed using these alias'
  CONTROL_NAMES = 'legControl', 'fkThigh', 'fkKnee', 'fkAnkle'

  def _build( self, skeletonPart, **kw ):
    #the code to build the actual rig goes here
    ...

    #this is the list of nodes that will get connected to the alias' defined
    #in the CONTROL_NAMES class variable
    controls = ikControl, fk0, fk1, fk2
    namedNodes = ()

    return controls, namedNodes
  def switchToIk( self ):

    #this code grabs the actual control nodes based on their alias'
    legControl = self.getControl( 'legControl' )
    fkThigh = self.getControl( 'fkThigh' )
    fkKnee = self.getControl( 'fkKnee' )
    fkAnkle = self.getControl( 'fkAnkle' )

    #logic to switch from Fk to Ik goes below
    ...
  def switchToFk( self ):
    #logic to switch from Ik to Fk goes below
    ...

Then calling this switch method is as simple as doing something like this:

from maya import cmds

selectedControls = cmds.ls( sl=True )
if selectedControls:
  rigPart = rigPrimitives.RigPart.InitFromItem( selectedControls[0] )
  rigPart.switchToFk()

And voila. So now you can write a single UI that lets users switch between Ik and Fk for ANY part of the rig simply by running the above code.

I’ll write up another post with another example of a useful runtime tool that I’ve written that would be very difficult to do without a nice object oriented rigging framework to leverage.

This post is public domain

::dependencies tool::

July 12th, 2011 by hamish download the zooToolBox

I finally managed to package up the dependency tracking tool I blogged about ages ago.  If you want to take a squiz you can find it here.  Its kinda neat actually.  As you can see from the link to the tool – its a zip file.  I made this zip file using one of the features of the tool; the /package flag.  Because the tool knows all the dependencies of all the scripts in your tree, you can ask it to make a zip file containing all the dependencies for a given list of scripts.

So to make the zip file in the link above I ran this command:

pydeps /package pydeps.cmd

And that was it.  Simple eh?  Packaging isn’t terribly useful, but I figured I’ll most likely use this tool to generate future zooToolBox distributions.  I should be able to maintain a list of tools I want to include and pipe them into this command.  And it seemed like a useful thing for anyone who wants to distribute a neat tool without having to manually figure out what they need to include.

You may be wondering about the .cmd extension in the example above.  Well take a look at the zip file.  Basically .cmd files in windows are similar to shell scripts in *nix.  The tool will peek into a .cmd file to see if its a python script and if so, will include them in the dependency database.

So what else can you do with it?  The main features are the /i and the /d flags.  The /i flag will report all import dependencies for the given scripts.  By default it will report only immediate import dependencies, but you can pass it an depth integer as well.  For example if you wanted to know every single import dependency for a script (ie what the imported scripts import etc), you’d simply run this command:

pydeps /i 0 someScript.py

The /d flag will report scripts that are dependent on the ones you specify.  So just say you find some code you want to re-factor.  You can run this command:

pydeps /d 1 someScript.py

This command will report deep dependents for someScript.py.  By this I mean it will report every script that may possibly be using some part of someScript.py.  So for example, just say you import someScript into scriptA and then import scriptA into scriptB.  ScriptB will have access to code in someScript via its scriptA import right?  So now the pyDeps tool will report scriptA as an immediate dependent and scriptB as a deep dependent when run on someScript.

The other flag worth pointing out is the /tree flag.  This will print out a dependency tree for the given scripts.  This can be an interesting exercise – try running it on some of your tools.  I expect you’ll see some cross dependencies that you weren’t expecting.  It’d be kinda neat to do some big fat visualization graph of this…  I did think about this – in fact I figured if I bothered doing it, I’d just use maya’s hypergraph.  Build some nodes to reflect the scripts and connect em up.  If anyone ends up doing this – let me know!

Anyway, there are a few other flags – just run the tool without args to see the available flags.  Enjoy!

This post is public domain

::cleaning house::

July 11th, 2011 by hamish download the zooToolBox

I figured I’d try to clean up the toolbox.  Its basically a horrible mess of crap all in the top level directory.  I’ve wanted to have this done for a long time, but so far my strategy of leaving it to magically fix itself has failed to yield results.  :(

Anyway I wanted to get a little feedback from folks.  Is anyone still using zooCST?

I also might split the project into two – one with old horrible MEL only tools and the other with the shiny new python tools.  The MEL tools aren’t changing anyway so its not like continually including them in releases is helpful.

Thoughts anyone?  Feel free to leave a comment or shoot me email.

This post is public domain