示例#1
0
def addOffsetRig():
    #===============================================================================
    # SETUP LOCATORS FOR ALIGN AND AIM
    #===============================================================================
    # add offsetAimLocs to blockAimCrv
    globalGrp = 'CT_teethOffset_mod_0'
    mc.group(n=globalGrp, em=True)
    name = 'CT_teethOffset'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs = []
    for locId in range(12):
        loc = mc.spaceLocator(n=name + '_aim_loc_%d' % locId)[0]
        mc.setAttr(loc + '.localScale', 0.1, 0.1, 0.1)
        rt.attachToMotionPath(targetCrv, (float(locId) + 0.5) / 12, loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethOffset_aim_loc_grp', p=globalGrp)
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)

    # add offsetAlignLocs to blockDrvCrv
    targetCrv = 'CT_teethBlockDrv_crv_0'
    locs = []
    for locId in range(12):
        loc = mc.spaceLocator(n=name + '_align_loc_%d' % locId)[0]
        mc.setAttr(loc + '.localScale', 0.1, 0.1, 0.1)
        rt.alignOnMotionPath(targetCrv, (float(locId) + 0.5) / 12,
                             loc,
                             name + '_aim_loc_%d.matrix' % locId,
                             True,
                             ua=1,
                             inverseUp=True)
        locs.append(loc)
    mc.group(locs, n='CT_teethOffset_align_loc_grp', p=globalGrp)
    rt.connectVisibilityToggle(locs, globalGrp, 'alignLocs', False)
示例#2
0
def addOffsetRig():
    #===============================================================================
    # SETUP LOCATORS FOR ALIGN AND AIM
    #===============================================================================
    # add offsetAimLocs to blockAimCrv
    globalGrp = 'CT_teethOffset_mod_0'
    mc.group(n=globalGrp, em=True)
    name = 'CT_teethOffset'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs=[]
    for locId in range(12):
        loc = mc.spaceLocator(n=name+'_aim_loc_%d'%locId)[0]
        mc.setAttr(loc+'.localScale', 0.1,0.1,0.1)
        rt.attachToMotionPath(targetCrv, (float(locId)+0.5)/12, loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethOffset_aim_loc_grp', p=globalGrp)
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)
    
    # add offsetAlignLocs to blockDrvCrv
    targetCrv = 'CT_teethBlockDrv_crv_0'
    locs=[]
    for locId in range(12):
        loc = mc.spaceLocator(n=name+'_align_loc_%d'%locId)[0]
        mc.setAttr(loc+'.localScale', 0.1,0.1,0.1)
        rt.alignOnMotionPath(targetCrv, (float(locId)+0.5)/12, loc, name+'_aim_loc_%d.matrix'%locId, True, ua=1, inverseUp=True)
        locs.append(loc)
    mc.group(locs, n='CT_teethOffset_align_loc_grp', p=globalGrp)
    rt.connectVisibilityToggle(locs, globalGrp, 'alignLocs', False)
示例#3
0
def addJntsOnSurfIntersection(surf1, surf2, jntsNum):
    '''
    Places jnts along intersection curve between surf1 and surf2
    naming convention based on surf1
    '''
    
    # intersect surfaces
    crvGrp, intNode = mc.intersect(surf1, surf2, fs=True, ch=True, o=True, cos=False)[:2]
    intNode = mc.rename(intNode, surf1+'_ints')
    crvGrp = mc.rename(crvGrp, surf1+'_ints_crv_grp')
    crv = mc.listRelatives(crvGrp, c=True)[0]
    crv = mc.rename(crv, surf1+'_ints_crv')
    
    # rebuild curve to jntNum spans
    rbdCrv, rbdNode = mc.rebuildCurve(crv, ch=True, o=True, rpo=False, spans=jntsNum, rt=0, kr=2, n=crv+'_rbd_crv')
    rbdNode = mc.rename(rbdNode, crv+'_rbd')
    
    # offset curve to control size of eye hole
    offsetCrv, offsetNode = mc.offsetCurve(rbdCrv, ch=True, distance=0, o=True, ugn=0, n=crv+'_offset_crv')
    offsetNode = mc.rename(offsetNode, crv+'_offset')
    
    locs = []
    locName = '_'.join(surf1.split('_')[:2])
    # attach locators to intersection curve
    for locId in range(jntsNum):
        loc = mc.spaceLocator(n=locName+'_loc_%d' % locId)[0]
        rt.attachToMotionPath(offsetCrv, locId, loc, fm=False)
        mc.setAttr(loc+'.localScale', 0.05, 0.05, 0.05)
        locs.append(loc)
        
    # normal constraint to surf1
    for loc in locs:
        mc.normalConstraint(surf2, loc, aim=(1,0,0))
    
    jnts = []
    # add joints under locators
    for loc in locs:
        mc.select(cl=True)
        jnt = mc.joint(n=loc.replace('_loc_','_jnt_'))
        rt.parentSnap(jnt, loc)
        mc.setAttr(jnt+'.jointOrient', 0,0,0)
        jnts.append(jnt)
        
    # groups
    grp = mc.group(crvGrp, offsetCrv, rbdCrv, locs, n=surf1+'_intersect_loc_grp')
    
    # create offset attribute
    mc.addAttr(grp, ln='collideOffset', at='double', dv=0, k=True)
    offsetPlug = cn.create_multDoubleLinear(grp+'.collideOffset', -1)
    mc.connectAttr(offsetPlug, offsetNode+'.distance', f=True)
    
    # connect debug
    rt.connectVisibilityToggle(offsetCrv, grp, 'offsetCrv', False)
    rt.connectVisibilityToggle(rbdCrv, grp, 'rebuildCrv', False)
    rt.connectVisibilityToggle(crvGrp, grp, 'intersectCrv', False)
    rt.connectVisibilityToggle(locs, grp, 'crvLocs', False)
    rt.connectVisibilityToggle(jnts, grp, 'crvJnts', False)
示例#4
0
def createPtDriverSys(nodeName, attachGeo=None):
    '''
    Create driver system based on vertex selection in viewport
    Returns drvSysGrp, and a list of locators that can be used to drive offset controls
    '''
    
    # get vertex selections
    selVerts = mc.ls(os=True, fl=True)

    # create control placement locators on each vert
    drvLocs = []
    origLocs = []
    popcNodes = []
    ctlNum = len(selVerts)
    for ctlId in range(ctlNum):
        loc = mc.spaceLocator(n=nodeName+'_wireOffset_drvLoc%d'%ctlId)[0]
        targetVert = selVerts[ctlId]
        mc.select(targetVert, loc, r=True)
        meval('doCreatePointOnPolyConstraintArgList 2 {   "0" ,"0" ,"0" ,"1" ,"" ,"1" ,"0" ,"0" ,"0" ,"0" };')
        meval('CBdeleteConnection "%s.rx";' % loc)
        meval('CBdeleteConnection "%s.ry";' % loc)
        meval('CBdeleteConnection "%s.rz";' % loc)
        mc.setAttr(loc+'.r', 0,0,0)
        drvLocs.append(loc)
        
        # if attachGeo is defined, use attachGeo to drive pointOnPolyConstraint
        popcNode = mc.listRelatives(loc, c=True, type='pointOnPolyConstraint')[0]
        if attachGeo:
            # make origLoc to preserve position
            origLoc = mc.group(n=loc.replace('_drvLoc', '_drvLocOrig'), em=True)
            rt.parentSnap(origLoc, loc)
            mc.parent(origLoc, w=True)
            
            # swap input mesh for popcNode -> this will move drvLoc
            mc.connectAttr(attachGeo, popcNode+'.target[0].targetMesh', f=True)
            
            # parent origLoc back under driverLoc, and use origLoc as driverLoc instead
            mc.parent(origLoc, loc)
            origLocs.append(origLoc)
            
        popcNodes.append(popcNode)
    
    drvLocGrp = mc.group(drvLocs, n=nodeName+'_wireOffset_drvLocs_grp')
    drvSysGrp = mc.group(drvLocGrp, n=nodeName+'_wireOffset_drvSys_grp')
    rt.connectVisibilityToggle(drvLocs, drvSysGrp, 'drvLocsVis', False)
    
    mc.addAttr(drvSysGrp, ln='enabled', at='bool', k=True, dv=True)
    for eachPopc in popcNodes:
        rt.connectSDK(drvSysGrp+'.enabled', eachPopc+'.nodeState', {1:0, 0:2})
    
    if attachGeo:
        return drvSysGrp, origLocs
    
    return drvSysGrp, drvLocs
示例#5
0
def globalRig():
    """
    Make global teeth rig
    """
    # teeth aim locs
    globalGrp = 'CT_teethBlockGlobal_mod_0'
    locNum = 7
    name = 'CT_teethBlock'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs = []
    for locId in range(locNum):
        loc = mc.spaceLocator(n=name + '_aim_loc_%d' % locId)[0]
        mc.setAttr(loc + '.localScale', 0.1, 0.1, 0.1)
        rt.attachToMotionPath(targetCrv,
                              float(locId) / (locNum - 1), loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethBlock_aim_loc_grp')
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)

    # teeth bind jnt for each aimLoc
    targetCrv = 'CT_teethBlockDrv_crv_0'
    jnts = []
    for jntId in range(locNum):
        mc.select(cl=True)
        jnt = mc.joint(n=name + '_bnd_jnt_%d' % jntId)
        mc.setAttr(jnt + '.radius', 0.5)
        rt.alignOnMotionPath(targetCrv,
                             float(jntId) / (locNum - 1),
                             jnt,
                             name + '_aim_loc_%d.matrix' % jntId,
                             True,
                             ua=1,
                             inverseUp=True)
        jnts.append(jnt)
    mc.group(jnts, n='CT_teethBlock_bnd_jnts_grp')
    rt.connectVisibilityToggle(jnts, globalGrp, 'bndJnts', False)

    jnts = mc.ls(sl=True)

    import utils.wrappers.abRiggingTools as abRT
    # add bnd jnts for bite
    # for each bndjnt, make another jnt below it
    for bndJnt in jnts:
        mc.select(cl=True)
        biteJnt = mc.joint(n=bndJnt + '_bite')
        mc.setAttr(biteJnt + '.radius', 0.5)
        abRT.snapToPosition(bndJnt, biteJnt)
        mc.xform(biteJnt, t=(0, -1, 0), r=True)
        mc.parentConstraint(bndJnt, biteJnt, mo=True)
        mc.parent(biteJnt, 'CT_teethBlock_bnd_jnts_grp')
示例#6
0
def addTangentMPTo(startMP, endMP, direction, default=0.5, reverse=False):
    '''
    add a "tangent" attribute to startLoc, and a tangentLoc to startLoc
    at 0, tangentLoc would be exactly on startLoc
    at 1, tangentLoc would be projected on direction vector onto endLoc's plane
    
    direction (string): 'x', 'y', or 'z'
    reverse (bool): reverse direction
    
    return tangentLoc
    '''
    # add tangentLoc
    tangentLoc = mc.spaceLocator(n=startMP+'_tangent_loc')[0]
    rt.parentSnap(tangentLoc, startMP)
    
    # add planeLoc - moves on plane of endMP, to help calculcate max distance
    planeLoc = mc.spaceLocator(n=endMP+'_plane_loc')[0]
    rt.parentSnap(planeLoc, endMP)
    
    # pointConstraint planeLoc to startMP
    # skip "direction" axis, to maintain sliding on endMP's plane
    mc.pointConstraint(startMP, planeLoc, skip=direction)
    
    # get distance between startMP and planeLoc
    # this is the maximum length for tangent
    maxDistance = cn.create_distanceBetween(startMP, planeLoc)
    
    # add "tangent" attribute to startMP
    mc.addAttr(startMP, ln='tangent', at='double', min=0, max=1, dv=default, k=True)
    
    # multiply tangent value by maxDistance
    tangentDistance = cn.create_multDoubleLinear(startMP+'.tangent', maxDistance)
    
    # reverse the direction if necessary
    if reverse:
        tangentDistance = cn.create_multDoubleLinear(tangentDistance, -1)
    
    # this will be used to drive the tangentLoc
    translatePlug = '%s.t%s' % (tangentLoc, direction)
    mc.connectAttr(tangentDistance, translatePlug, f=True)
    
    # connect locators for debug
    rt.connectVisibilityToggle((planeLoc, tangentLoc), startMP, 'debugTangentLocs', default=False)
    rt.connectVisibilityToggle(tangentLoc, startMP, 'tangentLoc', False)
    
    return tangentLoc
示例#7
0
def createCtlSys(nodeName, drvLocs, size=1, addGrp=1):
    '''
    Adds controls under drvLocs, to be used as offset controls
    size - [float] radius of nurbs sphere control
            if size=1, radius will be 0.2 of distance between first 2 locators
    addGrp - [int] number of offset grps above the control
    Returns ctlSysGrp, and a list of controls
    '''
    # calculate size
    pos1 = pm.dt.Point(mc.xform(drvLocs[0], q=True, ws=True, t=True))
    pos2 = pm.dt.Point(mc.xform(drvLocs[1], q=True, ws=True, t=True))
    vec = pos2 - pos1
    dist = vec.length()
    size = dist * 0.2 * size
    
    # create controls
    ctls = []
    for eachLoc in drvLocs:
        
        grp = eachLoc
        # add offset grps
        for grpId in range(addGrp):
            grp = mc.group(em=True, n=eachLoc.replace('_wireOffset_drvLoc', '_wireOffset_offset%d_grp'%grpId).replace('Orig',''), p=grp)
            mc.xform(grp, os=True, a=True, t=(0,0,0), ro=(0,0,0))
            
        # create control
        ctl = mc.sphere(r=size, n=eachLoc.replace('_wireOffset_drvLoc', '_wireOffset_ctl').replace('Orig',''))[0]
        mc.delete(ctl, ch=True)
        rt.parentSnap(ctl, grp)
        
        # assign color
        # first, break connection to shader
        ctlShape = mc.listRelatives(ctl, c=True, s=True)[0]
        shdConn = mc.listConnections(ctlShape+'.instObjGroups', p=True)[0]
        mc.disconnectAttr(ctlShape+'.instObjGroups', shdConn)
        # assign color override
        mc.setAttr(ctlShape+'.overrideEnabled', 1)
        mc.setAttr(ctlShape+'.overrideColor', 6)
        
        ctls.append(ctl)
    
    ctlSysGrp = mc.group(em=True, n=nodeName+'_wireOffset_ctlSys_grp')
    rt.connectVisibilityToggle(ctls, ctlSysGrp, 'ctlVis', True)
    
    return ctlSysGrp, ctls
示例#8
0
def globalRig():
    """
    Make global teeth rig
    """
    # teeth aim locs
    globalGrp = 'CT_teethBlockGlobal_mod_0'
    locNum = 7
    name = 'CT_teethBlock'
    targetCrv = 'CT_teethBlockAim_crv_0'
    locs=[]
    for locId in range(locNum):
        loc = mc.spaceLocator(n=name+'_aim_loc_%d'%locId)[0]
        mc.setAttr(loc+'.localScale', 0.1,0.1,0.1)
        rt.attachToMotionPath(targetCrv, float(locId)/(locNum-1), loc, True)
        locs.append(loc)
    mc.group(locs, n='CT_teethBlock_aim_loc_grp')
    rt.connectVisibilityToggle(locs, globalGrp, 'aimLocs', False)
    
    # teeth bind jnt for each aimLoc
    targetCrv = 'CT_teethBlockDrv_crv_0'
    jnts=[]
    for jntId in range(locNum):
        mc.select(cl=True)
        jnt = mc.joint(n=name+'_bnd_jnt_%d'%jntId)
        mc.setAttr(jnt+'.radius', 0.5)
        rt.alignOnMotionPath(targetCrv, float(jntId)/(locNum-1), jnt, name+'_aim_loc_%d.matrix'%jntId, True, ua=1, inverseUp=True)
        jnts.append(jnt)
    mc.group(jnts, n='CT_teethBlock_bnd_jnts_grp')
    rt.connectVisibilityToggle(jnts, globalGrp, 'bndJnts', False)
    
    jnts = mc.ls(sl=True)
    
    import utils.wrappers.abRiggingTools as abRT
    # add bnd jnts for bite
    # for each bndjnt, make another jnt below it
    for bndJnt in jnts:
        mc.select(cl=True)
        biteJnt = mc.joint(n=bndJnt+'_bite')
        mc.setAttr(biteJnt+'.radius', 0.5)
        abRT.snapToPosition(bndJnt, biteJnt)
        mc.xform(biteJnt, t=(0,-1,0), r=True)
        mc.parentConstraint(bndJnt, biteJnt, mo=True)
        mc.parent(biteJnt, 'CT_teethBlock_bnd_jnts_grp')
示例#9
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
示例#10
0
def addMidMP(startMP, endMP, startAimMP, endAimMP, aimVector, upVector, name):
    '''
    add a midLoc positioned between startMP and endMP
    alignment can be set to separate MPs
    
    return midLoc
    '''
    # add midPosLoc to get mid position
    midPosLoc = mc.spaceLocator(n=name+'_midPosLoc')[0]
    
    # constraint midPosLoc between startMP and endMP to get mid position
    mc.pointConstraint(startMP, endMP, midPosLoc)
    
    # add aimUp/Down locs to get orientation
    aimUpLoc = mc.spaceLocator(n=name+'_aimUpLoc')[0]
    aimDownLoc = mc.spaceLocator(n=name+'_aimDownLoc')[0]
    rt.parentSnap(aimUpLoc, midPosLoc)
    rt.parentSnap(aimDownLoc, midPosLoc)
    
    # aim constraints to startAimMP and endAimMPs
    mc.aimConstraint(startAimMP, aimDownLoc, aim=aimVector, u=upVector, wut='objectrotation', wuo=startAimMP, wu=upVector)
    oppositeAimVector = [-c for c in aimVector]
    mc.aimConstraint(endAimMP, aimUpLoc, aim=oppositeAimVector, u=upVector, wut='objectrotation', wuo=endAimMP, wu=upVector)
    
    # create orientLoc to blend between the two aims
    orientLoc = mc.spaceLocator(n=name+'_orientLoc')[0]
    rt.parentSnap(orientLoc, midPosLoc)
    mc.orientConstraint(startAimMP, endAimMP, orientLoc)
    
    # create midLoc for outputMP
    midLoc = mc.spaceLocator(n=name)[0]
    rt.parentSnap(midLoc, orientLoc)
    
    # connect visibilities for debugging
    rt.connectVisibilityToggle(midPosLoc, midLoc, 'debugMidPosLoc', default=False)
    rt.connectVisibilityToggle((aimUpLoc, aimDownLoc), midLoc, 'debugAimLocs', default=False)
    rt.connectVisibilityToggle(orientLoc, midLoc, 'debugOrientLoc', default=False)
    
    return midLoc
示例#11
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
示例#12
0
def createCrvDriverSys(nodeName, ctlNum, form=0, attachGeo=None):
    '''
    Create driver system based on edge loop selection in viewport
    nodeName [string]
    ctlNum [int] - number of controls to add along curve
    form - [int] 0 = open, 1 = periodic
    Returns drvSysGrp, and a list of locators that can be used to drive offset controls
    '''
    
    # select edge loop in UI
    drvCrv, p2cNode = mc.polyToCurve(form=form, degree=1, n=nodeName+'_wireOffset_crv')
    p2cNode = mc.rename(p2cNode, nodeName+'_wireOffset_p2c')
    crvSpans = mc.getAttr(drvCrv+'.spans')

    
    # create control placement locators on drvCrv
    drvLocs = []
    for ctlId in range(ctlNum):
        loc = mc.spaceLocator(n=nodeName+'_wireOffset_drvLoc%d'%ctlId)[0]
        param = float(ctlId) / ctlNum * crvSpans
        rt.attachToMotionPath(drvCrv, param, loc, False)
        drvLocs.append(loc)
        
    # if curve is open, we will create an extra ctl, where param = crvSpans 
    if mc.getAttr(drvCrv+'.form') != 2:
        loc = mc.spaceLocator(n=nodeName+'_wireOffset_drvLoc%d'%ctlNum)[0]
        param = crvSpans
        rt.attachToMotionPath(drvCrv, param, loc, False)
        drvLocs.append(loc)
        
    
    drvLocGrp = mc.group(drvLocs, n=nodeName+'_wireOffset_drvLocs_grp')
    drvSysGrp = mc.group(drvCrv, drvLocGrp, n=nodeName+'_wireOffset_drvSys_grp')
    
    rt.connectVisibilityToggle(drvLocs, drvSysGrp, 'drvLocsVis', False)
    rt.connectVisibilityToggle(drvCrv, drvSysGrp, 'drvCrvVis', False)
    
    mc.addAttr(drvSysGrp, ln='enabled', at='bool', k=True, dv=True)
    rt.connectSDK(drvSysGrp+'.enabled', p2cNode+'.nodeState', {1:0, 0:2})
    
        
    # if attachGeo is defined, use attachGeo to drive polyToCurve
    if attachGeo:
        # make an origLoc for each driverLoc to preserve orig positions
        origLocs = []
        for eachLoc in drvLocs:
            origLoc = mc.group(n=eachLoc.replace('_drvLoc', '_drvLocOrig'), em=True)
            rt.parentSnap(origLoc, eachLoc)
            mc.parent(origLoc, w=True)
            origLocs.append(origLoc)
            
        # switch the input mesh for polyToCurve -> this will move drvLocs
        mc.connectAttr(attachGeo, p2cNode+'.inputPolymesh', f=True)
        
        # parent orig loc back under driver loc, preserving transforms
        for drv, orig in zip(drvLocs, origLocs):
            mc.parent(orig, drv)
            
        return drvSysGrp, origLocs
    
    return drvSysGrp, drvLocs
示例#13
0
def addJntsOnSurfIntersection(surf1, surf2, jntsNum):
    '''
    Places jnts along intersection curve between surf1 and surf2
    naming convention based on surf1
    '''

    # intersect surfaces
    crvGrp, intNode = mc.intersect(surf1,
                                   surf2,
                                   fs=True,
                                   ch=True,
                                   o=True,
                                   cos=False)[:2]
    intNode = mc.rename(intNode, surf1 + '_ints')
    crvGrp = mc.rename(crvGrp, surf1 + '_ints_crv_grp')
    crv = mc.listRelatives(crvGrp, c=True)[0]
    crv = mc.rename(crv, surf1 + '_ints_crv')

    # rebuild curve to jntNum spans
    rbdCrv, rbdNode = mc.rebuildCurve(crv,
                                      ch=True,
                                      o=True,
                                      rpo=False,
                                      spans=jntsNum,
                                      rt=0,
                                      kr=2,
                                      n=crv + '_rbd_crv')
    rbdNode = mc.rename(rbdNode, crv + '_rbd')

    # offset curve to control size of eye hole
    offsetCrv, offsetNode = mc.offsetCurve(rbdCrv,
                                           ch=True,
                                           distance=0,
                                           o=True,
                                           ugn=0,
                                           n=crv + '_offset_crv')
    offsetNode = mc.rename(offsetNode, crv + '_offset')

    locs = []
    locName = '_'.join(surf1.split('_')[:2])
    # attach locators to intersection curve
    for locId in range(jntsNum):
        loc = mc.spaceLocator(n=locName + '_loc_%d' % locId)[0]
        rt.attachToMotionPath(offsetCrv, locId, loc, fm=False)
        mc.setAttr(loc + '.localScale', 0.05, 0.05, 0.05)
        locs.append(loc)

    # normal constraint to surf1
    for loc in locs:
        mc.normalConstraint(surf2, loc, aim=(1, 0, 0))

    jnts = []
    # add joints under locators
    for loc in locs:
        mc.select(cl=True)
        jnt = mc.joint(n=loc.replace('_loc_', '_jnt_'))
        rt.parentSnap(jnt, loc)
        mc.setAttr(jnt + '.jointOrient', 0, 0, 0)
        jnts.append(jnt)

    # groups
    grp = mc.group(crvGrp,
                   offsetCrv,
                   rbdCrv,
                   locs,
                   n=surf1 + '_intersect_loc_grp')

    # create offset attribute
    mc.addAttr(grp, ln='collideOffset', at='double', dv=0, k=True)
    offsetPlug = cn.create_multDoubleLinear(grp + '.collideOffset', -1)
    mc.connectAttr(offsetPlug, offsetNode + '.distance', f=True)

    # connect debug
    rt.connectVisibilityToggle(offsetCrv, grp, 'offsetCrv', False)
    rt.connectVisibilityToggle(rbdCrv, grp, 'rebuildCrv', False)
    rt.connectVisibilityToggle(crvGrp, grp, 'intersectCrv', False)
    rt.connectVisibilityToggle(locs, grp, 'crvLocs', False)
    rt.connectVisibilityToggle(jnts, grp, 'crvJnts', False)
示例#14
0
def addReverseRoll(jnts, bendPivot, leftPivot, rightPivot):
    '''
    add reverse roll to hand or foot setups
    
    jnts - 
    [base,
    [digitBase, digitEnd],
    ...
    ]
    
    digitBase joints will be parentConstrained to the new "stableDigitJoints" that sticks with the IK handles
    (so you should pass in an offset grp above the actual joint)
    
    ***
    ASSUME ONE SPLIT JOINT BETWEEN BASE AND DIGIT 
    TO BE CUSTOMIZED
    ***
    
    returns rollGrp, baseJnt
    
    EXAMPLE USE ON HAND:
    rollGrp (TRS, and attributes Bend & Side) should be driven by Ik/FKHand
    rollLocs rotations are driven by attributes on the Hand
    baseStableJnt is a child of the rollLocs, and therefore rotate with pivots at the rollLocs
    baseStableJnt drives the child of Ik/FkHand
    
    '''
    
    #===========================================================================
    # BUILD DRIVER JOINT CHAIN
    #===========================================================================
    
    baseJnt = jnts[0]
    digitJnts = jnts[1:]
    basePos = mc.xform(baseJnt, q=True, t=True, ws=True)
    
    # base joint
    mc.select(cl=True)
    baseStableJnt = mc.joint(n=baseJnt+'_stable')
    rt.parentSnap(baseStableJnt, baseJnt)
    mc.setAttr(baseStableJnt+'.jointOrient', 0,0,0)
    mc.parent(baseStableJnt, w=True)
    
    ikHs = []
    
    # digit joints
    for base, tip in digitJnts:
        
        #=======================================================================
        # MAKE JOINTS
        #=======================================================================
        
        mc.select(cl=True)
        
        # split joint
        digitPos = mc.xform(base, q=True, t=True, ws=True)
        # get midPoint between base to digitBase
        midPoint = [(b + d)/2 for b, d in zip(basePos, digitPos)]
        splitJnt = mc.joint(p=midPoint, n=base+'_mid')
        
        # digit base jnt
        digitBaseJnt = mc.joint(p=digitPos, n=base+'_stable')
        
        # digit end jnt
        tipPos = mc.xform(tip, q=True, t=True, ws=True)
        digitEndJnt = mc.joint(p=tipPos, n=base+'_stableTip')
        
        # orient joint chain
        mc.joint(splitJnt, oj='xyz', ch=True, sao='yup', e=True)
        mc.setAttr(digitEndJnt+'.jointOrient', 0,0,0)
        
        mc.parent(splitJnt, baseStableJnt)
        
        #=======================================================================
        # MAKE IKHANDLE
        #=======================================================================
        
        ikH = mc.ikHandle(solver='ikSCsolver', n=base+'_ikH', sj=digitBaseJnt, ee=digitEndJnt)[0]
        ikHs.append(ikH)
        
        #=======================================================================
        # PARENT CONSTRAINT original joints to stable joints
        #=======================================================================
        mc.parentConstraint(digitBaseJnt, base, mo=True)
    
    ikHdlGrp = mc.group(ikHs, n=baseJnt+'reverseRoll_ikHdl_grp')
    
    # parent baseStableJnt under locators to make multiple pivots
    
    rollGrp = abRT.groupFreeze(baseStableJnt)
    mc.parent(bendPivot, rollGrp)
    mc.parent(leftPivot, bendPivot)
    mc.parent(rightPivot, leftPivot)
    mc.parent(baseStableJnt, rightPivot)
    mc.parent(ikHdlGrp, rollGrp)
    
    # hide locators for debugging
    rt.connectVisibilityToggle([bendPivot, leftPivot, rightPivot], rollGrp, 'debugPivotLocs', False)
    
    # add attributes for controlling bend and side-to-side
    mc.addAttr(rollGrp, ln='bend', at='double', min=-10, max=10, dv=0, k=True)
    mc.addAttr(rollGrp, ln='side', at='double', min=-10, max=10, dv=0, k=True)
    
    rt.connectSDK(rollGrp+'.bend', bendPivot+'.rz', {-10:90, 10:-90})
    rt.connectSDK(rollGrp+'.side', leftPivot+'.rx', {0:0, 10:-90})
    rt.connectSDK(rollGrp+'.side', rightPivot+'.rx', {0:0, -10:90})
            
    return rollGrp, baseStableJnt
示例#15
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
示例#16
0
def createSplineMPs(MPs, newMPsNum, name, twistOffset):
    '''
    creates spline along mps
    adds new MPs along spline
    
    twistOffset - vector to offset twistCrv
    
    returns [(drvCrv, twistCrv, oldDrvCrv), MPJnts]
    '''
    numOfMPs = len(MPs)
    
    # create twist curve for aiming locs
    twistCrv = mc.curve(p=[(pt,pt,pt) for pt in range(numOfMPs)])
    twistCrv = mc.rename(twistCrv, name+'_twist_crv')
    
    # get point from MPs to drive curve CVs
    for mp in MPs:
        pmm = mc.createNode('pointMatrixMult', n=mp+'_pmm_0')
        mc.connectAttr(mp+'.worldMatrix', pmm+'.inMatrix', f=True)
        mc.setAttr(pmm+'.inPoint', *twistOffset)
        mc.connectAttr(pmm+'.output', twistCrv+'.cp[%d]' % MPs.index(mp))
        
    # create driver curve for locs
    drvCrv = mc.curve(p=[(pt,pt,pt) for pt in range(numOfMPs)])
    drvCrv = mc.rename(drvCrv, name+'_drv_crv')
    
    # get point from MPs to drive curve CVs
    for mp in MPs:
        pmm = mc.createNode('pointMatrixMult', n=mp+'_pmm_0')
        mc.connectAttr(mp+'.worldMatrix', pmm+'.inMatrix', f=True)
        mc.connectAttr(pmm+'.output', drvCrv+'.cp[%d]' % MPs.index(mp))
    
    # make driver curve uniform
    oldDrvCrv = drvCrv
    drvCrv = rt.makeUniformCrv(drvCrv, newMPsNum, name+'_uniform_crv')
    
    # add aimLocs to twistCurve
    aimLocs = []
    
    for locId in range(newMPsNum):
        loc = mc.spaceLocator(n=name+'_aimLoc_%d' % locId)[0]
        rt.attachToMotionPath(twistCrv, float(locId)/(newMPsNum-1), loc, 1)
        mc.setAttr(loc+'.localScale', 0.1,0.1,0.1)
        aimLocs.append(loc)
    
    aimLocsGrp = mc.group(aimLocs, n='CT_%s_aimLocs_grp'%name)
    
    MPJnts = []
    
    for jntId in range(newMPsNum):
        jnt = mc.joint(n=name+'_MPJnt_%d' % jntId)
        rt.alignOnMotionPath(drvCrv, float(jntId)/(newMPsNum-1), jnt, aimLocs[jntId]+'.worldMatrix', 1)
        MPJnts.append(jnt)
        
    MPJntsGrp = mc.group(MPJnts, n='CT_%s_MPJnts_grp'%name)
    
    # connect viz for debug
    rt.connectVisibilityToggle(oldDrvCrv, MPs[0], 'drvCrv', default=False)
    rt.connectVisibilityToggle((aimLocsGrp, twistCrv), MPs[0], 'twistLocs', default=False)
    rt.connectVisibilityToggle((MPJntsGrp, drvCrv), MPs[0], 'drvMPs', default=False)
    
    mc.group(oldDrvCrv, twistCrv, drvCrv, aimLocsGrp, MPJntsGrp, n=name+'_splineMPs_grp')
    
    return (drvCrv, twistCrv, oldDrvCrv), MPJnts
示例#17
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)
    
示例#18
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)
示例#19
0
def addOffsetPt(pt, aims, upObj, name):
    '''
    '''
    # make master grp
    masterGrp = mc.group(n=name+'_offsetPt_grp', em=True)
    mc.addAttr(masterGrp, ln='rollDistance', at='double', k=True, dv=2)
    
    #===========================================================================
    # BASE
    #===========================================================================
    # create base locator (drive base surface)
    baseLoc = mc.spaceLocator(n=name+'_baseLoc')[0]
    
    # point constraint to pt
    mc.pointConstraint(pt, baseLoc)
    
    # aim constraint to aim(s), using upObj as up object
    orientLocs = [] # should have maximum of 2 items
    for eachAim in aims:
        oriLoc = mc.spaceLocator(n=name+'_oriLoc#')[0]
        mc.pointConstraint(pt, oriLoc)
        if aims.index(eachAim) == 1:
            aimVec = (-1,0,0) # for the second aim constraint, use -X to aim opposite direction
        else:
            aimVec = (1,0,0)
        mc.aimConstraint(eachAim, oriLoc, aim=aimVec, u=(0,1,0), wuo=upObj, wut='object')
        orientLocs.append(oriLoc)
        
    mc.orientConstraint(orientLocs, baseLoc)
    
    # create base bnd jnt, parent under base loc
    baseBndJnt = mc.joint(n=name+'_base_bndJnt')
    rt.parentSnap(baseBndJnt, baseLoc)
    
    #===========================================================================
    # OFFSET
    #===========================================================================
    # create offset locator (drive offset surface), parent snap to base loc
    offsetLoc = mc.spaceLocator(n=name+'_offsetLoc')[0]
    rt.parentSnap(offsetLoc, baseLoc)
    
    # create acs locator (for automation), parent snap to offset loc
    offsetAcsLoc = mc.spaceLocator(n=name+'_offset_acsLoc')[0]
    rt.parentSnap(offsetAcsLoc, offsetLoc)
    
    #===========================================================================
    # ROLL
    #===========================================================================
    # create roll loc, parent snap to base loc, translate Z by masterGrp.rollDistance
    rollLoc = mc.spaceLocator(n=name+'_rollLoc')[0]
    rt.parentSnap(rollLoc, baseLoc)
    mc.connectAttr(masterGrp+'.rollDistance', rollLoc+'.tz', f=True)
    
    # create offset roll loc
    offsetRollLoc = mc.spaceLocator(n=name+'_roll_offsetLoc')[0]
    rt.parentSnap(offsetRollLoc, rollLoc)
    
    # create acs roll loc (for automation), parent snap to roll offset loc
    acsRollLoc = mc.spaceLocator(n=name+'_roll_acsLoc')[0]
    rt.parentSnap(acsRollLoc, offsetRollLoc)
    
    #===========================================================================
    # calculate Offset transform in Roll space
    #===========================================================================
    # offset-acs-loc.worldMatrix X roll-loc.inverseWorldMatrix
    mm = mc.createNode('multMatrix', n=name+'_calcRollSpace_mm')
    mc.connectAttr(offsetAcsLoc+'.worldMatrix[0]', mm+'.matrixIn[0]', f=True)
    mc.connectAttr(rollLoc+'.worldInverseMatrix[0]', mm+'.matrixIn[1]', f=True)
    
    dm = mc.createNode('decomposeMatrix', n=name+'_calcRollSpace_dm')
    mc.connectAttr(mm+'.matrixSum', dm+'.inputMatrix', f=True)

    #===========================================================================
    # offset bnd jnt
    #===========================================================================
    # use calculated position in roll-space, but parent under acs-roll-loc, to inherit offsets
    # make a locked loc first (to receive transforms)
    lockedLoc = mc.spaceLocator(n=name+'_readTransforms_loc')[0]
    rt.parentSnap(lockedLoc, acsRollLoc)
    
    mc.connectAttr(dm+'.outputTranslate', lockedLoc+'.t', f=True)
    mc.connectAttr(dm+'.outputRotate', lockedLoc+'.r', f=True)
    mc.connectAttr(dm+'.outputScale', lockedLoc+'.s', f=True)
    
    # user-controllable locator
    ctl = mc.spaceLocator(n=name+'_ctl')[0]
    rt.parentSnap(ctl, lockedLoc)
    
    # bnd jnt for offset surface
    offsetBndJnt = mc.joint(n=name+'_offset_bndJnt')
    
    #===========================================================================
    # HIDING
    #===========================================================================
    mc.addAttr(masterGrp, ln='debugVis', at='bool', k=True)
    mc.setAttr(masterGrp+'.debugVis', l=True)
    rt.connectVisibilityToggle(offsetBndJnt, masterGrp, 'offsetJnt', False)
    rt.connectVisibilityToggle(baseBndJnt, masterGrp, 'baseJnt', False)
    rt.connectVisibilityToggle(ctl, masterGrp, 'ctl', True)
    rt.connectVisibilityToggle(offsetRollLoc, masterGrp, 'rollLoc', True)
    rt.connectVisibilityToggle(orientLocs, masterGrp, 'orientLocs', False)
    rt.connectVisibilityToggle([baseLoc, oriLoc, offsetLoc, offsetAcsLoc, rollLoc, acsRollLoc, lockedLoc], masterGrp, 'locs', False)
    
    mc.parent(baseLoc, orientLocs, masterGrp)
    mc.select(masterGrp, r=True)
    
    return masterGrp