示例#1
0
def addVertCrvs():
    '''
    '''
    
    for side in 'LT_', 'RT_':
        for jntId in range(0, 13, 3):
            objs = [side+'jacketHori%s_crv_crv_jnt_%d' % (locId, jntId)
                     for locId in reversed(range(1,11))]
            rt.makeCrvThroughObjs(objs, name=side+'jacketVert_crv_'+str(jntId/3), 
                                  connect=True, degree=2)
示例#2
0
def addVertCrvs():
    '''
    '''

    for side in 'LT_', 'RT_':
        for jntId in range(0, 13, 3):
            objs = [
                side + 'jacketHori%s_crv_crv_jnt_%d' % (locId, jntId)
                for locId in reversed(range(1, 11))
            ]
            rt.makeCrvThroughObjs(objs,
                                  name=side + 'jacketVert_crv_' +
                                  str(jntId / 3),
                                  connect=True,
                                  degree=2)
示例#3
0
def addHoriCrvs():
    '''
    '''
    leftDir = ['_back', '_leftBack', '_left', '_leftFront', '_front']

    rightDir = ['_back', '_rightBack', '_right', '_rightFront', '_front']
    '''
    for jntId in range(5):
        objs = ['jacketVert%s_crv_crv_jnt_%d' % (grpName, jntId)
                 for grpName in leftDir]
        rt.makeCrvThroughObjs(objs, name='LT_jacketHori'+str(jntId)+'_crv', 
                              connect=True, degree=2)
        objs = ['jacketVert%s_crv_crv_jnt_%d' % (grpName, jntId)
                 for grpName in rightDir]
        rt.makeCrvThroughObjs(objs, name='RT_jacketHori'+str(jntId)+'_crv', 
                              connect=True, degree=2)
    '''
    '''
    # start locs
    objs = ['jacketStart%s_loc_offset' % grpName
            for grpName in leftDir]
    rt.makeCrvThroughObjs(objs, name='LT_jacketStartHori_crv', 
                          connect=True, degree=2)
    objs = ['jacketStart%s_loc_offset' % grpName
            for grpName in rightDir]
    rt.makeCrvThroughObjs(objs, name='RT_jacketStartHori_crv', 
                          connect=True, degree=2)
    '''
    # other locs
    for locId in range(1, 11):
        objs = [
            'torsoReader_%d%s_loc_pushOutLoc' % (locId, grpName)
            for grpName in leftDir
        ]
        rt.makeCrvThroughObjs(objs,
                              name='LT_jacketHori' + str(locId) + '_crv',
                              connect=True,
                              degree=2)
        objs = [
            'torsoReader_%d%s_loc_pushOutLoc' % (locId, grpName)
            for grpName in rightDir
        ]
        rt.makeCrvThroughObjs(objs,
                              name='RT_jacketHori' + str(locId) + '_crv',
                              connect=True,
                              degree=2)
示例#4
0
def addHoriCrvs():
    '''
    '''
    leftDir = ['_back',
               '_leftBack',
               '_left',
               '_leftFront',
               '_front']
    
    rightDir = ['_back',
               '_rightBack',
               '_right',
               '_rightFront',
               '_front']
    '''
    for jntId in range(5):
        objs = ['jacketVert%s_crv_crv_jnt_%d' % (grpName, jntId)
                 for grpName in leftDir]
        rt.makeCrvThroughObjs(objs, name='LT_jacketHori'+str(jntId)+'_crv', 
                              connect=True, degree=2)
        objs = ['jacketVert%s_crv_crv_jnt_%d' % (grpName, jntId)
                 for grpName in rightDir]
        rt.makeCrvThroughObjs(objs, name='RT_jacketHori'+str(jntId)+'_crv', 
                              connect=True, degree=2)
    '''
    '''
    # start locs
    objs = ['jacketStart%s_loc_offset' % grpName
            for grpName in leftDir]
    rt.makeCrvThroughObjs(objs, name='LT_jacketStartHori_crv', 
                          connect=True, degree=2)
    objs = ['jacketStart%s_loc_offset' % grpName
            for grpName in rightDir]
    rt.makeCrvThroughObjs(objs, name='RT_jacketStartHori_crv', 
                          connect=True, degree=2)
    '''
    # other locs
    for locId in range(1,11):
        objs = ['torsoReader_%d%s_loc_pushOutLoc' % (locId, grpName)
                for grpName in leftDir]
        rt.makeCrvThroughObjs(objs, name='LT_jacketHori'+str(locId)+'_crv', 
                              connect=True, degree=2)
        objs = ['torsoReader_%d%s_loc_pushOutLoc' % (locId, grpName)
                for grpName in rightDir]
        rt.makeCrvThroughObjs(objs, name='RT_jacketHori'+str(locId)+'_crv', 
                              connect=True, degree=2)
示例#5
0
def createDfmSys(nodeName, drvLocs, ctls, geo):
    '''
    drvLocs are used to drive baseCrv
    ctls are used to drive wireCrv
    wire deforms geo
    
    return dfmSysGrp
    '''
    
    # create baseCrv
    baseCrv = rt.makeCrvThroughObjs(drvLocs, nodeName+'_wireOffset_baseCrv', True, 3)
    
    # create wireCrv
    wireCrv = rt.makeCrvThroughObjs(ctls, nodeName+'_wireOffset_wireCrv', True, 3)
    
    # create wireDfm
    wireDfm, wireCrv = mc.wire(geo, wire=wireCrv, n=nodeName+'_wireOffset_wireDfm', dds=(0,5))
    wireBaseUnwanted = wireCrv+'BaseWire'
    # replace base
    mc.connectAttr(baseCrv+'.worldSpace[0]', wireDfm+'.baseWire[0]', f=True)
    mc.delete(wireBaseUnwanted)
    
    # create dfmSysGrp
    dfmSysGrp = mc.group(baseCrv, wireCrv, n=nodeName+'_wireOffset_dfmSys_grp')
    rt.connectVisibilityToggle(wireCrv, dfmSysGrp, 'wireCrvVis', False)
    rt.connectVisibilityToggle(baseCrv, dfmSysGrp, 'baseCrvVis', False)
    
    mc.addAttr(dfmSysGrp, ln='envelope', at='double', k=True, dv=1)
    mc.addAttr(dfmSysGrp, ln='dropoff', at='double', k=True, dv=5)
    mc.addAttr(dfmSysGrp, ln='rotation', at='double', k=True, dv=0)
    
    mc.connectAttr(dfmSysGrp+'.envelope', wireDfm+'.envelope', f=True)
    mc.connectAttr(dfmSysGrp+'.dropoff', wireDfm+'.dds[0]', f=True)
    mc.connectAttr(dfmSysGrp+'.rotation', wireDfm+'.rotation', f=True)
    
    mc.addAttr(dfmSysGrp, ln='enabled', at='bool', k=True, dv=True)
    rt.connectSDK(dfmSysGrp+'.enabled', wireDfm+'.nodeState', {1:0, 0:2})
    
    return dfmSysGrp
示例#6
0
def makeDynamicWire(jnts, geo, name, ctl):
    '''
    '''
    # make curve through joints
    startCrv = rt.makeCrvThroughObjs(jnts, name + '_startCrv', True, 2)

    # make curve dynamic
    mc.select(startCrv, r=True)
    meval('makeCurvesDynamic 2 { "0", "0", "1", "1", "0"};')

    # get a handle on new (badly named) nodes
    hairSys = mc.ls(sl=True)[0]
    foll = mc.listConnections(hairSys + '.outputHair[0]', d=True)[0]
    dynCrv = mc.listConnections(foll + '.outCurve', d=True)[0]

    # rename nodes properly
    hairSys = mc.rename(hairSys, name + '_hairSysShape')
    foll = mc.rename(foll, name + '_foll')
    dynCrv = mc.rename(dynCrv, name + '_dynCrv')

    # rename group and transform nodes as well
    hairSysTransform = mc.listRelatives(hairSys, p=True)[0]
    hairSysTransform = mc.rename(hairSysTransform, name + '_hairSys')

    startGrp = mc.listRelatives(foll, p=True)[0]
    startGrp = mc.rename(startGrp, name + '_hairSysFollicles')

    outputGrp = mc.listRelatives(dynCrv, p=True)[0]
    outputGrp = mc.rename(outputGrp, name + '_hairSysOutputCrvs')

    # since we now have start curve and end curve, we can make the wire deformer
    wireDfm, wireCrv = mc.wire(geo,
                               wire=dynCrv,
                               n=name + '_dyn_wireDfm',
                               dds=(0, 50))
    wireBaseUnwanted = wireCrv + 'BaseWire'
    # replace base
    mc.connectAttr(startCrv + '.worldSpace[0]',
                   wireDfm + '.baseWire[0]',
                   f=True)
    mc.delete(wireBaseUnwanted)

    # group nodes nicely
    masterGrp = mc.group(hairSysTransform,
                         startGrp,
                         outputGrp,
                         n=name + '_hairSysMaster_grp')
    rt.connectVisibilityToggle([startGrp, outputGrp], masterGrp, 'curvesVis',
                               False)
    rt.connectVisibilityToggle(hairSysTransform, masterGrp, 'hairSysVis',
                               False)

    # attributes on ctl
    mc.addAttr(ctl,
               ln='tDynamics',
               nn='DYNAMICS',
               at='enum',
               en='-----',
               k=True)
    #mc.setAttr(ctl+'.tDynamics', l=True)
    mc.addAttr(ctl, ln='enabled', at='bool', dv=True, k=True)
    mc.addAttr(ctl, ln='weight', at='double', min=0, max=1, dv=1, k=True)

    mc.connectAttr(ctl + '.weight', wireDfm + '.envelope', f=True)
    rt.connectSDK(ctl + '.enabled', hairSys + '.simulationMethod', {
        0: 0,
        1: 3
    })

    # expose follicle attributes to ctl
    mc.addAttr(ctl,
               ln='pointLock',
               at='enum',
               en='No Attach:Base:Tip:Both Ends',
               k=True,
               dv=1)
    mc.connectAttr(ctl + '.pointLock', foll + '.pointLock', f=True)

    # expose hairSystem attributes to ctl
    mc.addAttr(ctl,
               ln='startCurveAttract',
               at='double',
               min=0,
               max=1,
               dv=0.05,
               k=True)
    mc.addAttr(ctl, ln='mass', at='double', min=0, dv=1, k=True)
    mc.addAttr(ctl, ln='drag', at='double', min=0, dv=0.05, k=True)
    mc.addAttr(ctl, ln='damp', at='double', min=0, dv=0, k=True)

    mc.connectAttr(ctl + '.startCurveAttract',
                   hairSys + '.startCurveAttract',
                   f=True)
    mc.connectAttr(ctl + '.mass', hairSys + '.mass', f=True)
    mc.connectAttr(ctl + '.drag', hairSys + '.drag', f=True)
    mc.connectAttr(ctl + '.damp', hairSys + '.damp', f=True)
示例#7
0
def addIndividualOffsetRig(toothId, selVerts):
    """
    returns top group node
    """
    name = 'CT_toothOffset%d_' % toothId
    #===========================================================================
    # ADD OFFSET CONTROLS
    #===========================================================================

    # add offset controlA
    ctlA = rt.ctlCurve(name + 'ctlA',
                       'circle',
                       0,
                       snap='CT_teethOffset_align_loc_%d' % toothId,
                       size=1,
                       ctlOffsets=['bend'])
    mc.aimConstraint('CT_teethOffset_aim_loc_%d' % toothId,
                     ctlA.home,
                     aim=(1, 0, 0),
                     u=(0, 0, 1),
                     wut='objectRotation',
                     wuo='CT_teethOffset_align_loc_%d' % toothId,
                     wu=(0, 0, 1))
    mc.pointConstraint('CT_teethOffset_align_loc_%d' % toothId, ctlA.home)

    # add second offset control as child to first
    ctlB = rt.ctlCurve(name + 'ctlB',
                       'circle',
                       0,
                       snap=ctlA.crv,
                       size=1,
                       ctlOffsets=['bend'])
    mc.parent(ctlB.home, ctlA.crv)
    mc.setAttr(ctlB.home + '.tx', 0.5)

    # local rig's bend should update CtlB
    mc.connectAttr('CT_teethLocal%d_bndB.ry' % (toothId + 1),
                   ctlB.grp['bend'] + '.ry',
                   f=True)

    #===============================================================================
    # Connections from offsetCtls to localRig
    #===============================================================================
    # since scale should always be local
    mc.connectAttr(ctlA.crv + '.sy',
                   'CT_teethLocal%d_bndA.sy' % (toothId + 1),
                   f=True)
    mc.connectAttr(ctlA.crv + '.sz',
                   'CT_teethLocal%d_bndA.sz' % (toothId + 1),
                   f=True)

    mc.connectAttr(ctlB.crv + '.sy',
                   'CT_teethLocal%d_bndB.sy' % (toothId + 1),
                   f=True)
    mc.connectAttr(ctlB.crv + '.sz',
                   'CT_teethLocal%d_bndB.sz' % (toothId + 1),
                   f=True)

    # twisting could also be local
    mc.connectAttr(ctlA.crv + '.rx',
                   'CT_teethLocal%d_bndA.rx' % (toothId + 1),
                   f=True)
    mc.connectAttr(ctlB.crv + '.rx',
                   'CT_teethLocal%d_bndB.rx' % (toothId + 1),
                   f=True)

    # slide tooth along path
    mc.addAttr(ctlA.crv, ln='slide', at='double', k=True)
    mc.connectAttr(ctlA.crv + '.slide',
                   'CT_teethLocal%d_bndA.ty' % (toothId + 1),
                   f=True)

    #===============================================================================
    # Complete CV point placement for curves
    #===============================================================================
    # endLoc under ctlB
    endLoc = mc.spaceLocator(n=name + 'ctlB_endLoc')[0]
    rt.parentSnap(endLoc, ctlB.crv)
    mc.setAttr(endLoc + '.tx', 0.5)
    mc.setAttr(endLoc + '.localScale', 0.1, 0.1, 0.1)

    #===============================================================================
    # second hierarchy for base curve
    #===============================================================================
    ctlABase = mc.group(em=True, n=name + 'ctlABase_grp')
    mc.aimConstraint('CT_teethOffset_aim_loc_%d' % toothId,
                     ctlABase,
                     aim=(1, 0, 0),
                     u=(0, 0, 1),
                     wut='objectRotation',
                     wuo='CT_teethOffset_align_loc_%d' % toothId,
                     wu=(0, 0, 1))
    mc.pointConstraint('CT_teethOffset_align_loc_%d' % toothId, ctlABase)
    ctlBBase = mc.group(em=True, n=name + 'ctlBBase_grp')
    rt.parentSnap(ctlBBase, ctlABase)
    mc.setAttr(ctlBBase + '.tx', 0.5)
    mc.connectAttr('CT_teethLocal%d_bndB.ry' % (toothId + 1),
                   ctlBBase + '.ry',
                   f=True)
    endBaseLoc = mc.spaceLocator(n=name + 'ctlB_endBaseLoc')[0]
    rt.parentSnap(endBaseLoc, ctlBBase)
    mc.setAttr(endBaseLoc + '.tx', 0.5)
    mc.setAttr(endBaseLoc + '.localScale', 0.1, 0.1, 0.1)

    # connect scale for base transforms
    mc.connectAttr(ctlA.crv + '.sy', ctlABase + '.sy', f=True)
    mc.connectAttr(ctlA.crv + '.sz', ctlABase + '.sz', f=True)
    mc.connectAttr(ctlB.crv + '.sy', ctlBBase + '.sy', f=True)
    mc.connectAttr(ctlB.crv + '.sz', ctlBBase + '.sz', f=True)

    #===============================================================================
    # Make wire deformer
    #===============================================================================
    # base curve
    baseCrv = rt.makeCrvThroughObjs([ctlABase, ctlBBase, endBaseLoc],
                                    name + 'baseCrv', True, 2)
    # wire curve
    wireCrv = rt.makeCrvThroughObjs([ctlA.crv, ctlB.crv, endLoc],
                                    name + 'wireCrv', True, 2)
    # make wire
    wireDfm, wireCrv = mc.wire(selVerts,
                               wire=wireCrv,
                               n=name + 'wire_dfm',
                               dds=(0, 50))
    wireBaseUnwanted = wireCrv + 'BaseWire'
    # replace base
    mc.connectAttr(baseCrv + '.worldSpace[0]',
                   wireDfm + '.baseWire[0]',
                   f=True)
    mc.delete(wireBaseUnwanted)

    #===========================================================================
    # GROUPS & DEBUG UTILS
    #===========================================================================
    dfmGrp = mc.group(baseCrv, wireCrv, n=name + 'dfg_0')
    ctlGrp = mc.group(ctlA.home, ctlABase, n=name + 'ctg_0')
    retGrp = mc.group(dfmGrp, ctlGrp, n=name + 'mod_0')

    rt.connectVisibilityToggle([endLoc, endBaseLoc], retGrp, 'endLocs', False)
    rt.connectVisibilityToggle(dfmGrp, retGrp, 'wires', False)

    return retGrp
示例#8
0
def addIndividualOffsetRig(toothId, selVerts):
    """
    returns top group node
    """
    name = 'CT_toothOffset%d_'%toothId
    #===========================================================================
    # ADD OFFSET CONTROLS
    #===========================================================================
    
    # add offset controlA
    ctlA = rt.ctlCurve(name+'ctlA', 'circle', 0, snap='CT_teethOffset_align_loc_%d'%toothId, size=1, ctlOffsets=['bend'])
    mc.aimConstraint('CT_teethOffset_aim_loc_%d'%toothId, ctlA.home, aim=(1,0,0), u=(0,0,1), wut='objectRotation', wuo='CT_teethOffset_align_loc_%d'%toothId, wu=(0,0,1))
    mc.pointConstraint('CT_teethOffset_align_loc_%d'%toothId, ctlA.home)
    
    # add second offset control as child to first
    ctlB = rt.ctlCurve(name+'ctlB', 'circle', 0, snap=ctlA.crv, size=1, ctlOffsets=['bend'])
    mc.parent(ctlB.home, ctlA.crv)
    mc.setAttr(ctlB.home+'.tx', 0.5)
    
    # local rig's bend should update CtlB
    mc.connectAttr('CT_teethLocal%d_bndB.ry'%(toothId+1), ctlB.grp['bend']+'.ry', f=True)
    
    #===============================================================================
    # Connections from offsetCtls to localRig
    #===============================================================================
    # since scale should always be local
    mc.connectAttr(ctlA.crv+'.sy', 'CT_teethLocal%d_bndA.sy'%(toothId+1), f=True)
    mc.connectAttr(ctlA.crv+'.sz', 'CT_teethLocal%d_bndA.sz'%(toothId+1), f=True)
    
    mc.connectAttr(ctlB.crv+'.sy', 'CT_teethLocal%d_bndB.sy'%(toothId+1), f=True)
    mc.connectAttr(ctlB.crv+'.sz', 'CT_teethLocal%d_bndB.sz'%(toothId+1), f=True)
    
    # twisting could also be local
    mc.connectAttr(ctlA.crv+'.rx', 'CT_teethLocal%d_bndA.rx'%(toothId+1), f=True)
    mc.connectAttr(ctlB.crv+'.rx', 'CT_teethLocal%d_bndB.rx'%(toothId+1), f=True)
    
    # slide tooth along path
    mc.addAttr(ctlA.crv, ln='slide', at='double', k=True)
    mc.connectAttr(ctlA.crv+'.slide', 'CT_teethLocal%d_bndA.ty'%(toothId+1), f=True)
    
    #===============================================================================
    # Complete CV point placement for curves
    #===============================================================================
    # endLoc under ctlB
    endLoc = mc.spaceLocator(n=name+'ctlB_endLoc')[0]
    rt.parentSnap(endLoc, ctlB.crv)
    mc.setAttr(endLoc+'.tx', 0.5)
    mc.setAttr(endLoc+'.localScale', 0.1,0.1,0.1)
    
    #===============================================================================
    # second hierarchy for base curve
    #===============================================================================
    ctlABase = mc.group(em=True, n=name+'ctlABase_grp')
    mc.aimConstraint('CT_teethOffset_aim_loc_%d'%toothId, ctlABase, aim=(1,0,0), u=(0,0,1), wut='objectRotation', wuo='CT_teethOffset_align_loc_%d'%toothId, wu=(0,0,1))
    mc.pointConstraint('CT_teethOffset_align_loc_%d'%toothId, ctlABase)
    ctlBBase = mc.group(em=True, n=name+'ctlBBase_grp')
    rt.parentSnap(ctlBBase, ctlABase)
    mc.setAttr(ctlBBase+'.tx', 0.5)
    mc.connectAttr('CT_teethLocal%d_bndB.ry'%(toothId+1), ctlBBase+'.ry', f=True)
    endBaseLoc = mc.spaceLocator(n=name+'ctlB_endBaseLoc')[0]
    rt.parentSnap(endBaseLoc, ctlBBase)
    mc.setAttr(endBaseLoc+'.tx', 0.5)
    mc.setAttr(endBaseLoc+'.localScale', 0.1,0.1,0.1)
    
    # connect scale for base transforms
    mc.connectAttr(ctlA.crv+'.sy', ctlABase+'.sy', f=True)
    mc.connectAttr(ctlA.crv+'.sz', ctlABase+'.sz', f=True)
    mc.connectAttr(ctlB.crv+'.sy', ctlBBase+'.sy', f=True)
    mc.connectAttr(ctlB.crv+'.sz', ctlBBase+'.sz', f=True)

    #===============================================================================
    # Make wire deformer
    #===============================================================================
    # base curve
    baseCrv = rt.makeCrvThroughObjs([ctlABase, ctlBBase, endBaseLoc], name+'baseCrv', True, 2)
    # wire curve
    wireCrv = rt.makeCrvThroughObjs([ctlA.crv, ctlB.crv, endLoc], name+'wireCrv', True, 2)
    # make wire
    wireDfm, wireCrv = mc.wire(selVerts, wire=wireCrv, n=name+'wire_dfm', dds=(0,50))
    wireBaseUnwanted = wireCrv+'BaseWire'
    # replace base
    mc.connectAttr(baseCrv+'.worldSpace[0]', wireDfm+'.baseWire[0]', f=True)
    mc.delete(wireBaseUnwanted)
    
    #===========================================================================
    # GROUPS & DEBUG UTILS
    #===========================================================================
    dfmGrp = mc.group(baseCrv, wireCrv, n=name+'dfg_0')
    ctlGrp = mc.group(ctlA.home, ctlABase, n=name+'ctg_0')
    retGrp= mc.group(dfmGrp, ctlGrp, n=name+'mod_0')
    
    rt.connectVisibilityToggle([endLoc, endBaseLoc], retGrp, 'endLocs', False)
    rt.connectVisibilityToggle(dfmGrp, retGrp, 'wires', False)
    
    return retGrp
示例#9
0
def makeDynamicWire(jnts, geo, name, ctl):
    '''
    '''
    # make curve through joints
    startCrv = rt.makeCrvThroughObjs(jnts, name+'_startCrv', True, 2)
    
    # make curve dynamic
    mc.select(startCrv, r=True)
    meval('makeCurvesDynamic 2 { "0", "0", "1", "1", "0"};')
    
    # get a handle on new (badly named) nodes
    hairSys = mc.ls(sl=True)[0]
    foll = mc.listConnections(hairSys+'.outputHair[0]', d=True)[0]
    dynCrv = mc.listConnections(foll+'.outCurve', d=True)[0]
    
    # rename nodes properly
    hairSys = mc.rename(hairSys, name+'_hairSysShape')
    foll = mc.rename(foll, name+'_foll')
    dynCrv = mc.rename(dynCrv, name+'_dynCrv')
    
    # rename group and transform nodes as well
    hairSysTransform = mc.listRelatives(hairSys, p=True)[0]
    hairSysTransform = mc.rename(hairSysTransform, name+'_hairSys')
    
    startGrp = mc.listRelatives(foll, p=True)[0]
    startGrp = mc.rename(startGrp, name+'_hairSysFollicles')
    
    outputGrp = mc.listRelatives(dynCrv, p=True)[0]
    outputGrp = mc.rename(outputGrp, name+'_hairSysOutputCrvs')
    
    # since we now have start curve and end curve, we can make the wire deformer
    wireDfm, wireCrv = mc.wire(geo, wire=dynCrv, n=name+'_dyn_wireDfm', dds=(0,50))
    wireBaseUnwanted = wireCrv+'BaseWire'
    # replace base
    mc.connectAttr(startCrv+'.worldSpace[0]', wireDfm+'.baseWire[0]', f=True)
    mc.delete(wireBaseUnwanted)
    
    # group nodes nicely
    masterGrp = mc.group(hairSysTransform, startGrp, outputGrp, n=name+'_hairSysMaster_grp')
    rt.connectVisibilityToggle([startGrp, outputGrp], masterGrp, 'curvesVis', False)
    rt.connectVisibilityToggle(hairSysTransform, masterGrp, 'hairSysVis', False)
    
    # attributes on ctl
    mc.addAttr(ctl, ln='tDynamics', nn='DYNAMICS', at='enum', en='-----', k=True)
    #mc.setAttr(ctl+'.tDynamics', l=True)
    mc.addAttr(ctl, ln='enabled', at='bool', dv=True, k=True)
    mc.addAttr(ctl, ln='weight', at='double', min=0, max=1, dv=1, k=True)
    
    mc.connectAttr(ctl+'.weight', wireDfm+'.envelope', f=True)
    rt.connectSDK(ctl+'.enabled', hairSys+'.simulationMethod', {0:0, 1:3})
    
    # expose follicle attributes to ctl
    mc.addAttr(ctl, ln='pointLock', at='enum', en='No Attach:Base:Tip:Both Ends', k=True, dv=1)
    mc.connectAttr(ctl+'.pointLock', foll+'.pointLock', f=True)
    
    # expose hairSystem attributes to ctl
    mc.addAttr(ctl, ln='startCurveAttract', at='double', min=0, max=1, dv=0.05, k=True)
    mc.addAttr(ctl, ln='mass', at='double', min=0, dv=1, k=True)
    mc.addAttr(ctl, ln='drag', at='double', min=0, dv=0.05, k=True)
    mc.addAttr(ctl, ln='damp', at='double', min=0, dv=0, k=True)
    
    mc.connectAttr(ctl+'.startCurveAttract', hairSys+'.startCurveAttract', f=True)
    mc.connectAttr(ctl+'.mass', hairSys+'.mass', f=True)
    mc.connectAttr(ctl+'.drag', hairSys+'.drag', f=True)
    mc.connectAttr(ctl+'.damp', hairSys+'.damp', f=True)