::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'''
  def switchToIk( self ):
    '''this method should implement the logic to switch to IK mode'''

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

  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():
  def on_pressIk( self, *a ):
    for rigPart in getSelectedSwitchableParts():

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

  def __init__( self ):
    UserToolLayout( self )

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

This entry was posted on Thursday, July 21st, 2011 at 14:47 and is filed under main. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.