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 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 __init__(self, meshData, baseInfo=None): self._meshData = meshData fn = MFnMesh(meshData) # 頂点座標リストを生成。各要素は API 2.0 の MVector とする。 pntArr = MFloatPointArray() fn.getPoints(pntArr) nVrts = pntArr.length() if baseInfo and baseInfo[0] != nVrts: # ベースケージと頂点数が合わない場合は無効とする。 self._vertices = None return vertices = _NONE_LIST * nVrts for i in xrange(nVrts): p = pntArr[i] vertices[i] = api2_MVector(p.x, p.y, p.z) #_pprt(vertices) self._vertices = vertices # ベースケージの場合はトライアングル情報を構築する。 # トライアングルリストを生成。各要素は3頂点のインデクスリストとする。 if baseInfo: triangles = baseInfo[1] self._triRestEdges = baseInfo[2] self._triRestAreas = baseInfo[3] else: triCounts = MIntArray() triVrts = MIntArray() fn.getTriangles(triCounts, triVrts) nPlys = triCounts.length() #print(triCounts.length(), triVrts.length()) triangles = [] vi = 0 for i in xrange(nPlys): for j in range(triCounts[i]): triangles.append([triVrts[k] for k in range(vi, vi + 3)]) vi += 3 #_pprt(triangles) self._triangles = triangles # トライアングルのエッジベクトルを計算。 self._triEdges = [(vertices[tri[1]] - vertices[tri[0]], vertices[tri[2]] - vertices[tri[1]]) for tri in triangles] # トライアングルの法線ベクトルを計算。 self._triNrms = [(u ^ v).normalize() for u, v in self._triEdges] # ベースケージの場合はトライアングルの面積を計算。変形ケージでは不要。 if not baseInfo: self._triAreas = [(u ^ v).length() * .5 for u, v in self._triEdges]
def setSkinWeights( meshName, skinClusterName, filePath, sel = False): ## Start the clock! start = time.time() cmds.undoInfo(openChunk=True) vertJointWeightData = getData(filePath) ## Turn off maintain max influences.. cmds.setAttr('%s.maintainMaxInfluences' % skinClusterName, 0) ## Set weights normalize to none cmds.setAttr('%s.normalizeWeights' % skinClusterName, 0) ## Set weight distribution to Distance cause neighbours is buggy cmds.setAttr('%s.weightDistribution' % skinClusterName, 0) #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) ) mesh = cmds.listRelatives(meshName, shapes= True)[0] mSel = om.MSelectionList() mSel.add(mesh) meshMObject = om.MObject() meshDagPath = om.MDagPath() mSel.getDependNode(0, meshMObject) mSel.getDagPath(0, meshDagPath) skinFn = None iterDg = om.MItDependencyGraph(meshMObject, om.MItDependencyGraph.kDownstream, om.MItDependencyGraph.kPlugLevel) while not iterDg.isDone(): currentItem = iterDg.currentItem() if currentItem.hasFn(om.MFn.kSkinClusterFilter): skinFn = oma.MFnSkinCluster(currentItem) break iterDg.next() #construct a dict mapping joint names to joint indices jApiIndices = {} # Influences & Influence count influences= om.MDagPathArray() infCount = skinFn.influenceObjects(influences) #influenceNames = [influences[i].partialPathName() for i in range(infCount)] for i in range(infCount): jApiIndices[ str(influences[i].partialPathName()) ] = skinFn.indexForInfluenceObject( influences[i] ) ########### weightListP = skinFn.findPlug( "weightList" ) weightListObj = weightListP.attribute() weightsP = skinFn.findPlug( "weights" ) tmpIntArray = MIntArray() baseFmtStr = str( skinClusterName ) + '.weightList[%d]' #pre build this string: fewer string ops == faster-ness! if sel: verts = getIndexes() for vertIdx, jointsAndWeights in idxJointWeight: #we need to use the api to query the physical indices used weightsP.selectAncestorLogicalIndex( vertIdx, weightListObj ) weightsP.getExistingArrayAttributeIndices( tmpIntArray ) if sel: if vertIdx in verts: weightFmtStr = baseFmtStr % vertIdx + '.weights[%d]' for jointName, weight in jointsAndWeights: infIdx = jApiIndices[ jointName ] cmds.setAttr(weightFmtStr % infIdx, weight) else: 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() ): command = '%s' % (weightFmtStr % tmpIntArray[n]) mel.eval("removeMultiInstance %s;" % command) #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 jointName, weight in jointsAndWeights: if weight != 0.0: try: infIdx = jApiIndices[ jointName ] cmds.setAttr(weightFmtStr % infIdx, weight) except KeyError: cmds.warning('Key error for %s skipping' % jointName) pass ## Final cleanup ## Prune! cmds.skinPercent(skinClusterName, pruneWeights = .0015) ## Set weights normalize to interactive cmds.setAttr('%s.normalizeWeights' % skinClusterName, 1) ## Set weight distribution to neighbours cmds.setAttr('%s.weightDistribution' % skinClusterName, 1) ## Normalize the weights cmds.skinPercent(skinClusterName, normalize = True) ## Turn on maintain max again cmds.setAttr('%s.maintainMaxInfluences' % skinClusterName, 1) print 'Skin Import Complete..' print 'Time to import skin weights for %s: %s' % (meshName, time.time() - start) cmds.undoInfo(closeChunk=True)