Search code examples
pythonmaya

Maya Python: Match Curve CVs to Joint Positions in chain?


So I discovered one brilliant way to find a good place to place an elbow ik control for a pole vector. The idea is you create a three point cv curve, snap the cvs to the shoulder, elbow, and wrist respectively, select the elbow cv, then switch your move tool's Axis Orientation to normal and move it behind the elbow. I opted instead to have a script that does that all for me.

My initial plan of action was to use a group of variables that gets the translates of any three joints in a chain you select, it would then copy the translates of each joint in the chain to the cvs of the poleVecCRV and snap each part of the joint to their respective position, then move the center CV behind the joint chain.

Instead I get errors saying "Error reading data element number 1: [(5.552068394583248, -3.418543359042418e-16, -4.440892098500626e-16)]"

As always, any help is appreciated:

import maya.cmds as cmds

if cmds.window("buildWin", exists =True):
    cmds.deleteUI("buildWin", window = True)

myWindow = cmds.window("buildWin",t='DS_pvFinder',rtf=1,w=100, h=100, toolbox=True)
column = cmds.columnLayout(adj=True)

def gui(*args):
    cmds.columnLayout()
    cmds.button(label='build placement curve',c=matchJNT)
    cmds.showWindow(myWindow)

def matchJNT(*args):

    root = cmds.ls(sl=True)[0]
    child = cmds.listRelatives(root,ad=1,type='joint')
    child.append(root)
    child.reverse()
    limbJnt = child

    sldrJntPos = cmds.getAttr(child[0]+'.translate')
    elbwJntPos = cmds.getAttr(child[1]+'.translate')
    wrstJntPos = cmds.getAttr(child[2]+'.translate')

    poleVecCRV = cmds.curve(d=1,p=[(0,1,0),(0,2,0),(0,3,0)])

    #move placement curve for ik control
    cmds.move(poleVecCRV+'.cv[0]', sldrJntPos)
    cmds.move(poleVecCRV+'.cv[1]', elbwJntPos)
    cmds.move(poleVecCRV+'.cv[2]', wrstJntPos)

    #move curve behind elblow with normal axis orientation
    cmds.moveVertexAlongDirection(poleVecCRV+'.cv[1]',n=[5,0,0])

    cmds.setAttr(poleVecCRV + '.dispEP',1)

The script should snap the curve's three cvs to three of any selected joint chain, then move the center one back in a normal axis orientation.

Thank you


Solution

  • Let's print out one of the translate values cmds.getAttr(child[0]+'.translate'):

    [(-1.46044102058298, 0.0, 11.480993930263558)]

    Notice that it's a tuple inside of a list? So you need to grab the result like this: sldrJntPos = cmds.getAttr(child[0]+'.translate')[0].

    But this still doesn't work the way you're trying with cmds.move. You can't just pass the list as it is, but instead pass the values individually: cmds.move(sldrJntPos[0], sldrJntPos[1], sldrJntPos[2], poleVecCRV+'.cv[0]')

    But there's still an issue with what it's doing overall, because once it's done you'll notice none of the cvs are aligned to the joints (unless they're parent is world origin). Right now you're grabbing the objects' local translation, but you need their world translation. Instead, you can use cmds.xform(shoulder, q=True, ws=True, t=True) which will return the position in world coordinates.

    One last issue is with moveVertexAlongDirection. Right now you're using n=[5,0,0], but this causes it to error. The length of that parameter's list should match the number of cvs you're moving, in this case one: n=[5].