Maya Python: How do I parent these FK controls hierarchically?

125 views Asked by At

I've been trying to get this code to run based off what I found at this forum: https://discourse.techart.online/t/maya-python-fk-controls-generator-parenting-issue/5395

The first list I commented out kindof works, but it has a finite number of times it can work. What I'm trying to do is have this script not just create the fk controls (Which it does fine) I want it to also parent the controls under eachother based on selected order.

To run it is simple, simply create a joint chain, select whatever joints you want, paste the script in an empty python tab and hit enter. It'll create the controls, but it wont parent them properly. I put the script below for anyone who wants to take a crack at it:

import maya.cmds as cmds

#create variable for the selected joints
selected = cmds.ls(sl=True)

#clears the selection
cmds.select(cl=True)

#create empty list for the new controls
CL = []




#parent = None
#for the joints in selection, run the following code
for s in selected:

    #create variable for the position/rotation of the joints
    pos = cmds.xform(s, q=True, t=True, ws=True)
    rot = cmds.xform(s, q=True, rotation=True, ws=True)

    #create 3lvl controls and position them on top of joints
    ctrl = cmds.circle(n=str(s + '_ctrl'), radius=0.6,nr=(1,0,0), ch=False) 
    cmds.group(n=str(s + '_sdk'))
    offset = cmds.group(n=str(s + '_offset'))

    #snap the controls to the position of the joint
    cmds.xform(offset, translation=pos, ws=True)
    cmds.xform(offset, rotation=rot, ws=True)

    #parent constraint joints to ctrls
    cmds.parentConstraint(ctrl, s)

    #append offset nodes to CL
    CL.append(offset)
    
    #offsets = [selected[0]+ '_ctrl_offset',selected[1]+ '_ctrl_offset',selected[2]+ '_ctrl_offset',selected[3]+ '_ctrl_offset',selected[4]+ '_ctrl_offset']
    #controls = [selected[0]+ '_ctrl',selected[1]+ '_ctrl',selected[2]+ '_ctrl',selected[3]+ '_ctrl',selected[4]+ '_ctrl']
    
#I know a zip loop works, I just dont how to write it properly to get it to parent hierarchically with these variable lists
    offsets = [str(s + '_offset')]
    controls = [str(s + '_ctrl')]
    
    
    
    for offset, control in zip(offsets, controls[-1:]):
      cmds.parent(control, offset)
1

There are 1 answers

2
CLR On BEST ANSWER

Ideally, your code should not rely on selection order (read on for details).

There are two ways of fixing this issue; a robust method and an easy but unreliable method.

The robust method requires that you sort your selected joints based on hierarchy before generating controllers. This will guarantee that when you generate the controller, it will be parented correctly (assuming the chain selected is a single contiguous chain of joints). There are several means to that goal. Here's a post on how to do this: https://discourse.techart.online/t/sorting-objects-in-a-list-by-heirarchy/11625

The easy (and less reliable) method is to modify the preferences. I believe out of the box Maya stores selections in arbitrary order. Check the Preferences->Settings->Selection->Track selection order. Check that box and then your current code should work with a slight modification (you were on to a correct solution):

offset_parent = None  # your code showed this so you were almost there
for s in selected:

    #create variable for the position/rotation of the joints
    pos = cmds.xform(s, q=True, t=True, ws=True)
    rot = cmds.xform(s, q=True, rotation=True, ws=True)

    #create 3lvl controls and position them on top of joints
    ctrl = cmds.circle(n=str(s + '_ctrl'), radius=0.6,nr=(1,0,0), ch=False) 
    cmds.group(n=str(s + '_sdk'))
    offset = cmds.group(n=str(s + '_offset'))

    #snap the controls to the position of the joint
    cmds.xform(offset, translation=pos, ws=True)
    cmds.xform(offset, rotation=rot, ws=True)

    #parent constraint joints to ctrls
    cmds.parentConstraint(ctrl, s)

    #append offset nodes to CL
    CL.append(offset)

    cmds.parent(ctrl, offset)
    # if offset_parent is None, you're first time in (assuming the base ctrl is not parented and order starts at base and moves towards leaf of chain)
    if offset_parent is not None:
        cmds.parent(offset, offset_parent)
    # now set parent to be this offset node for next iteration
    offset_parent = offset

enter image description here