There are plenty of tutorials about how to set up poleVectors, but not all describe what it actually does. Long story short; a poleVector defines two things:
- the plane
- the direction of bending
The underlying concepts apply to any 3D software. Once you understand them, things will make more sense. No matter which program you use. Phenomenons like Maya’s infamous popping joints when creating a poleVector-constraint should make sense after this post.
Why we need poleVectors
An Inverse Kinematics (IK) setup uses a start and end position, to orient your joint chain. “Inverse” because you define the end position you want to reach and the solver calculates the angles to get there.
Opposed to Forward Kinematics (FK), which lets you define the joint angles directly. In that case the final joint simply goes along for the ride and ends up wherever it was carried to.
We will look at a simple three joint IK, for which the solver only has to find the position of the middle joint. The initial restrictions for this system are:
- 2 points in space (start and end point)
- 2 distances (first and second bone length)
Unfortunately there are infinitely many middle joint positions that satisfy these restrictions.
Reducing our options
To get a single solution we need… take a wild guess… a poleVector! This third point defines a unique plane in space, as long as start point, end point and poleVector aren’t in a straight line or on top of each other.
The plane defined by start point, end point, and poleVector control still allows for two solutions: One bends the chain towards the poleVector control, whereas the other bends away.
The solution that is closest to the poleVector is chosen and with that the middle joint unambiguously defined. Yay!
Your guess is better than the software’s guess
Even if you are not explicitly using a poleVector, your 3D software still has to somehow pick one of the infinitely many possible solutions. Under the hood this might be done via a “twist” attribute, which is a more obscure constraint than a poleVector. It’s generally not a good idea to let the program handle this for you, since it has no concept of your rig and might bend your limbs in all kinds of horrific ways 😉
A similar thing happens with joint chains that contain more than 3 joints: The degrees of freedom of all these joints need to be restricted somehow. The computer can make assumptions, but it will always be a guess. Same thing applies: You are probably better off if you can somehow define your joint chains step by step (3 joints at a time), instead of all in one go.
Side-note, for Maya users: Some available IK solvers do not accept a poleVector (for example the SingleChain solver) and purely rely on the twist attribute instead.
Hopefully this gave you a bit of an intuition for poleVectors: It is a point in space, which limits an infinite amount of solutions down to one.
I only talked about the big-picture concept and intentionally skipped over the math. Look for tutorials about these topics, if you are interested:
- The poleVector plane (or rather “coordinate system”) is established by two vectors:
- start joint -> end joint
- start joint -> poleVector ctrl
- Picking between the two possible solutions that lie on the plane can be done with a dot product.
If you’re still here, let’s look at some Maya examples:
Example: poleVector constraint moves joints
When you add a poleVector constraint, your joint chain snaps to the plane defined by the start point, end point and poleVector. You can avoid this popping, by placing the poleVector control on the plane defined by your joint chain. The constraint still snaps the joint chain to the plane defined by the poleVector – it just happens to be the same as the joints lie in.
It doesn’t matter whether your joints are different lengths, at weird angles, etc. It’s all about that plane!
Manually positionion and aligning your poleVector control is tedious, which is why most TDs eventually use a script to do so. This is my quick & dirty code, if you need something to get started:
from maya import cmds from maya.api import OpenMaya def get_pos_as_mvector(node): """Get a transform position as an MVector instance. Args: node (str): Name of transform. Returns: MVector: Position of given transform node. """ pos = cmds.xform(node, query=True, translation=True, worldSpace=True) return OpenMaya.MVector(pos) def place_pole_vector_ctrl(pv_ctrl, start, mid, end, shift_factor=2): """Position and orient the given poleVector control to avoid popping. Args: pv_ctrl (str): Name of transform to be used as poleVector. start (str): Name of start joint. mid (str): Name of mid joint. end (str): Name of end joint. shift_factor (float): How far ctrl should be moved away from mid joint. """ # Find mid-point between start and end joint start_pos = get_pos_as_mvector(start) end_pos = get_pos_as_mvector(end) center_pos = (start_pos + end_pos) / 2 # Use vector from mid-point to mid joint... mid_pos = get_pos_as_mvector(mid) offset = mid_pos - center_pos # ...to place the poleVector control pv_pos = center_pos + offset * shift_factor cmds.xform(pv_ctrl, translation=pv_pos, worldSpace=True) # Orient ctrl so that the XY-plane coincides with plane of joint chain. aim_constraint = cmds.aimConstraint( mid, pv_ctrl, aimVector=(-1, 0, 0), upVector=(0, 1, 0), worldUpType="object", worldUpObject=start, ) cmds.delete(aim_constraint) place_pole_vector_ctrl( start="ik_start_jnt", mid="ik_mid_jnt", end="ik_end_jnt", pv_ctrl="poleVector_ctrl", shift_factor=2, )
Example: Change bend direction
Most programs allow you to offset the orientation of the poleVector freely (“Pole Angle” in Blender, “Twist” in Maya). For the sake of a little exercise let’s look at the Maya node graph for another way to flip the bend direction:
That vector going into the “Pole Vector” plug of the IK constraint looks mighty interesting! I wonder whether we can just reverse its direction…
And indeed, the bend direction is flipped when we reverse the “Constraint Translate” plug by multiplying with a vector (-1, -1, -1).
Definitely not the best way to flip the direction, since it requires an unnecessary extra node. Use a twist angle of 180 degrees instead.
I hope this post helped to build an intuition for poleVectors and demystified them a bit. Let me know if you have questions, so I can refine this post for any future visitor.
Thanks to these fine folks for pointing out shortcomings in this post: