Beispiel #1
0
def build( root, fingerDict, side='rt', cleanUp=1 ):
    '''
    Builds an fk hand with extendable knuckles
    
    Args:
        root - node at the location of the wrist
        fingerDict - dictionary with keys for the name of each digit and values which are the root node for each digit:
            e.g. { 'thumb':'lf_thumb1_defJnt', 'index':'lf_index1_defJnt' }
            
            For each key in fingerDict a digit will be created with segments based on the number of child joints in the chain.
            
            Any joints with the same worldSpace location as their child will become 'extend' joints
    
    '''
    # Validate arguments
    if type(root) != type('hello') and type(root) != type(u'hello'):
        return showDialog( 'Argument Error', 'You must supply a root of type string or unicode' )
    
    if type(fingerDict) != type({}):
        return showDialog( 'Argument Error', "fingerDict must be supplied as a dictionary/nwith a key for the name of each digit and a root node as its value/n e.g.{ 'thumb':'lf_thumb1_defJnt', 'index':'lf_index1_defJnt' }")
    
    # Build and align root groups
    xformGrp = cmds.group(empty=1)
    xformGrp = cmds.rename(xformGrp, common.getName( node=xformGrp, side=side, rigPart='hand', function='xform', nodeType='grp'))
    common.align(node=xformGrp, target=root)
    
    rigGrp = cmds.duplicate(xformGrp)
    rigGrp = cmds.rename(rigGrp, common.getName( node=rigGrp, side=side, rigPart='hand', function='rig', nodeType='grp'))
    cmds.parent( rigGrp, xformGrp )
    
    # Root joint
    cmds.select(None)
    rootJnt = cmds.joint()
    rootJnt = cmds.rename(rootJnt, common.getName( node=rootJnt, side=side, rigPart='hand', function='root', nodeType='jnt'))
    common.align(rootJnt, xformGrp)
    cmds.parent(rootJnt, rigGrp)
    cmds.setAttr('%s.jointOrient' % rootJnt, 0, 0, 0 )
    
    # Build fingers
    for key in fingerDict.keys():
        fing = buildFinger( side=side, name=key, rootJnt=fingerDict[key], rootGrp=xformGrp, cleanUp=cleanUp )
        cmds.parent(fing['jnts'][0], rigGrp)
        
    # Cleanup
    if cleanUp:
        cmds.setAttr( '%s.visibility' % rigGrp, 0 )
        common.attrCtrl(nodeList=[rigGrp], attrList=['visibility'])
        
    return {'systemGrp':xformGrp}
Beispiel #2
0
def buildFinger( side, name, rootJnt, rootGrp, cleanUp ):
    # Get aim axis - this presumes the rootJnt is NOT an extend joint
    childJnt = cmds.listRelatives( rootJnt, c=1, type='joint' )[0]
    childPos = cmds.getAttr('%s.t' % childJnt)[0]
    childPosAbs = [ math.fabs(value) for value in childPos ]
    twistIndex = childPosAbs.index(max(childPosAbs))
    twistAxis = ['x', 'y', 'z'][ twistIndex ]
    
    # Determine whether the joints have a negative translation along the twist axis
    neg = False
    if childPos[ twistIndex ] < 0.0:
        neg = True
    
    # Duplicate joint chain
    dupJnts = cmds.duplicate( rootJnt, rc=1 )
    print dupJnts
    jnts=[]
    ctrls = []
    index=1
    for d in range(len(dupJnts)):
        if isExtendJnt(dupJnts[d]):
            j = cmds.rename(dupJnts[d], common.getName( node=dupJnts[d], side=side, rigPart='hand', function='%sExtend%s' % ( name, index ), nodeType='jnt'))
            grp = common.insertGroup( node=j )
            grp = cmds.rename( grp, j.replace('jnt', 'grp') )
            # Connect twistAxis translate to ctrl and ctrl rotatePivotTrnaslate back to ctrl.translate
            cmds.connectAttr('%s.t%s' % (ctrls[index-2], twistAxis), '%s.t%s' % ( j, twistAxis ) )
            rotPivTransUC = cmds.createNode('unitConversion')
            rotPivTransUC = cmds.rename(rotPivTransUC, common.getName( node=rotPivTransUC, side=side, rigPart='hand', function='%sNegTrans%s' % ( name, index ), nodeType='conv'))
            cmds.setAttr( '%s.conversionFactor' % rotPivTransUC, -1.0 )
            cmds.connectAttr( '%s.t' % ctrls[index-2], '%s.input' % rotPivTransUC )
            cmds.connectAttr( '%s.output' % rotPivTransUC, '%s.rotatePivotTranslate' % ctrls[index-2] )
        else:
            j = cmds.rename(dupJnts[d], common.getName( node=dupJnts[d], side=side, rigPart='hand', function='%s%s' % ( name, index ), nodeType='jnt'))
            
            if d < (len(dupJnts)-1):
                # Build control
                c = controls.Control( side=side, rigPart="hand", function='%s%s' % ( name, index ), nodeType="ctrl", size=0.15, color=side, aimAxis=twistAxis, flip=neg )
                c.pinCtrl()
                grp = common.insertGroup( node=c.control )
                grp = cmds.rename( grp, c.control.replace('ctrl', 'grp') )
                common.align( node=grp, target=j )
                if d == 0:
                    cmds.parent( grp, rootGrp )
                    cmds.parent( j, rootGrp )
                else:
                    cmds.parent(grp, ctrls[index-2])
                    cmds.pointConstraint(j, grp)
                ctrls.append(c.control)
                
                # Connect joint rotations to ctrl rotations
                cmds.connectAttr('%s.r' % c.control, '%s.r' % j)
                
            index = index + 1
            
        jnts.append( j )
        
        if cleanUp:
            lockAxes = ['t%s' % axis for axis in ['x', 'y', 'z'] if not axis == twistAxis]
            attrList=lockAxes + ['sx', 'sy', 'sz', 'visibility']
            for c in ctrls:
                common.attrCtrl(nodeList=[c], attrList=attrList)
            #common.attrCtrl(nodeList=[ctrls[-1]], attrList='t%s' % twistAxis) 
        
    return {'jnts':jnts, 'ctrls':ctrls}
Beispiel #3
0
def build(
    hips=None, chest=None, head=None, numSpineJoints=6, numHeadJoints=6, twistAxis="x", bendAxis="y", cleanUp=True
):
    """
    function to create the fk spine with head isolation...
    
    requires 3 objects to be selected or supplied - hips, chest, head
    
    hips: location of the first spine joint - this joint doesn't inherit any chest rotation
    chest: where the chest ctrl is placed. It's rotation is distributed from the second spine joint up to this point
    head: location of the last spine joint

    """

    axisDict = {"x": [1, 0, 0], "y": [0, 1, 0], "z": [0, 0, 1]}

    # Validate that the correct arguments have been supplied
    if not hips or not chest or not head:
        # If hips, chest anf head aren't explicitly supplied, check for a valid selection to use
        sel = cmds.ls(sl=1, type="transform")
        if len(sel) == 3:
            hips, chest, head = sel[0], sel[1], sel[2]
        else:
            return showDialog("Argument Error", "Cannot determine hips, chest and head points")

    # Get positions of spine and head joints
    spineLocs = common.pointsAlongVector(start=hips, end=chest, divisions=numSpineJoints - 1)
    headLocs = common.pointsAlongVector(start=chest, end=head, divisions=numHeadJoints - 1)
    spineLocs.extend(headLocs[1:])

    xformGrp = cmds.group(empty=1)
    xformGrp = cmds.rename(
        xformGrp, common.getName(node=xformGrp, side="cn", rigPart="spine", function="xform", nodeType="grp")
    )
    common.align(node=xformGrp, target=hips)
    aimConst = cmds.aimConstraint(
        chest, xformGrp, aimVector=axisDict[twistAxis], upVector=axisDict[bendAxis], worldUpVector=[1, 0, 0]
    )
    cmds.delete(aimConst)

    # Build control objects
    hipCtrl = controls.Control(
        side="cn", rigPart="spine", function="hips", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    hipCtrl.circleCtrl()
    hipGrp = common.insertGroup(node=hipCtrl.control)
    hipGrp = cmds.rename(hipGrp, hipCtrl.control.replace("ctrl", "grp"))
    common.align(node=hipGrp, target=xformGrp)
    cmds.parent(hipGrp, xformGrp)

    chestCtrl = controls.Control(
        side="cn", rigPart="spine", function="chest", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    chestCtrl.circleCtrl()
    chestGrp = common.insertGroup(node=chestCtrl.control)
    chestGrp = cmds.rename(chestGrp, chestCtrl.control.replace("ctrl", "grp"))
    common.align(node=chestGrp, orient=False, target=chest)
    common.align(node=chestGrp, translate=False, target=xformGrp)
    cmds.parent(chestGrp, hipCtrl.control)

    headCtrl = controls.Control(
        side="cn", rigPart="spine", function="head", nodeType="ctrl", size=1.25, color="green", aimAxis="twistAxis"
    )
    headCtrl.crownCtrl()
    headGrp = common.insertGroup(node=headCtrl.control)
    headGrp = cmds.rename(headGrp, headCtrl.control.replace("ctrl", "grp"))
    common.align(node=headGrp, target=head, orient=False)
    common.align(node=headGrp, target=xformGrp, translate=False)
    cmds.parent(headGrp, xformGrp)

    # Add attr to head ctrl for isolating head rotation
    cmds.addAttr(headCtrl.control, longName="isolate_rotation", at="double", keyable=True, min=0, max=1)

    # Build driven groups
    spineGrps = []
    for i in range(len(spineLocs)):
        g = cmds.group(empty=1)
        g = cmds.rename(
            g, common.getName(node=g, side="cn", rigPart="spine", function="driven%s" % str(i + 1), nodeType="grp")
        )
        spineGrps.append(g)
        cmds.setAttr("%s.t" % g, spineLocs[i][0], spineLocs[i][1], spineLocs[i][2])
        common.align(node=g, target=xformGrp, translate=False)
        if i > 0:
            cmds.parent(g, spineGrps[i - 1])
        else:
            cmds.parent(g, xformGrp)
            cmds.parentConstraint(hipCtrl.control, g)

    # Build joints
    spineJoints = []
    for i in range(len(spineLocs)):
        cmds.select(spineGrps[i])
        j = cmds.joint()
        common.align(node=j, target=xformGrp, translate=False)
        cmds.setAttr("%s.jointOrient" % j)
        j = cmds.rename(
            j, common.getName(node=j, side="cn", rigPart="spine", function="driven%s" % str(i + 1), nodeType="jnt")
        )
        spineJoints.append(j)
        cmds.setAttr("%s.displayLocalAxis" % j, 1)

    # set rotation orders
    leanAxis = [axis for axis in ["x", "y", "z"] if not axis in [twistAxis, bendAxis]][0]
    rotateOrder = "%s%s%s" % (twistAxis, leanAxis, bendAxis)
    rotateOrderDict = {"xyz": 0, "yzx": 1, "zxy": 2, "xzy": 3, "yxz": 4, "zyx": 5}

    for i in (
        [hipGrp, hipCtrl.control, chestGrp, chestCtrl.control, headGrp, headCtrl.control] + spineGrps + spineJoints
    ):
        cmds.setAttr("%s.rotateOrder" % i, rotateOrderDict[rotateOrder])

    # connect driven groups and joints below chest to chest control rotations
    spineBendUC = cmds.createNode("unitConversion")
    spineBendUC = cmds.rename(
        spineBendUC, common.getName(node=spineBendUC, side="cn", rigPart="spine", function="bend", nodeType="conv")
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, bendAxis), "%s.input" % spineBendUC)
    cmds.setAttr("%s.conversionFactor" % spineBendUC, 1.0 / (numSpineJoints - 1))

    spineLeanUC = cmds.createNode("unitConversion")
    spineLeanUC = cmds.rename(
        spineLeanUC, common.getName(node=spineLeanUC, side="cn", rigPart="spine", function="lean", nodeType="conv")
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, leanAxis), "%s.input" % spineLeanUC)
    cmds.setAttr("%s.conversionFactor" % spineLeanUC, 1.0 / (numSpineJoints - 1))

    for grp in spineGrps[1:numSpineJoints]:
        cmds.connectAttr("%s.output" % spineBendUC, "%s.r%s" % (grp, bendAxis))
        cmds.connectAttr("%s.output" % spineLeanUC, "%s.r%s" % (grp, leanAxis))

    for i in range(numSpineJoints - 1):
        spineTwistUC = cmds.createNode("unitConversion")
        spineTwistUC = cmds.rename(
            spineTwistUC,
            common.getName(node=spineTwistUC, side="cn", rigPart="spine", function="twist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % spineTwistUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistUC, 1.0 / (numSpineJoints - 1) * (i + 1))
        cmds.connectAttr("%s.output" % spineTwistUC, "%s.r%s" % (spineJoints[i + 1], twistAxis))

    # connect driven groups above chest to reverse chest control rotations + hips control rotations
    hipRotUC = cmds.createNode("unitConversion")
    hipRotUC = cmds.rename(
        hipRotUC, common.getName(node=hipRotUC, side="cn", rigPart="spine", function="hipRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % hipRotUC, -1)
    cmds.connectAttr("%s.r" % hipCtrl.control, "%s.input" % hipRotUC)
    hipRotMD = cmds.createNode("multiplyDivide")
    hipRotMD = cmds.rename(
        hipRotMD, common.getName(node=hipRotMD, side="cn", rigPart="spine", function="hipRotate", nodeType="multDiv")
    )
    cmds.connectAttr("%s.output" % hipRotUC, "%s.input1" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2X" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Y" % hipRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Z" % hipRotMD)

    chestRotUC = cmds.createNode("unitConversion")
    chestRotUC = cmds.rename(
        chestRotUC, common.getName(node=chestRotUC, side="cn", rigPart="spine", function="chestRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % chestRotUC, -1)
    cmds.connectAttr("%s.r" % chestCtrl.control, "%s.input" % chestRotUC)
    chestRotMD = cmds.createNode("multiplyDivide")
    chestRotMD = cmds.rename(
        chestRotMD,
        common.getName(node=chestRotMD, side="cn", rigPart="spine", function="chestRotate", nodeType="multDiv"),
    )
    cmds.connectAttr("%s.output" % chestRotUC, "%s.input1" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2X" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Y" % chestRotMD)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.input2Z" % chestRotMD)

    headRotUC = cmds.createNode("unitConversion")
    headRotUC = cmds.rename(
        headRotUC, common.getName(node=headRotUC, side="cn", rigPart="spine", function="headRotate", nodeType="conv")
    )
    cmds.setAttr("%s.conversionFactor" % headRotUC, 1)
    cmds.connectAttr("%s.r" % headCtrl.control, "%s.input" % headRotUC)

    # negative hip and chest rotation are added to head rotation. The negative values are piped through a multiplier to blend the head isolation off and on
    spineRotNegPMA = cmds.createNode("plusMinusAverage")
    spineRotNegPMA = cmds.rename(
        spineRotNegPMA,
        common.getName(node=spineRotNegPMA, side="cn", rigPart="spine", function="rotateNeg", nodeType="pma"),
    )
    cmds.connectAttr("%s.output" % hipRotMD, "%s.input3D[0]" % spineRotNegPMA)
    cmds.connectAttr("%s.output" % chestRotMD, "%s.input3D[1]" % spineRotNegPMA)
    cmds.connectAttr("%s.output" % headRotUC, "%s.input3D[2]" % spineRotNegPMA)

    spineBendNegUC = cmds.createNode("unitConversion")
    spineBendNegUC = cmds.rename(
        spineBendNegUC,
        common.getName(node=spineBendNegUC, side="cn", rigPart="spine", function="bendNeg", nodeType="conv"),
    )
    cmds.connectAttr("%s.output3D%s" % (spineRotNegPMA, bendAxis), "%s.input" % spineBendNegUC)
    cmds.setAttr("%s.conversionFactor" % spineBendNegUC, 1.0 / (numHeadJoints - 2))

    spineLeanNegUC = cmds.createNode("unitConversion")
    spineLeanNegUC = cmds.rename(
        spineLeanNegUC,
        common.getName(node=spineLeanNegUC, side="cn", rigPart="spine", function="leanNeg", nodeType="conv"),
    )
    cmds.connectAttr("%s.output3D%s" % (spineRotNegPMA, leanAxis), "%s.input" % spineLeanNegUC)
    cmds.setAttr("%s.conversionFactor" % spineLeanNegUC, 1.0 / (numHeadJoints - 2))

    for grp in spineGrps[numSpineJoints:-1]:
        cmds.connectAttr("%s.output" % spineBendNegUC, "%s.r%s" % (grp, bendAxis))
        cmds.connectAttr("%s.output" % spineLeanNegUC, "%s.r%s" % (grp, leanAxis))

    # Direct output from chest control. If head isolation is off. All twist joints above it recieve 100% of its twisting
    chestTwistDirectUC = cmds.createNode("unitConversion")
    chestTwistDirectUC = cmds.rename(
        chestTwistDirectUC,
        common.getName(node=chestTwistDirectUC, side="cn", rigPart="spine", function="chestTwist", nodeType="conv"),
    )
    cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % chestTwistDirectUC)
    cmds.setAttr("%s.conversionFactor" % chestTwistDirectUC, 1.0)

    for i in range(numSpineJoints + 1, len(spineJoints)):
        # gradually negate hip twist from chest up
        hipTwistUC = cmds.createNode("unitConversion")
        hipTwistUC = cmds.rename(
            hipTwistUC,
            common.getName(node=hipTwistUC, side="cn", rigPart="spine", function="hipTwist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (hipCtrl.control, twistAxis), "%s.input" % hipTwistUC)
        cmds.setAttr("%s.conversionFactor" % hipTwistUC, -1.0 / (numHeadJoints - 2) * (i - numSpineJoints))

        # gradually negate chest twist from chest up
        chestTwistUC = cmds.createNode("unitConversion")
        chestTwistUC = cmds.rename(
            chestTwistUC,
            common.getName(node=chestTwistUC, side="cn", rigPart="spine", function="chestTwist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (chestCtrl.control, twistAxis), "%s.input" % chestTwistUC)
        cmds.setAttr("%s.conversionFactor" % chestTwistUC, 1.0 / (numHeadJoints - 2) * (len(spineJoints) - (i + 1)))

        # sum hip and chest negation
        spineTwistNegPMA = cmds.createNode("plusMinusAverage")
        spineTwistNegPMA = cmds.rename(
            spineTwistNegPMA,
            common.getName(
                node=spineTwistNegPMA, side="cn", rigPart="spine", function="twistNeg%s" % i, nodeType="pma"
            ),
        )
        cmds.connectAttr("%s.output" % hipTwistUC, "%s.input1D[0]" % spineTwistNegPMA)
        cmds.connectAttr("%s.output" % chestTwistUC, "%s.input1D[1]" % spineTwistNegPMA)

        # Distribute head twist down to chest
        spineTwistUC = cmds.createNode("unitConversion")
        spineTwistUC = cmds.rename(
            spineTwistUC,
            common.getName(node=spineTwistUC, side="cn", rigPart="spine", function="twist%s" % i, nodeType="conv"),
        )
        cmds.connectAttr("%s.r%s" % (headCtrl.control, twistAxis), "%s.input" % spineTwistUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistUC, 1.0 / (numHeadJoints - 2) * (i - numSpineJoints))

        # Blend between hip and chest negation (head isolation on) and full inheritance of chest twist (head isolation off)
        spineTwistNegBC = cmds.createNode("blendColors")
        spineTwistNegBC = cmds.rename(
            spineTwistNegBC,
            common.getName(node=spineTwistNegBC, side="cn", rigPart="spine", function="twistNeg%s" % i, nodeType="bc"),
        )
        cmds.connectAttr("%s.output1D" % spineTwistNegPMA, "%s.color1R" % spineTwistNegBC)
        cmds.connectAttr("%s.output" % chestTwistDirectUC, "%s.color2R" % spineTwistNegBC)
        cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.blender" % spineTwistNegBC)

        # Sum blended negation twist and head twist
        spineTwistPMA = cmds.createNode("plusMinusAverage")
        spineTwistPMA = cmds.rename(
            spineTwistPMA,
            common.getName(
                node=spineTwistPMA, side="cn", rigPart="spine", function="twistResult%s" % i, nodeType="pma"
            ),
        )
        cmds.connectAttr("%s.outputR" % spineTwistNegBC, "%s.input1D[0]" % spineTwistPMA)
        cmds.connectAttr("%s.output" % spineTwistUC, "%s.input1D[1]" % spineTwistPMA)

        # Force unit conversion to 1
        spineTwistResultUC = cmds.createNode("unitConversion")
        spineTwistResultUC = cmds.rename(
            spineTwistResultUC,
            common.getName(
                node=spineTwistResultUC, side="cn", rigPart="spine", function="twistResult%s" % i, nodeType="conv"
            ),
        )
        cmds.connectAttr("%s.output1D" % spineTwistPMA, "%s.input" % spineTwistResultUC)
        cmds.setAttr("%s.conversionFactor" % spineTwistResultUC, 1.0)

        cmds.connectAttr("%s.output" % spineTwistResultUC, "%s.r%s" % (spineJoints[i - 1], twistAxis))

    # Orient contstrain last head joint to second last head joint
    orientConst = cmds.orientConstraint(spineJoints[-2], spineJoints[-1])
    # Point constrain chest ctrl grp to its spine group
    pointConst = cmds.pointConstraint(spineGrps[numSpineJoints - 1], chestGrp)
    # Point constrain head ctrl grp to last spine group
    pointConst = cmds.pointConstraint(spineGrps[-1], headGrp)
    # Add orient constraint to headCtrl group - weighted between root noXformGrp and last spine grp - weight controlled by isolation attr
    orientConst = cmds.orientConstraint(xformGrp, chestCtrl.control, headGrp)[0]
    isolateRev = cmds.createNode("reverse")
    isolateRev = cmds.rename(
        isolateRev, common.getName(node=isolateRev, side="cn", rigPart="spine", function="headIsolate", nodeType="rev")
    )
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.inputX" % isolateRev)
    cmds.connectAttr("%s.isolate_rotation" % headCtrl.control, "%s.%sW0" % (orientConst, xformGrp), f=1)
    cmds.connectAttr("%s.outputX" % isolateRev, "%s.%sW1" % (orientConst, chestCtrl.control), f=1)
    cmds.setAttr("%s.interpType" % orientConst, 2)

    # Clean up attributes and objects that need to be hidden / locked
    if cleanUp:
        cmds.setAttr("%s.visibility" % spineGrps[0], 0)
        common.attrCtrl(nodeList=[spineGrps[1]], attrList=["visibility"])
        common.attrCtrl(nodeList=[hipCtrl.control], attrList=["sx", "sy", "sz", "visibility"])
        common.attrCtrl(
            nodeList=[chestCtrl.control, headCtrl.control], attrList=["tx", "ty", "tz", "sx", "sy", "sz", "visibility"]
        )

    returnDict = collections.defaultdict(list)
    returnDict["xformGrp"].append(xformGrp)
    returnDict["hipCtrl"].append(hipCtrl.control)
    returnDict["chestCtrl"].append(chestCtrl.control)
    returnDict["headCtrl"].append(headCtrl.control)

    return returnDict