Jul 22 2014

Using Vector Math to Rig an Arm…

Quick example on how to use vector math (mostly) to get the most out of locator based rigging. The following example makes a joint chain and a pole vector locator using 3 positions (Shoulder, elbow, and wrist). All the joint orientations and pole vector position are worked out automatically by the use of some simple subtraction addition and cross multiplication of vectors. In the future, I’m hoping to write a more in-depth explanation of my process. But, in the mean while I hope it helps those diving into auto rigging who might not be so fresh on vector math 🙂
The example is done in Maya, since Maya joints can have much different orientations than those visually displayed in the view-port.
Being that this snippet is in python, we must make use of the mayaAPIs vector and matrix classes which is a departure to the way in which we used to do it, in mel.

Here’s the snippet!
hope you find it useful 🙂

from maya import cmds
import maya.api.OpenMaya as om

def makeIkPlaneSetup(helpers, poleVectorDistance=5.0):
    if len(helpers) != 3:
        raise Exception('makeIkPlaneSetup input error, you need objects to pull positions from there were %s inputs\n' % len(helpers))
   
    
    shld = om.MVector(cmds.xform(helpers[0],q=True,ws=True,t=True))
    elbow = om.MVector(cmds.xform(helpers[1],q=True,ws=True,t=True))
    wrist = om.MVector(cmds.xform(helpers[2],q=True,ws=True,t=True))
    
    #figure out the upNode (plane direction)
    planeX = wrist - shld
    planeXL = planeX.length()

    armDis = (elbow - shld).length()
    foreArmDis = (wrist-elbow).length()
    fraction = armDis/(foreArmDis+armDis)
    planeP = shld + (planeX.normalize() * (planeXL*fraction))
    upNode = (elbow-planeP).normalize()
    
    pvPos = shld + (upNode * poleVectorDistance)
    
    #shoulder orintation matrix
    shdXAxis = (elbow-shld).normalize()
    shdYAxis = (upNode ^ shdXAxis).normalize() #cross product a noramalize....
    shdZAxis = (shdXAxis ^ shdYAxis).normalize() #cross product a noramalize....
  
  
    shldM = om.MMatrix([[shdXAxis.x,shdXAxis.y,shdXAxis.z,0],
                        [shdYAxis.x,shdYAxis.y,shdYAxis.z,0],
                        [shdZAxis.x,shdZAxis.y,shdZAxis.z,0],
                        [shld.x,shld.y,shld.z,1]])
    
    elbowXAxis = (wrist-elbow).normalize()
    elbowYAxis = shdYAxis
    elbowZAxis = (elbowXAxis ^ elbowYAxis).normalize()
    
    elbowM = om.MMatrix([[elbowXAxis.x,elbowXAxis.y,elbowXAxis.z,0],
                         [elbowYAxis.x,elbowYAxis.y,elbowYAxis.z,0],
                         [elbowZAxis.x,elbowZAxis.y,elbowZAxis.z,0],
                         [elbow.x,elbow.y,elbow.z,1]])
    
                     
    wristM = om.MMatrix([[elbowXAxis.x,elbowXAxis.y,elbowXAxis.z,0],
                         [elbowYAxis.x,elbowYAxis.y,elbowYAxis.z,0],
                         [elbowZAxis.x,elbowZAxis.y,elbowZAxis.z,0],
                         [wrist.x,wrist.y,wrist.z,1]])                
    
    pvM = om.MMatrix([[shdXAxis.x,shdXAxis.y,shdXAxis.z,0],
                      [shdYAxis.x,shdYAxis.y,shdYAxis.z,0],
                      [shdZAxis.x,shdZAxis.y,shdZAxis.z,0],
                      [pvPos.x,pvPos.y,pvPos.z,1]]) 
                          
    #convert matrix values to list for xform input 
    shldML = [v for v in shldM]
    elbowML = [v for v in elbowM]
    wristML = [v for v in wristM]
    pvML = [v for v in pvM]
    
    #make pole vector point
    pv = cmds.spaceLocator()
    cmds.select(clear=True) #we'll keep joints parented to avoid rotation offset which maya creates when parenting joints post creation
    
    shldJ = cmds.joint()
    elbowJ = cmds.joint()
    wristJ = cmds.joint()
    
    
    cmds.xform(shldJ,ws=True,m=shldML)
    cmds.xform(elbowJ,ws=True,m=elbowML)
    cmds.xform(wristJ,ws=True,m=wristML)
    cmds.xform(pv,ws=True,m=pvML)
    
 
    
           
    
makeIkPlaneSetup(cmds.ls(sl=True))

 

Leave a Reply