예제 #1
0
def softSelectionSkinWeights(*args):

    model = mc.ls(sl=True, o=True)
    joints = mc.ls(model, type='joint')
    mc.select(joints, deselect=True)
    weights = getSoftSelectionWeights()
    
    if not model or not joints or not weights:
        raise RuntimeError('Select vertices followed by a joint')
    
    if len(joints) > 1:
        raise RuntimeError('Only one joint can be selected at a time')
    
    joint = joints[0]

    skin = utl.getSkinCluster(model[0])
    
    if not skin:
        raise RuntimeError('Mesh must have an existing skinCluster')

    influences = mc.skinCluster(skin, query=True, influence=True)
    if joint not in influences:
        mc.skinCluster(skin, edit=True, addInfluence=joint, lockWeights=False, weight=0)
    
    for influence in influences:
        mc.skinCluster(skin, edit=True, influence=influence, lockWeights=False)

    for vertex, weight in weights.items():
        mc.skinPercent(skin, vertex, transformValue=(joint, weight))
    
    mc.select(joint)
예제 #2
0
def copySkinComponents(source, destinationVerts):

    if not mc.listRelatives(source, shapes=True):
        raise RuntimeError('Source object must be geometry.')

    sourceSkin = utl.getSkinCluster(source)

    if not sourceSkin:
        raise RuntimeError("Source mesh doesn't have a skinCluster to copy from.")

    destMesh = mc.ls(destinationVerts[0], o=True)[0]
    destMesh = mc.listRelatives(destMesh, parent=True)[0]
    destSkin = copySkinInfluences(source, destMesh)

    tempSet = mc.sets(destinationVerts)

    mc.select(source, tempSet)

    mc.copySkinWeights(noMirror=True,
                       surfaceAssociation='closestPoint',
                       influenceAssociation='closestJoint',
                       normalize=True)

    mc.delete(tempSet)
    mc.select(destinationVerts)
예제 #3
0
def copySkinComponents(source, destinationVerts):

    if not mc.listRelatives(source, shapes=True):
        raise RuntimeError('Source object must be geometry.')

    sourceSkin = utl.getSkinCluster(source)

    if not sourceSkin:
        raise RuntimeError(
            "Source mesh doesn't have a skinCluster to copy from.")

    destMesh = mc.ls(destinationVerts[0], o=True)[0]
    destMesh = mc.listRelatives(destMesh, parent=True)[0]
    destSkin = copySkinInfluences(source, destMesh)

    tempSet = mc.sets(destinationVerts)

    mc.select(source, tempSet)

    mc.copySkinWeights(noMirror=True,
                       surfaceAssociation='closestPoint',
                       influenceAssociation='closestJoint',
                       normalize=True)

    mc.delete(tempSet)
    mc.select(destinationVerts)
예제 #4
0
def copySkinInfluences(source, dest):

    sourceSkin = utl.getSkinCluster(source)
    if not sourceSkin:
        return False

    joints = mc.skinCluster(sourceSkin, query=True, influence=True)

    destSkin = utl.getSkinCluster(dest)

    if not destSkin:
        destSkin = mc.skinCluster(joints, dest, toSelectedBones=True)[0]
    else:
        destJoints = mc.skinCluster(destSkin, query=True, influence=True)
        for joint in [x for x in joints if x not in destJoints]:
            mc.skinCluster(destSkin, edit=True, addInfluence=joint, lockWeights=False, weight=0)

    return destSkin
예제 #5
0
def createCenterOfMass(*args):
    '''
    Create a center of mass node, and constrain it to the
    character based on the selected root node.
    '''

    sel = mc.ls(sl=True)

    if not len(sel) == 1:
        raise RuntimeError('Please select the root control of your puppet.')

    print 'Create Center Of Mass Node'
    print '--------------------------'

    meshes = meshesFromReference(sel[0]) or meshesFromHistory(sel[0])

    if not meshes:
        raise RuntimeError('Could not determine geometry from selected control. Make sure geo is visible.')

    mc.select(meshes)
    mc.refresh()

    print 'Discovered Meshes:'
    for mesh in meshes:
        print '\t',mesh

    skinnedMeshes = []
    for mesh in meshes:
        if utl.getSkinCluster(mesh):
            skinnedMeshes.append(mesh)
            continue
        hist = mc.listHistory(mesh, breadthFirst=True)
        skins = mc.ls(hist, type='skinCluster')
        if not skins:
            warnings.warn('Could not find a skinned mesh affecting {}'.format(mesh))
            continue
        outGeo = mc.listConnections(skins[0]+'.outputGeometry[0]', source=False)
        outGeo = mc.ls(outGeo, type=['mesh','transform'])
        if not outGeo:
            warnings.warn('Could not find a skinned mesh affecting {}'.format(mesh))
            continue
        skinnedMeshes.append(outGeo[0])

    if not skinnedMeshes:
        raise RuntimeError('Could not determine skinned geometry from selected control. This tool will only work if geo is skinned.')

    locator = centerOfMassLocator(skinnedMeshes)

    mc.addAttr(locator, longName=COM_ATTR, attributeType='message')
    mc.connectAttr('.'.join((sel[0],'message')), '.'.join((locator,COM_ATTR)))

    mc.select(sel)
    return locator
예제 #6
0
def createCenterOfMass(*args):
    '''
    Create a center of mass node, and constrain it to the 
    character based on the selected root node.
    '''
    
    sel = mc.ls(sl=True)
    
    if not len(sel) == 1:
        raise RuntimeError('Please select the root control of your puppet.')
    
    print 'Create Center Of Mass Node'
    print '--------------------------'
    
    meshes = meshesFromReference(sel[0]) or meshesFromHistory(sel[0])
    
    if not meshes:
        raise RuntimeError('Could not determine geomerty from selected control. Make sure geo is visible.')
    
    mc.select(meshes)
    mc.refresh()
    
    print 'Discovered Meshes:'
    for mesh in meshes:
        print '\t',mesh
    
    skinnedMeshes = []
    for mesh in meshes:
        if utl.getSkinCluster(mesh):
            skinnedMeshes.append(mesh)
            continue
        hist = mc.listHistory(mesh, breadthFirst=True)
        skins = mc.ls(hist, type='skinCluster')
        if not skins:
            warnings.warn('Could not find a skinned mesh affecting {}'.format(mesh))
            continue
        outGeo = mc.listConnections(skins[0]+'.outputGeometry[0]', source=False)
        outGeo = mc.ls(outGeo, type=['mesh','transform'])
        if not outGeo:
            warnings.warn('Could not find a skinned mesh affecting {}'.format(mesh))
            continue
        skinnedMeshes.append(outGeo[0])
    
    if not skinnedMeshes:
        raise RuntimeError('Could not determine skinned geometry from selected control. This tool will only work if geo is skinned.')
    
    locator = centerOfMassLocator(skinnedMeshes)
    
    mc.addAttr(locator, longName=COM_ATTR, attributeType='message')
    mc.connectAttr('.'.join((sel[0],'message')), '.'.join((locator,COM_ATTR)))
    
    mc.select(sel)
    return locator
예제 #7
0
def copySkinCluster(source, destination):

    sourceSkin = utl.getSkinCluster(source)
    if not sourceSkin:
        raise RuntimeError("Source mesh doesn't have a skinCluster to copy from.")

    destSkin = copySkinInfluences(source, destination)

    mc.copySkinWeights(sourceSkin=sourceSkin, destinationSkin=destSkin, noMirror=True,
                       surfaceAssociation='closestPoint',
                       influenceAssociation='closestJoint', normalize=True)

    return destSkin
예제 #8
0
def copySkinInfluences(source, dest):

    sourceSkin = utl.getSkinCluster(source)
    if not sourceSkin:
        return False

    joints = mc.skinCluster(sourceSkin, query=True, influence=True)

    destSkin = utl.getSkinCluster(dest)

    if not destSkin:
        destSkin = mc.skinCluster(joints, dest, toSelectedBones=True)[0]
    else:
        destJoints = mc.skinCluster(destSkin, query=True, influence=True)
        for joint in [x for x in joints if x not in destJoints]:
            mc.skinCluster(destSkin,
                           edit=True,
                           addInfluence=joint,
                           lockWeights=False,
                           weight=0)

    return destSkin
예제 #9
0
def copySkinCluster(source, destination):

    sourceSkin = utl.getSkinCluster(source)
    if not sourceSkin:
        raise RuntimeError(
            "Source mesh doesn't have a skinCluster to copy from.")

    destSkin = copySkinInfluences(source, destination)

    mc.copySkinWeights(sourceSkin=sourceSkin,
                       destinationSkin=destSkin,
                       noMirror=True,
                       surfaceAssociation='closestPoint',
                       influenceAssociation='closestJoint',
                       normalize=True)

    return destSkin
예제 #10
0
def softSelectionSkinWeights(*args):

    model = mc.ls(sl=True, o=True)
    joints = mc.ls(model, type='joint')
    mc.select(joints, deselect=True)
    weights = getSoftSelectionWeights()

    if not model or not joints or not weights:
        raise RuntimeError('Select vertices followed by a joint')

    if len(joints) > 1:
        raise RuntimeError('Only one joint can be selected at a time')

    joint = joints[0]

    skin = utl.getSkinCluster(model[0])

    if not skin:
        raise RuntimeError('Mesh must have an existing skinCluster')

    influences = mc.skinCluster(skin, query=True, influence=True)
    if joint not in influences:
        mc.skinCluster(skin, edit=True, addInfluence=joint, lockWeights=False, weight=0)

    for influence in influences:
        mc.skinCluster(skin, edit=True, influence=influence, lockWeights=False)

    for vertex, weight in weights.items():
        mc.skinPercent(skin, vertex, transformValue=(joint, weight))

    mc.select(joint)


#      ______________________
# - -/__ Revision History __/- - - - - - - - - - - - - - - - - - - - - - - -
#
# Revision 1: 2016-12-31 : Initial publish
#
# Revision 2: 2018-02-17 : Updating license to MIT.
예제 #11
0
def getMaxInfluenceMap(model):
    '''
    return mesh faces with highest weight for each joint.
    '''
    skin = utl.getSkinCluster(model)
    if not skin:
        return {}

    # get the MFnSkinCluster
    selList = om.MSelectionList()
    selList.add(skin)
    clusterNode = om.MObject()
    selList.getDependNode(0, clusterNode)
    skinFn = oma.MFnSkinCluster(clusterNode)

    # get the MDagPath for all influence
    infDags = om.MDagPathArray()
    skinFn.influenceObjects(infDags)

    # create a dictionary whose key is the MPlug indice id and
    # whose value is the influence list id
    infIds = {}
    joints = {}
    for x in xrange(infDags.length()):
        infPath = infDags[x].fullPathName()
        infId = int(skinFn.indexForInfluenceObject(infDags[x]))
        infIds[infId] = x
        joints[infId] = infPath

    # get the MPlug for the weightList and weights attributes
    wlPlug = skinFn.findPlug('weightList')
    wPlug = skinFn.findPlug('weights')
    wlAttr = wlPlug.attribute()
    wAttr = wPlug.attribute()
    wInfIds = om.MIntArray()

    #joint is key, value is list of vertices
    weights = {}
    for vId in xrange(wlPlug.numElements()):
        #loop through verts

        # tell the weights attribute which vertex id it represents
        wPlug.selectAncestorLogicalIndex(vId, wlAttr)
        # get the indice of all non-zero weights for this vert
        wPlug.getExistingArrayAttributeIndices(wInfIds)

        # create a copy of the current wPlug
        infPlug = om.MPlug(wPlug)

        maxWeight = 0
        maxInfId = None
        for infId in wInfIds:
            #loop through influences
            infPlug.selectAncestorLogicalIndex(infId, wAttr)
            #try:
            weight = infPlug.asDouble()
            if weight > maxWeight:
                maxWeight = weight
                maxInfId = infId
                if weight > 0.5:
                    break
            #except KeyError:
            #    pass
        if maxInfId is None:
            continue
        if not maxInfId in joints:
            continue
        joint = joints[maxInfId]
        if not joint in weights:
            weights[joint] = []
        weights[joint].append('{}.vtx[{}]'.format(model,vId))

    return weights

#      ______________________
# - -/__ Revision History __/- - - - - - - - - - - - - - - - - - - - - - - -
#
# Revision 1: 2016-12-05 : First publish.
#
# Revision 2: 2018-02-17 : Updating license to MIT.
예제 #12
0
def centerOfMassLocator(meshes):
    '''
    Constrains a locator at the approximate center of mass of a list of skinned meshes.
    '''

    constraintWeights = {}

    numJoints = 0
    skinnedMeshes = []
    for mesh in meshes:
        skin = utl.getSkinCluster(mesh)
        if not skin:
            continue
        numJoints += len(mc.skinCluster(skin, query=True, influence=True))
        skinnedMeshes.append(mesh)

    if not skinnedMeshes:
        raise RuntimeError('No skinClusters affecting the geometry.')

    mc.progressWindow(title='Center Of Mass',
                      progress=0,
                      maxValue=numJoints,
                      status='Prep...',
                      isInterruptable=True )

    mins = [0,0,0]
    maxs = [0,0,0]

    for mesh in skinnedMeshes:

        bb = mc.exactWorldBoundingBox(mesh)
        for i,x in enumerate(bb[:3]):
            mins[1] = min(x,mins[i])
        for i,x in enumerate(bb[3:]):
            maxs[1] = min(x,maxs[i])

        mc.progressWindow(edit=True, step=1, status=('Getting influence data from {}...'.format(mesh)))

        jointMap = getMaxInfluenceMap(mesh)

        mc.progressWindow(edit=True, status='Calculating joint weights...')

        for joint, verts in jointMap.items():

            # Check if the dialog has been cancelled
            if mc.progressWindow( query=True, isCancelled=True ):
                return

            mc.progressWindow(edit=True, step=1)

            faces = mc.polyListComponentConversion(verts, fromVertex=True, toFace=True)
            if not faces:
                continue
            faces = mc.ls(faces,fl=True)

            area = getFacesArea(faces)

            #approximate volume is based on ratio of lateral surface area to volume of a cylinder
            #approxVolume = (area * area) / (4 * math.pi)
            approxVolume = area
            if not joint in constraintWeights:
                constraintWeights[joint] = 0.0
            constraintWeights[joint]+=approxVolume

    mc.progressWindow(endProgress=True)
    if not constraintWeights:
        raise RuntimeError('No skinned geometry found')

    loc = mc.spaceLocator(name='COM_#')[0]
    locShape = mc.listRelatives(loc, shapes=True)[0]

    #set the scale of the locator shape
    scales = [a-b for a,b in zip(maxs,mins)]
    scale = sum(scales)*2
    mc.setAttr(locShape+'.localScale',scale,scale,scale)

    args = constraintWeights.keys()
    args.append(loc)
    con = mc.pointConstraint(*args)[0]
    weightAttrs = mc.listAttr(con, ud=True)
    for attr,value in zip(weightAttrs, constraintWeights.values()):
        mc.setAttr('{}.{}'.format(con, attr), value)

    return loc
예제 #13
0
def getMaxInfluenceMap(model):
    '''
    return mesh faces with highest weight for each joint.
    '''
    skin = utl.getSkinCluster(model)
    if not skin:
        return {}
    
    # get the MFnSkinCluster
    selList = om.MSelectionList()
    selList.add(skin)
    clusterNode = om.MObject()
    selList.getDependNode(0, clusterNode)
    skinFn = oma.MFnSkinCluster(clusterNode)
    
    # get the MDagPath for all influence
    infDags = om.MDagPathArray()
    skinFn.influenceObjects(infDags)
    
    # create a dictionary whose key is the MPlug indice id and 
    # whose value is the influence list id
    infIds = {}
    joints = {}
    for x in xrange(infDags.length()):
        infPath = infDags[x].fullPathName()
        infId = int(skinFn.indexForInfluenceObject(infDags[x]))
        infIds[infId] = x
        joints[infId] = infPath
        
    # get the MPlug for the weightList and weights attributes
    wlPlug = skinFn.findPlug('weightList')
    wPlug = skinFn.findPlug('weights')
    wlAttr = wlPlug.attribute()
    wAttr = wPlug.attribute()
    wInfIds = om.MIntArray()
    
    #joint is key, value is list of vertices
    weights = {}
    for vId in xrange(wlPlug.numElements()):
        #loop through verts
        
        # tell the weights attribute which vertex id it represents
        wPlug.selectAncestorLogicalIndex(vId, wlAttr)
        # get the indice of all non-zero weights for this vert
        wPlug.getExistingArrayAttributeIndices(wInfIds)
    
        # create a copy of the current wPlug
        infPlug = om.MPlug(wPlug)
        
        maxWeight = 0
        maxInfId = None
        for infId in wInfIds:
            #loop through influences
            infPlug.selectAncestorLogicalIndex(infId, wAttr)
            #try:
            weight = infPlug.asDouble()
            if weight > maxWeight:
                maxWeight = weight
                maxInfId = infId
                if weight > 0.5:
                    break
            #except KeyError:
            #    pass
        if maxInfId is None:
            continue
        if not maxInfId in joints:
            continue
        joint = joints[maxInfId]
        if not joint in weights:
            weights[joint] = []
        weights[joint].append('{}.vtx[{}]'.format(model,vId))
    
    return weights
예제 #14
0
def centerOfMassLocator(meshes):
    '''
    Constrains a locator at the approximate center of mass of a list of skinned meshes.
    '''
    
    constraintWeights = {}
    
    numJoints = 0
    skinnedMeshes = []
    for mesh in meshes:
        skin = utl.getSkinCluster(mesh)
        if not skin:
            continue
        numJoints += len(mc.skinCluster(skin, query=True, influence=True))
        skinnedMeshes.append(mesh)
    
    if not skinnedMeshes:
        raise RuntimeError('No skinClusters affecting the geometry.')
    
    mc.progressWindow(title='Center Of Mass',
                      progress=0,
                      maxValue=numJoints,
                      status='Prep...',
                      isInterruptable=True )
    
    mins = [0,0,0]
    maxs = [0,0,0]
    
    for mesh in skinnedMeshes:
        
        bb = mc.exactWorldBoundingBox(mesh)
        for i,x in enumerate(bb[:3]):
            mins[1] = min(x,mins[i])
        for i,x in enumerate(bb[3:]):
            maxs[1] = min(x,maxs[i])
        
        mc.progressWindow(edit=True, step=1, status=('Getting influence data from {}...'.format(mesh)))
        
        jointMap = getMaxInfluenceMap(mesh)
        
        mc.progressWindow(edit=True, status='Calculating joint weights...')
        
        for joint, verts in jointMap.items():

            # Check if the dialog has been cancelled
            if mc.progressWindow( query=True, isCancelled=True ):
                return            
            
            mc.progressWindow(edit=True, step=1)
            
            faces = mc.polyListComponentConversion(verts, fromVertex=True, toFace=True)
            if not faces:
                continue
            faces = mc.ls(faces,fl=True)
            
            area = getFacesArea(faces)
            
            #approximate volume is based on ratio of lateral surface area to volume of a cylinder
            #approxVolume = (area * area) / (4 * math.pi)
            approxVolume = area
            if not joint in constraintWeights:
                constraintWeights[joint] = 0.0
            constraintWeights[joint]+=approxVolume
    
    mc.progressWindow(endProgress=True)
    if not constraintWeights:
        raise RuntimeError('No skinned geometry found')
    
    loc = mc.spaceLocator(name='COM_#')[0]
    locShape = mc.listRelatives(loc, shapes=True)[0]
    
    #set the scale of the locator shape
    scales = [a-b for a,b in zip(maxs,mins)]
    scale = sum(scales)*2
    mc.setAttr(locShape+'.localScale',scale,scale,scale)
    
    args = constraintWeights.keys()
    args.append(loc)
    con = mc.pointConstraint(*args)[0]
    weightAttrs = mc.listAttr(con, ud=True)
    for attr,value in zip(weightAttrs, constraintWeights.values()):
        mc.setAttr('{}.{}'.format(con, attr), value)
    
    return loc