Пример #1
1
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 )
Пример #2
0
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)
Пример #3
0
    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 __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)