Maya PoleVector Placement MEL

Hey guys I just watched a video on how to place your polevector to avoid any popping and I was wondering what steps it takes to make the script work in mel

from maya import cmds , OpenMaya
import math

sel = cmds.ls(sl = 1)

start = cmds.xform(sel[0] ,q= 1 ,ws = 1,t =1 )
mid = cmds.xform(sel[1] ,q= 1 ,ws = 1,t =1 )
end = cmds.xform(sel[2] ,q= 1 ,ws = 1,t =1 )

startV = OpenMaya.MVector(start[0] ,start[1],start[2])
midV = OpenMaya.MVector(mid[0] ,mid[1],mid[2])
endV = OpenMaya.MVector(end[0] ,end[1],end[2])

startEnd = endV - startV
startMid = midV - startV

dotP = startMid * startEnd
proj = float(dotP) / float(startEnd.length())
startEndN = startEnd.normal()
projV = startEndN * proj

arrowV = startMid - projV
arrowV*= 0.5
finalV = arrowV + midV

cross1 = startEnd ^ startMid
cross1.normalize()

cross2 = cross1 ^ arrowV
cross2.normalize()
arrowV.normalize()

matrixV = [arrowV.x , arrowV.y , arrowV.z , 0 ,
cross1.x ,cross1.y , cross1.z , 0 ,
cross2.x , cross2.y , cross2.z , 0,
0,0,0,1]

matrixM = OpenMaya.MMatrix()

OpenMaya.MScriptUtil.createMatrixFromList(matrixV , matrixM)

matrixFn = OpenMaya.MTransformationMatrix(matrixM)

rot = matrixFn.eulerRotation()

loc = cmds.spaceLocator()[0]
cmds.xform(loc , ws =1 , t= (finalV.x , finalV.y ,finalV.z))

cmds.xform ( loc , ws = 1 , rotation = ((rot.x/math.pi*180.0),
(rot.y/math.pi*180.0),
(rot.z/math.pi*180.0)))

This is from Marco Giordano

and is pretty great, however I want to try making this is Mel, but don’t know how certain command work. I might be over thinking it and this might be very simple but If you guys could give an explanation or a method to get similar results with a offset ability would be greatly appreciated

Most of what I’m confused

Is the OpenMaya stuff. It seems i can’t find it in the autodesk technical documentation, but I can find it in the API. Is there any possible way for them to be used in Mel? Thanks for your time and in advance!

No you can’t call OpenMaya stuff from MEL. That’s one of the advantages of python. However, it is possible to do that math in MEL if you’re really determined to rewrite it without using python. It’s all just vector math so if you understand what he is doing already then it shouldn’t be too hard to convert. The one thing he does that I don’t know of an easy equivalent in MEL is where he converts the matrix to euler angles but that’s not necessary anyway as you can just set the matrix via xform without doing that.

These are the things you’ll most likely need to use to do it in MEL:
the vector type
cross product
dot product
magnitude of a vector
normalise a vector

With MEL’s vector type you can use the + and - operators as you’d expect as well as the * and / operators to multiply or divide by a float.

… or you could just learn python instead :stuck_out_tongue: Most people are converting scripts in the opposite direction between those languages these days.

This method is roughly equivalent to:

  1. create a locator point constrained to the first and last joints of a chain
  2. aim-constrain the locator so that it looks at the middle joint of the chain with it’s up vector pointing at the start of the chain
  3. any point on the plane defined by the look-at and up vectors of that constrain is valid, usually along the vector from the locator to the mid point.
  4. create the control, parent it to the first locator, and set it’s local position to a position on the solution plane - that is , the look-at and up axes of the locator. zero out the control’s position in the axis which is neither the look-at nor the up axis of the first locator.

You can do all of that in Mel w/o a lot of hand done math…

But learn python anyway. Boo mel.

Yup, that’s true the constraints can do a lot of the math for you so that’s the easier option. The math is still good to know though :wink:

I usually don’t take the time to do the maths since the IK Solver already does all the calculations for you! If you already have an IK Handle on top of your bone chain, the proper trajectory is already calculated in the “poleVector” channel.

Create your pole-vector object and place it on top of the first bone of the chain ( the value from the poleVector channel is a vector relative to the root of the IK Handle i.e: the first bone. ) Then add the vector from that channel to your object’s current position. The object will now be perfectly aligned with the rotate plane and a constraint won’t make your chain pop. The vector being very short though, you might want to multiply it in order to place your node further away from the chain. After that, apply the constraint.

That’s all you have to do if I remember properly. I can give you an example in python later on if you need it. I haven’t played in Maya for a while so this procedure might be off a bit.

Hmmm I think I found another solution but im not sure if it works or not. I was simply parenting a locator to the elbow joint then zeroing out the rotation and translation. Then using the axis which best represents the pole vector location and moving the locator to the final position. Unparent the locator and create a pole vector. In addition pgz I’m not sure what you mean by the pole vector channel. I did follow your directions however I ended up with a locator that was still next to the shoulder. I was hoping you could clarify a bit more. Also thank you guys for all the reply’s this is great!

That method is close sometimes, but it depends on the way the joints are set up - if you have an oddly rotated middle joint (or a 3+ bone chain that is not a plane) it won’t work.

Sorry for the late follow up. Here’s some explanations followed by an example. You may know most, if not all of that stuff already but please bear with me.

You can consider the IKHandle’s rotate plane as what it says it is: an actual plane! You need two vectors to “draw” that plane. The first vector points towards the end effector. The second vector is stored in the poleVector channel on the IKHandle node. Remember that the origin of these vectors is the IKHandle’s root ( the first joint ) not the origin of the scene.

When you first apply an IKHandle on a joint chain, the solver already calculates its proper rotate plane and stores the second vector for free in that channel. We are lucky, because we have direct access to that vector. No need to look at the joint chain at all in order to find it! Which means that if you place an object at that exact location and apply a poleVector constraint with it, because it is perfectly aligned with the plane, there will be no “pop.” Applying the constraint simply overrides that channel with the location of your node in relation to the IKHandle’s root. ( After applying the constraint on the IKHandle, you will notice that the poleVector channel turns blue like for any other constraint )

If you ended up with a locator that was VERY close to the first joint, it was probably right! Constraining that locator would result in a perfect pole vector. The only problem is where it is located in respect to the joint chain. It is very inconvenient! All you have to do then is move it away from the chain.

Now, if you apply an aimConstraint on that locator, aim it towards the first joint and use the endEffector as an upVector, it should allow you to move it away safely. However exotic your joint chain may be, it will work since the locator will be sitting on that “plane.”

Here is a complete example of what I am talking about ( including the positioning! I guess I was missing MEL a bit XD ):

global proc createPoleVector(string $ik)
{
	// Get the first joint and the end effector.
	string $firstJnt[] = `listConnections ($ik + ".startJoint")`;
	string $endEff[] = `listConnections ($ik + ".endEffector")`;
	
	// The location of the first joint is the origin of the pole vector.
	vector $rootPos = `xform -query -worldSpace -translation $firstJnt[0]`;
	
	// Add the pole vector to it.
	vector $polePos = `getAttr ($ik + ".poleVector")`;
	vector $targetPos = $rootPos + $polePos;
	
	// Create the poleVector node and place it along the rotate plane.
	string $poleVector[] = `spaceLocator -name "the_poleVector"`;
	xform -translation ($targetPos.x) ($targetPos.y) ($targetPos.z) $poleVector[0];
	
	// The new node is too close the the chain to be useful for an artist. 
	// Orient it so you can move it some place else.
	delete `aimConstraint -aimVector 1 0 0 -upVector 0 1 0 -worldUpType "object" -worldUpObject $endEff[0] $firstJnt[0] $poleVector[0]`;
	
	// To place it properly, I usually move it to the middle of the chain and then offset it by
	// about half of the "chain length" away from it. It is usually a reasonable distance, however weird the chain may be.
	// First get the middle of the chain.
	vector $effPos = `xform -query -worldSpace -translation $endEff[0]`;
	float $middle = ( `mag ($rootPos - $effPos)` * 0.5 );
	
	// Then get the chain length.
	float $length = 0.0;
	
	string $endJnt[] = `listConnections -destination 0 $endEff[0]`;
	
	string $currentJnt = $endJnt[0];
	while (true)
	{
		string $nextJnt[] = `listRelatives -parent $currentJnt`;
		
		vector $posA = `xform -query -worldSpace -translation $currentJnt`;
		vector $posB = `xform -query -worldSpace -translation $nextJnt[0]`;
		
		$length += `mag ($posA - $posB)`;
		
		if ($nextJnt[0] == $firstJnt[0])
			break;
		else
			$currentJnt = $nextJnt[0];
	}
	
	// Now move that pole vector to a more decent place!
	xform -relative -objectSpace -translation ( $length * -0.5 ) $middle 0 $poleVector[0];
	
	// Finally, apply that poleVector constraint.
	poleVectorConstraint $poleVector[0] $ik;
	
}

global proc string[] test()
{
	joint -p -5.9  0.0  3.8 ;
	joint -p -5.2  1.1 -1.0 ;
	joint -e -zso -oj xyz -sao yup joint1;
	joint -p  0.3 -2.2  2.2 ;
	joint -e -zso -oj xyz -sao yup joint2;
	joint -p  1.8  0.4 -1.3 ;
	joint -e -zso -oj xyz -sao yup joint3;
	joint -p  3.8  1.3  6.2 ;
	joint -e -zso -oj xyz -sao yup joint4;
	
	return `ikHandle -solver "ikRPsolver" -startJoint "joint1" -endEffector "joint5"`;
	
}

// Run the test first. Look at the chain.
string $ik[] = test();

// Give it a pole vector!
createPoleVector( $ik[0] );

This function should work on any chain. Even though it is less bad-ass than a pure math approach, it is simple and it uses the information that is already available in the scene.
I hope it better answers your question now. :slight_smile:

G