Pole vector match help



Hello everyone, I have this script for matching IK and FK. I can get everything to match perfectly except the pole vector. Any ideas? I can get it to mostly match having a locator on the PV control parent constrained to the elbow joint, but it isn’t always perfect going between the two systems. It has a tendency for the locator to move when swapping to IK.

These are the scripts I’m using:

(expression 1)
//left arm
left_arm_shoulder_parentConstraint1.FK_left_arm_shoulderW1 = left_arm_IKFK_switch.Constraints;
left_arm_elbow_parentConstraint1.FK_left_arm_elbowW1 = left_arm_IKFK_switch.Constraints;
left_arm_forearm_orientConstraint1.FK_left_arm_wristW1 = left_arm_IKFK_switch.Constraints;
left_arm_wrist_parentConstraint1.FK_left_arm_wristW1 = left_arm_IKFK_switch.Constraints;
FK_left_arm_shoulder_control.visibility = left_arm_IKFK_switch.Constraints;

left_arm_shoulder_parentConstraint1.IK_left_arm_shoulderW0 = !left_arm_IKFK_switch.Constraints;
left_arm_elbow_parentConstraint1.IK_left_arm_elbowW0 = !left_arm_IKFK_switch.Constraints;
left_arm_forearm_orientConstraint1.IK_left_arm_wristW0 = !left_arm_IKFK_switch.Constraints;
left_arm_wrist_parentConstraint1.IK_left_arm_wristW0 = !left_arm_IKFK_switch.Constraints;
left_IK_hand_control.visibility = !left_arm_IKFK_switch.Constraints;
left_arm_PV_control.visibility = !left_arm_IKFK_switch.Constraints;

expression 2:
scriptJob -attributeChange “left_arm_IKFK_switch.IKFK” “IKFKMatch()”;

script node:
global proc IKFKMatch()
//left arm
int $switchCheck = getAttr left_arm_IKFK_switch.IKFK;

print("switch is at " + $switchCheck);

if ($switchCheck == 0)
	float $laikXrot = `getAttr left_arm_hand_IK_match_locator.rotateX`;
	float $laikYrot = `getAttr left_arm_hand_IK_match_locator.rotateY`;
	float $laikZrot = `getAttr left_arm_hand_IK_match_locator.rotateZ`;

	float $laikXtrans = `getAttr left_arm_hand_IK_match_locator.translateX`;
	float $laikYtrans = `getAttr left_arm_hand_IK_match_locator.translateY`;
	float $laikZtrans = `getAttr left_arm_hand_IK_match_locator.translateZ`;

	setAttr left_IK_hand_control.rotateX $laikXrot;
	setAttr left_IK_hand_control.rotateY $laikYrot;
	setAttr left_IK_hand_control.rotateZ $laikZrot;

	setAttr left_IK_hand_control.translateX $laikXtrans;
	setAttr left_IK_hand_control.translateY $laikYtrans;
	setAttr left_IK_hand_control.translateZ $laikZtrans;

	float $lapvmatchX = `getAttr left_arm_pv_match_locator.translateX`;
	float $lapvmatchY = `getAttr left_arm_pv_match_locator.translateY`;
	float $lapvmatchZ = `getAttr left_arm_pv_match_locator.translateZ`;

	setAttr left_arm_PV_control.translateX $lapvmatchX;
	setAttr left_arm_PV_control.translateY $lapvmatchY;
	setAttr left_arm_PV_control.translateZ $lapvmatchZ;

	setAttr left_arm_IKFK_switch.constraints 0;
if ($switchCheck == 1)
    float $lashXrot = `getAttr left_arm_shoulder_FK_match_locator.rotateX`;
    float $lashYrot = `getAttr left_arm_shoulder_FK_match_locator.rotateY`;
    float $lashZrot = `getAttr left_arm_shoulder_FK_match_locator.rotateZ`;
    setAttr FK_left_arm_shoulder_control.rotateX $lashXrot;
    setAttr FK_left_arm_shoulder_control.rotateY $lashYrot;
    setAttr FK_left_arm_shoulder_control.rotateZ $lashZrot;
    float $laelXrot = `getAttr left_arm_elbow_FK_match_locator.rotateX`;
    float $laelYrot = `getAttr left_arm_elbow_FK_match_locator.rotateY`;
    float $laelZrot = `getAttr left_arm_elbow_FK_match_locator.rotateZ`;
    setAttr FK_left_arm_elbow_control.rotateX $laelXrot;
    setAttr FK_left_arm_elbow_control.rotateY $laelYrot;
    setAttr FK_left_arm_elbow_control.rotateZ $laelZrot;
    float $lawrXrot = `getAttr left_arm_wrist_FK_match_locator.rotateX`;
    float $lawrYrot = `getAttr left_arm_wrist_FK_match_locator.rotateY`;
    float $lawrZrot = `getAttr left_arm_wrist_FK_match_locator.rotateZ`;
    setAttr FK_left_arm_wrist_control.rotateX $lawrXrot;
    setAttr FK_left_arm_wrist_control.rotateY $lawrYrot;
    setAttr FK_left_arm_wrist_control.rotateZ $lawrZrot;

	setAttr left_arm_IKFK_switch.constraints 1;


  1. Using a script job seems like overkill to me. Maybe a bit “dangerous” in the sense that if each char has one, things can get heavy . . . I avoid them unless they’re necessary.
  2. You’re probably gonna have better luck using math to do this. Relatively simple vector addition, subtraction and scaling (multiplying). If you’re going to be doing stuff like this, you really should know at least that much math. It’s not that hard, I promise :wink: I suppose you could do it with an expression, but you can also use nodes to do it and not have the hassle of the expression syntax. Might be worth figuring it out in expression/mel/python then just converting to nodes.



I am rigging these characters for a school project as if for a video game, so I won’t have more than one character in a scene. The scripts I have were given to me by a teacher.



how does that help me match it with FK controls?


That link covers creating an IK pole vector to match an existing skeleton. To match FK to IK, you basically just copy the rotations across (if the base skeletons are set up the same) or use orientConstraints with offsets (if they are not). Here’s the basic sequence of things that happen when going from FK to IK or vice versa:


Why not get the current world space position of the FK elbow/knee and use it to set the world space position of the pole vector control?


Same reason animators usually pull the vectors out farther: the shorter throw on the elbow will lead to a higher likelihood of flips, depending on the rig and the sampling frequency at which you are matching. The elbow is one of set of valid solutions for a given frame – unless the arm is hyperextended – but you’re increasing the likelihood of a flip if, say, the animator tweaks the torso position or starts removing keys.


the main problem people have with matching and match failing even with good math is bad Joint orient at the elbow - once your orient is clean then matching is no problem http://www.riggingdojo.com/2014/10/03/everything-thought-knew-maya-joint-orient-wrong/