def setSkinWeights( skinCluster, vertJointWeightData ): ''' vertJointWeightData is a list of 2-tuples containing the vertex component name, and a list of 2-tuples containing the joint name and weight. ie it looks like this: [ ('someMesh.vtx[0]', [('joint1', 0.25), 'joint2', 0.75)]), ('someMesh.vtx[1]', [('joint1', 0.2), 'joint2', 0.7, 'joint3', 0.1)]), ... ] ''' #convert the vertex component names into vertex indices idxJointWeight = [] for vert, jointsAndWeights in vertJointWeightData: idx = int( vert[ vert.rindex( '[' )+1:-1 ] ) idxJointWeight.append( (idx, jointsAndWeights) ) #get an MObject for the skin cluster node skinCluster = apiExtensions.asMObject( skinCluster ) skinFn = MFnSkinCluster( skinCluster ) #construct a dict mapping joint names to joint indices jApiIndices = {} _tmp = MDagPathArray() skinFn.influenceObjects( _tmp ) for n in range( _tmp.length() ): jApiIndices[ str( _tmp[n].node() ) ] = skinFn.indexForInfluenceObject( _tmp[n] ) weightListP = skinFn.findPlug( "weightList" ) weightListObj = weightListP.attribute() weightsP = skinFn.findPlug( "weights" ) tmpIntArray = MIntArray() baseFmtStr = str( skinCluster ) +'.weightList[%d]' #pre build this string: fewer string ops == faster-ness! for vertIdx, jointsAndWeights in idxJointWeight: #we need to use the api to query the physical indices used weightsP.selectAncestorLogicalIndex( vertIdx, weightListObj ) weightsP.getExistingArrayAttributeIndices( tmpIntArray ) weightFmtStr = baseFmtStr % vertIdx +'.weights[%d]' #clear out any existing skin data - and awesomely we cannot do this with the api - so we need to use a weird ass mel command for n in range( tmpIntArray.length() ): removeMultiInstance( weightFmtStr % tmpIntArray[n] ) #at this point using the api or mel to set the data is a moot point... we have the strings already so just use mel for joint, weight in jointsAndWeights: if weight: try: infIdx = jApiIndices[ joint ] except KeyError: try: infIdx = jApiIndices[ joint.split( '|' )[0] ] except KeyError: continue setAttr( weightFmtStr % infIdx, weight )
def jointVerts(joint, tolerance=1e-4, onlyVisibleMeshes=True): ''' returns a dict containing data about the verts influences by the given joint - dict keys are mesh names the joint affects. each dict value is a list of tuples containing (weight, idx) for the verts affected by the joint ''' newObjs = [] meshVerts = {} joint = apiExtensions.asMObject(joint) jointMDag = joint.dagPath() try: skins = list(set(listConnections(joint, s=0, type='skinCluster'))) except TypeError: return meshVerts MObject = OpenMaya.MObject MDagPath = OpenMaya.MDagPath MDoubleArray = OpenMaya.MDoubleArray MSelectionList = OpenMaya.MSelectionList MIntArray = OpenMaya.MIntArray MFnSingleIndexedComponent = OpenMaya.MFnSingleIndexedComponent for skin in skins: skin = apiExtensions.asMObject(skin) mfnSkin = MFnSkinCluster(skin) mSel = MSelectionList() mWeights = MDoubleArray() mfnSkin.getPointsAffectedByInfluence(jointMDag, mSel, mWeights) for n in range(mSel.length()): mesh = MDagPath() component = MObject() mSel.getDagPath(n, mesh, component) #if we only want visible meshes - check to see that this mesh is visible if onlyVisibleMeshes: if not isNodeVisible(mesh): continue c = MFnSingleIndexedComponent(component) idxs = MIntArray() c.getElements(idxs) meshVerts[mesh.partialPathName()] = [ (w, idx) for idx, w in zip(idxs, mWeights) if w > tolerance ] return meshVerts
def jointVerts( joint, tolerance=1e-4, onlyVisibleMeshes=True ): ''' returns a dict containing data about the verts influences by the given joint - dict keys are mesh names the joint affects. each dict value is a list of tuples containing (weight, idx) for the verts affected by the joint ''' newObjs = [] meshVerts = {} joint = apiExtensions.asMObject( joint ) jointMDag = joint.dagPath() try: skins = list( set( listConnections( joint, s=0, type='skinCluster' ) ) ) except TypeError: return meshVerts MObject = OpenMaya.MObject MDagPath = OpenMaya.MDagPath MDoubleArray = OpenMaya.MDoubleArray MSelectionList = OpenMaya.MSelectionList MIntArray = OpenMaya.MIntArray MFnSingleIndexedComponent = OpenMaya.MFnSingleIndexedComponent for skin in skins: skin = apiExtensions.asMObject( skin ) mfnSkin = MFnSkinCluster( skin ) mSel = MSelectionList() mWeights = MDoubleArray() mfnSkin.getPointsAffectedByInfluence( jointMDag, mSel, mWeights ) for n in range( mSel.length() ): mesh = MDagPath() component = MObject() mSel.getDagPath( n, mesh, component ) #if we only want visible meshes - check to see that this mesh is visible if onlyVisibleMeshes: if not isNodeVisible( mesh ): continue c = MFnSingleIndexedComponent( component ) idxs = MIntArray() c.getElements( idxs ) meshVerts[ mesh.partialPathName() ] = [ (w, idx) for idx, w in zip( idxs, mWeights ) if w > tolerance ] return meshVerts
def setSkinWeights(skinCluster, vertJointWeightData): ''' vertJointWeightData is a list of 2-tuples containing the vertex component name, and a list of 2-tuples containing the joint name and weight. ie it looks like this: [ ('someMesh.vtx[0]', [('joint1', 0.25), 'joint2', 0.75)]), ('someMesh.vtx[1]', [('joint1', 0.2), 'joint2', 0.7, 'joint3', 0.1)]), ... ] ''' #convert the vertex component names into vertex indices idxJointWeight = [] for vert, jointsAndWeights in vertJointWeightData: idx = int(vert[vert.rindex('[') + 1:-1]) idxJointWeight.append((idx, jointsAndWeights)) #get an MObject for the skin cluster node skinCluster = apiExtensions.asMObject(skinCluster) skinFn = MFnSkinCluster(skinCluster) #construct a dict mapping joint names to joint indices jApiIndices = {} _tmp = MDagPathArray() skinFn.influenceObjects(_tmp) for n in range(_tmp.length()): jApiIndices[str(_tmp[n].node())] = skinFn.indexForInfluenceObject( _tmp[n]) weightListP = skinFn.findPlug("weightList") weightListObj = weightListP.attribute() weightsP = skinFn.findPlug("weights") tmpIntArray = MIntArray() baseFmtStr = str( skinCluster ) + '.weightList[%d]' #pre build this string: fewer string ops == faster-ness! for vertIdx, jointsAndWeights in idxJointWeight: #we need to use the api to query the physical indices used weightsP.selectAncestorLogicalIndex(vertIdx, weightListObj) weightsP.getExistingArrayAttributeIndices(tmpIntArray) weightFmtStr = baseFmtStr % vertIdx + '.weights[%d]' #clear out any existing skin data - and awesomely we cannot do this with the api - so we need to use a weird ass mel command for n in range(tmpIntArray.length()): removeMultiInstance(weightFmtStr % tmpIntArray[n]) #at this point using the api or mel to set the data is a moot point... we have the strings already so just use mel for joint, weight in jointsAndWeights: if weight: try: infIdx = jApiIndices[joint] except KeyError: try: infIdx = jApiIndices[joint.split('|')[0]] except KeyError: continue setAttr(weightFmtStr % infIdx, weight)