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)
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)
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)
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
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
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
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
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
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.
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.
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
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