Smooth Enum Space Switching with “AB Space” (working title)
As far as I’ve known during my time in rigging/animation, there have been two widely used methods of control for multi-space switching. Either you have an enum attribute with all the spaces or float attributes between two spaces, as more typically seen in IK FK switches, but sometimes with space switching as well.
Enum Attributes:
The Good- Easy and clean, expandable, current space is always clear
The Bad- Works like integers under the hood, so no smooth interpolation. So switching isn’t practical unless paired with a matching script. Even if Maya were to change somehow behave a bit more like floats between values, it’s not like blending between 2 and 5 would be direct.
Float Attributes:
The Good- You can switch over a few frames or blend spaces rather than necessarily relying on matching scripts, making the whole thing a bit more lightweight and portable.
The Bad- This setup is typically confined to switching between two spaces (world space vs parent space, or something like that) with the only way of expanding typically being either adding more float attributes that sort of daisy chain and have a priority order or constraint-switch to another controller that in turn has more float or enum attributes.
—
Animator preference (and in turn, the rigging tools) at Insomniac is to use the float attributes largely because of the smooth interpolation. That being said, I’ve personally never been a fan of that setup largely because that sort of ties our hands for controllers where we’d like the give the animators more options without making a messy attribute-filled controller. So I’ve been tinkering with a C option.
A Quick Aside
The lookDevKit plugin that’s been shipping with the last few Maya versions is quickly becoming one of my favorites with its set of super useful utility nodes (god I’m such a nerd)
The one I’ve been using the most is floatMath because it conveniently combines a lot of operations in to one node, so one doesn’t have to deal with all the different nodes in the standard Maya set with their accompanying different behaviors and attribute naming conventions. So in general, the one stop-shop is my preference. Plus I feel less wasteful when I’m using them for my typical use of calculating single numbers where most of the old math nodes are designed for color and therefore you have to switch between having xyz or rgb attributes or different naming patterns (again, that slightly different behavior can cause confusion and consternation, at least for me)
In the cases were vectors/3 floats are needed, for most of these nodes, there are color variants, and occasionally they also have alpha attributes as well so you can maybe sneak in a forth attribute if needed. I dunno, I haven’t messed with those, but I’m assuming it would work though it may clamp values.
In any case, there are a lot of other useful nodes in the kit. You should check it out. Now that’s enough with the evangelizing. Back to the subject at hand
Enums or Floats

(Photo credit goes to theporkchopexpress on deviantart)
To try and get around the issue of getting the advantages of both floats and enums, I started playing around with a new scheme where there are two sets of enums for an “A Space” and a “B Space” with a float to blend between the two.
(This video was too long to convert to a GIF, and I’m too tired to recapture)
This setup uses floatLogic nodes (from the lookDevKit, though for people with older Maya builds, I think condition nodes would also work) and floatComposite set to mix mode (though blendTwoAttr would work, in fact, until I almost had finished writing this post, I was using blendTwoAttr, but realized I could use composite) to create a switchboard of sorts for connecting to constraint weights.
For each of the target nodes in the Enum, You’ll need 2 floatLogic nodes and a blendTwoAttr to output to the weight attributes on the parent (or whatever else) constraint.
The floatLogic nodes for A or B space are set to output a bool for True if the enum attributes are set to the same index as the parent constraint target. The out bools are hooked up to the blendTwoAttr and blended between a space or b space by the followB float attribute. That way, it’s all set to 0 except for the chosen values for A and B space, which are set to 0 or 1 depending on which space is set using the followB attribute.
One could potentially pack down the floatComposite nodes in multiples of 3 using colorComposite nodes, but I tend to prefer sticking to 1 dimensional nodes when possible and just making more of them when dealing with 1 dimensional attributes for readability purposes. To each their own though. Just saying it is possible to use the color nodes instead for that bit (using color logic instead for packing won’t work though since it compares all 3 attributes)
Here’s a quick script I hastily recreated because I’m away from my usual computer(s) because I’m on vacation in Morocco /humble-brag
import pymel.core as pm sel = pm.selected() controller = sel[-1] targets = sel[:len(sel)-1] # This setup presupposes a parent group for the controller to be constrained const = pm.parentConstraint([targets, controller.getParent()], mo=True) # or whatever else constraint controller.addAttr('Space Switching', keyable=True, lock=True) controller.addAttr('aSpace', at='enum', enum=[target.nodeName() for target in targets], keyable=True) controller.addAttr('bSpace', at='enum', enum=[target.nodeName() for target in targets], keyable=True) controller.addAttr('followB', at='double', min=0, max=1, keyable=True) if not pm.pluginInfo('lookdevKit.mll', q=True, isLoaded=True): pm.loadPlugin('lookdevKit.mll', force=True) for i, target in enumerate(targets): aspace_logic = pm.createNode('floatLogic', n='{}_aSpace_following_{}_equals'.format(controller, target)) bSpace_logic = pm.createNode('floatLogic', n='{}_bSpace_following_{}_equals'.format(controller, target)) blend = pm.createNode('floatComposite', n='{}_{}_blend'.format(controller, target)) # Set the constants aspace_logic.floatB.set(i) bSpace_logic.floatB.set(i) blend.operation.set(2) # mix # Make the connections controller.aSpace.connect(aspace_logic.floatA) controller.bSpace.connect(bSpace_logic.floatA) aspace_logic.outBool.connect(blend.floatA) bSpace_logic.outBool.connect(blend.floatB) controller.followB.connect(blend.factor) blend.outFloat.connect(filter(lambda x: x.endswith('W{}'.format(i)), const.listAttr(userDefined=True))[-1])
So I just thought I’d share this to see what people think about it because I haven’t really seen it done this way before. Plus to be honest, I’m not nuts about the attribute names for switching as far as clarity for animators goes. That’s actually the other reason I’m writing this post, to maybe crowdsource some better name ideas, so feel free to mention any ideas you might have if something comes to mind while reading, even if just for the setup itself (I’ve just been calling it AB Space, but am not wedded to it)
Anyways, let me know what you think, if you’d maybe like a more tutorialized post about the setup if the way it works isn’t clear enough, or if you spot any ways the setup could be a bit less node-heavy or as mentioned before if you have any bright ideas on attribute or setup naming.
very nice sir, thank you!